From 0ddfb2ee3c50bdb8bca7c44de5438f2febc06c6f Mon Sep 17 00:00:00 2001 From: Max Wash Date: Fri, 11 Apr 2025 13:56:09 +0100 Subject: [PATCH] object: add generic byte-buffer data structure --- object/buffer.c | 325 ++++++++++++++++++++++++++++ object/buffer.h | 17 ++ object/include/blue/object/buffer.h | 37 +++- 3 files changed, 369 insertions(+), 10 deletions(-) create mode 100644 object/buffer.c create mode 100644 object/buffer.h diff --git a/object/buffer.c b/object/buffer.c new file mode 100644 index 0000000..32cb037 --- /dev/null +++ b/object/buffer.c @@ -0,0 +1,325 @@ +#include "buffer.h" + +#include +#include +#include +#include +#include + +static void buffer_release(struct b_object *obj); + +static struct b_object_type buffer_type = { + .t_flags = B_OBJECT_FUNDAMENTAL, + .t_id = B_OBJECT_TYPE_BUFFER, + .t_name = "corelib::buffer", + .t_instance_size = sizeof(struct b_buffer), + .t_release = buffer_release, +}; + +struct b_buffer *b_buffer_create(size_t item_sz) +{ + struct b_buffer *buffer + = (struct b_buffer *)b_object_type_instantiate(&buffer_type); + if (!buffer) { + return NULL; + } + + buffer->buf_itemsz = item_sz; + + return buffer; +} + +struct b_buffer *b_buffer_create_from_bytes(const void *p, size_t len) +{ + struct b_buffer *buffer = b_buffer_create(1); + if (!buffer) { + return NULL; + } + + buffer->buf_len = len; + buffer->buf_cap = len; + buffer->buf_itemsz = 1; + buffer->buf_data = calloc(len, 1); + if (!buffer->buf_data) { + b_buffer_release(buffer); + return NULL; + } + + memcpy(buffer->buf_data, p, len); + + return buffer; +} + +struct b_buffer *b_buffer_create_from_array(const void *p, size_t item_sz, size_t len) +{ + struct b_buffer *buffer = b_buffer_create(1); + if (!buffer) { + return NULL; + } + + buffer->buf_len = len; + buffer->buf_cap = len; + buffer->buf_itemsz = item_sz; + buffer->buf_data = calloc(len, item_sz); + if (!buffer->buf_data) { + b_buffer_release(buffer); + return NULL; + } + + memcpy(buffer->buf_data, p, len * item_sz); + + return buffer; +} + +static b_status resize_buffer(struct b_buffer *buffer, size_t new_capacity) +{ + if (buffer->buf_cap < new_capacity) { + void *new_data = realloc( + buffer->buf_data, new_capacity * buffer->buf_itemsz); + if (!new_data) { + return B_ERR_NO_MEMORY; + } + + buffer->buf_data = new_data; + } else { + void *new_data = realloc( + buffer->buf_data, new_capacity * buffer->buf_itemsz); + if (!new_data) { + return B_ERR_NO_MEMORY; + } + + buffer->buf_data = new_data; + } + + buffer->buf_cap = new_capacity; + if (buffer->buf_len > new_capacity) { + buffer->buf_len = new_capacity; + } + + return B_SUCCESS; +} + +void *b_buffer_steal(struct b_buffer *buf) +{ + void *p = buf->buf_data; + + buf->buf_data = NULL; + buf->buf_len = 0; + buf->buf_cap = 0; + + return p; +} + +enum b_status b_buffer_reserve(struct b_buffer *buf, size_t capacity) +{ + if (buf->buf_cap >= capacity) { + return B_SUCCESS; + } + + return resize_buffer(buf, capacity); +} + +enum b_status b_buffer_resize(struct b_buffer *buf, size_t length) +{ + enum b_status status = resize_buffer(buf, length); + + if (!B_OK(status)) { + return status; + } + + buf->buf_len = length; + return B_SUCCESS; +} + +enum b_status b_buffer_append(struct b_buffer *buffer, const void *p, size_t count) +{ + return b_buffer_insert(buffer, p, count, B_NPOS); +} + +enum b_status b_buffer_prepend(struct b_buffer *buffer, const void *p, size_t count) +{ + return b_buffer_insert(buffer, p, count, 0); +} + +enum b_status b_buffer_insert( + struct b_buffer *buffer, const void *p, size_t count, size_t at) +{ + if (at == B_NPOS) { + at = buffer->buf_len; + } + + if (at > buffer->buf_len) { + return B_ERR_OUT_OF_BOUNDS; + } + + b_status status = B_SUCCESS; + + if (buffer->buf_len + count > buffer->buf_cap) { + status = resize_buffer(buffer, buffer->buf_cap + count); + + if (status != B_SUCCESS) { + return status; + } + } + + unsigned char *src + = (unsigned char *)buffer->buf_data + (at * buffer->buf_itemsz); + unsigned char *dest = src + (count * buffer->buf_itemsz); + size_t move_len = (buffer->buf_len - at) * buffer->buf_itemsz; + + memmove(dest, src, move_len); + memcpy(src, p, count * buffer->buf_itemsz); + + buffer->buf_len += count; + return B_SUCCESS; +} + +enum b_status b_buffer_remove(struct b_buffer *buffer, size_t at, size_t count) +{ + if (at >= buffer->buf_len) { + return B_ERR_OUT_OF_BOUNDS; + } + + if (at + count >= buffer->buf_len) { + count = buffer->buf_len - at; + } + + unsigned char *dest = buffer->buf_data + (at * buffer->buf_itemsz); + unsigned char *src = dest + (count * buffer->buf_itemsz); + size_t move_len = (buffer->buf_len - at - count) * buffer->buf_itemsz; + + memmove(dest, src, move_len); + + buffer->buf_len -= count; + + return B_SUCCESS; +} + +void *b_buffer_ptr(const struct b_buffer *buffer) +{ + return buffer->buf_data; +} + +void *b_buffer_get(const struct b_buffer *buffer, size_t at) +{ + if (at >= buffer->buf_len) { + return NULL; + } + + return (unsigned char *)buffer->buf_data + (at * buffer->buf_itemsz); +} + +size_t b_buffer_size(const struct b_buffer *buffer) +{ + return buffer->buf_len; +} + +size_t b_buffer_capacity(const struct b_buffer *buffer) +{ + return buffer->buf_cap; +} + +void buffer_release(struct b_object *obj) +{ + struct b_buffer *buffer = B_BUFFER(obj); + + if (buffer->buf_data) { + free(buffer->buf_data); + buffer->buf_data = NULL; + } +} + +enum b_status b_buffer_clear(struct b_buffer *buffer) +{ + buffer->buf_len = 0; + return B_SUCCESS; +} + +enum b_status b_buffer_push_back(struct b_buffer *buf, size_t count, void **p) +{ + enum b_status status = B_SUCCESS; + + if (buf->buf_len + count > buf->buf_cap) { + status = resize_buffer(buf, buf->buf_len + count); + } + + if (!B_OK(status)) { + return status; + } + + buf->buf_len += count; + *p = b_buffer_get(buf, buf->buf_len - count); + + return B_SUCCESS; +} + +enum b_status b_buffer_push_front(struct b_buffer *buf, size_t count, void **p) +{ + enum b_status status = B_SUCCESS; + + if (buf->buf_len + count > buf->buf_cap) { + status = resize_buffer(buf, buf->buf_len + count); + } + + if (!B_OK(status)) { + return status; + } + + void *src = buf->buf_data; + void *dest = b_buffer_get(buf->buf_data, count); + size_t len = count * buf->buf_itemsz; + + memmove(dest, src, len); + buf->buf_len += count; + + *p = b_buffer_get(buf, 0); + + return B_SUCCESS; +} + +enum b_status b_buffer_pop_back(struct b_buffer *buf, size_t count) +{ + if (count > buf->buf_len) { + return B_ERR_OUT_OF_BOUNDS; + } + + buf->buf_len -= count; + + return B_SUCCESS; +} + +enum b_status b_buffer_pop_front(struct b_buffer *buf, size_t count) +{ + if (count > buf->buf_len) { + return B_ERR_OUT_OF_BOUNDS; + } + + void *src = b_buffer_get(buf->buf_data, count); + void *dest = buf->buf_data; + size_t len = (buf->buf_len - count) * buf->buf_itemsz; + + memmove(dest, src, len); + buf->buf_len -= count; + + return B_SUCCESS; +} + +size_t b_buffer_get_size(const struct b_buffer *buf) +{ + return buf->buf_len; +} + +size_t b_buffer_get_item_size(const struct b_buffer *buf) +{ + return buf->buf_itemsz; +} + +size_t b_buffer_get_capacity(const struct b_buffer *buf) +{ + return buf->buf_cap; +} + +b_object_type_id b_buffer_type_id(void) +{ + return (b_object_type_id)&buffer_type; +} diff --git a/object/buffer.h b/object/buffer.h new file mode 100644 index 0000000..8ca6ae2 --- /dev/null +++ b/object/buffer.h @@ -0,0 +1,17 @@ +#ifndef _BLUELIB_BUFFER_H_ +#define _BLUELIB_BUFFER_H_ + +#include "../object.h" + +struct b_buffer { + struct b_object buf_base; + /* number of items in buffer */ + unsigned int buf_len; + /* maximum number of items that can currently be stored in array */ + unsigned int buf_cap; + /* the size of each individual item in the buffer */ + unsigned int buf_itemsz; + void *buf_data; +}; + +#endif diff --git a/object/include/blue/object/buffer.h b/object/include/blue/object/buffer.h index c135e5b..3548700 100644 --- a/object/include/blue/object/buffer.h +++ b/object/include/blue/object/buffer.h @@ -1,8 +1,8 @@ #ifndef BLUELIB_BUFFER_H_ #define BLUELIB_BUFFER_H_ -#include #include +#include #include #define B_BUFFER(p) ((b_buffer *)(p)) @@ -11,22 +11,39 @@ typedef struct b_buffer b_buffer; BLUE_API b_buffer *b_buffer_create(size_t item_sz); BLUE_API b_buffer *b_buffer_create_from_bytes(const void *p, size_t len); -BLUE_API b_buffer *b_buffer_create_from_array(const void *p, size_t item_sz, size_t len); +BLUE_API b_buffer *b_buffer_create_from_array( + const void *p, size_t item_sz, size_t len); -static inline b_buffer *b_buffer_retain(b_buffer *buf) { return B_BUFFER(b_retain(B_OBJECT(buf))); } -static inline void b_buffer_release(b_buffer *buf) { b_release(B_OBJECT(buf)); } +static inline b_buffer *b_buffer_retain(b_buffer *buf) +{ + return B_BUFFER(b_retain(B_OBJECT(buf))); +} +static inline void b_buffer_release(b_buffer *buf) +{ + b_release(B_OBJECT(buf)); +} BLUE_API void *b_buffer_steal(b_buffer *buf); BLUE_API b_status b_buffer_reserve(b_buffer *buf, size_t capacity); +BLUE_API b_status b_buffer_resize(b_buffer *buf, size_t length); BLUE_API b_status b_buffer_append(b_buffer *dest, const void *p, size_t count); BLUE_API b_status b_buffer_prepend(b_buffer *dest, const void *p, size_t count); -BLUE_API b_status b_buffer_insert(b_buffer *dest, const void *p, size_t count, size_t at); -BLUE_API b_status b_buffer_clear(b_buffer *str); +BLUE_API b_status b_buffer_insert( + b_buffer *dest, const void *p, size_t count, size_t at); +BLUE_API b_status b_buffer_remove(b_buffer *dest, size_t at, size_t count); +BLUE_API b_status b_buffer_clear(b_buffer *buf); -BLUE_API size_t b_buffer_get_size(const b_buffer *str); -BLUE_API size_t b_buffer_get_item_size(const b_buffer *str); -BLUE_API size_t b_buffer_get_capacity(const b_buffer *str); +BLUE_API b_status b_buffer_push_back(b_buffer *buf, size_t count, void **p); +BLUE_API b_status b_buffer_push_front(b_buffer *buf, size_t count, void **p); -BLUE_API void *b_buffer_ptr(const b_buffer *str); +BLUE_API b_status b_buffer_pop_back(b_buffer *buf, size_t count); +BLUE_API b_status b_buffer_pop_front(b_buffer *buf, size_t count); + +BLUE_API size_t b_buffer_get_size(const b_buffer *buf); +BLUE_API size_t b_buffer_get_item_size(const b_buffer *buf); +BLUE_API size_t b_buffer_get_capacity(const b_buffer *buf); + +BLUE_API void *b_buffer_ptr(const b_buffer *buf); +BLUE_API void *b_buffer_get(const b_buffer *buf, size_t at); #endif