#include #include #include #include /*** PRIVATE DATA *************************************************************/ struct b_buffer_p { /* 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; }; /*** PRIVATE FUNCTIONS ********************************************************/ static b_status resize_buffer(struct b_buffer_p *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; } static void *buffer_steal(struct b_buffer_p *buf) { void *p = buf->buf_data; buf->buf_data = NULL; buf->buf_len = 0; buf->buf_cap = 0; return p; } static enum b_status buffer_reserve(struct b_buffer_p *buf, size_t capacity) { if (buf->buf_cap >= capacity) { return B_SUCCESS; } return resize_buffer(buf, capacity); } static enum b_status buffer_resize(struct b_buffer_p *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; } static enum b_status buffer_insert( struct b_buffer_p *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; } static enum b_status buffer_remove(struct b_buffer_p *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; } static void *buffer_ptr(const struct b_buffer_p *buffer) { return buffer->buf_data; } static void *buffer_get(const struct b_buffer_p *buffer, size_t at) { if (at >= buffer->buf_len) { return NULL; } return (unsigned char *)buffer->buf_data + (at * buffer->buf_itemsz); } static size_t buffer_size(const struct b_buffer_p *buffer) { return buffer->buf_len; } static size_t buffer_capacity(const struct b_buffer_p *buffer) { return buffer->buf_cap; } static enum b_status buffer_clear(struct b_buffer_p *buffer) { buffer->buf_len = 0; return B_SUCCESS; } static enum b_status buffer_push_back( struct b_buffer_p *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 = buffer_get(buf, buf->buf_len - count); return B_SUCCESS; } static enum b_status buffer_push_front( struct b_buffer_p *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 = buffer_get(buf, 0); return B_SUCCESS; } static enum b_status buffer_pop_back(struct b_buffer_p *buf, size_t count) { if (count > buf->buf_len) { return B_ERR_OUT_OF_BOUNDS; } buf->buf_len -= count; return B_SUCCESS; } static enum b_status buffer_pop_front(struct b_buffer_p *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; } static size_t buffer_get_size(const struct b_buffer_p *buf) { return buf->buf_len; } static size_t buffer_get_item_size(const struct b_buffer_p *buf) { return buf->buf_itemsz; } static size_t buffer_get_capacity(const struct b_buffer_p *buf) { return buf->buf_cap; } /*** PUBLIC FUNCTIONS *********************************************************/ b_buffer *b_buffer_create(size_t item_sz) { b_buffer *buffer = b_object_create(B_TYPE_BUFFER); if (!buffer) { return NULL; } struct b_buffer_p *p = b_object_get_private(buffer, B_TYPE_BUFFER); p->buf_itemsz = item_sz; return buffer; } b_buffer *b_buffer_create_from_bytes(const void *buf, size_t len) { b_buffer *buffer = b_object_create(B_TYPE_BUFFER); if (!buffer) { return NULL; } struct b_buffer_p *p = b_object_get_private(buffer, B_TYPE_BUFFER); p->buf_len = len; p->buf_cap = len; p->buf_itemsz = 1; p->buf_data = calloc(len, 1); if (!p->buf_data) { b_buffer_unref(buffer); return NULL; } memcpy(p->buf_data, buf, len); return buffer; } b_buffer *b_buffer_create_from_array(const void *buf, size_t item_sz, size_t len) { b_buffer *buffer = b_object_create(B_TYPE_BUFFER); if (!buffer) { return NULL; } struct b_buffer_p *p = b_object_get_private(buffer, B_TYPE_BUFFER); p->buf_len = len; p->buf_cap = len; p->buf_itemsz = item_sz; p->buf_data = calloc(len, item_sz); if (!p->buf_data) { b_buffer_unref(buffer); return NULL; } memcpy(p->buf_data, buf, len * item_sz); return buffer; } void *b_buffer_steal(b_buffer *buf) { B_CLASS_DISPATCH_STATIC_0(B_TYPE_BUFFER, buffer_steal, buf); } enum b_status b_buffer_reserve(b_buffer *buf, size_t capacity) { B_CLASS_DISPATCH_STATIC(B_TYPE_BUFFER, buffer_reserve, buf, capacity); } enum b_status b_buffer_resize(b_buffer *buf, size_t length) { B_CLASS_DISPATCH_STATIC(B_TYPE_BUFFER, buffer_resize, buf, length); } enum b_status b_buffer_insert( b_buffer *buffer, const void *p, size_t count, size_t at) { B_CLASS_DISPATCH_STATIC(B_TYPE_BUFFER, buffer_insert, buffer, p, count, at); } enum b_status b_buffer_remove(b_buffer *buffer, size_t at, size_t count) { B_CLASS_DISPATCH_STATIC(B_TYPE_BUFFER, buffer_remove, buffer, at, count); } void *b_buffer_ptr(const b_buffer *buffer) { B_CLASS_DISPATCH_STATIC_0(B_TYPE_BUFFER, buffer_ptr, buffer); } void *b_buffer_get(const b_buffer *buffer, size_t at) { B_CLASS_DISPATCH_STATIC(B_TYPE_BUFFER, buffer_get, buffer, at); } size_t b_buffer_size(const b_buffer *buffer) { B_CLASS_DISPATCH_STATIC_0(B_TYPE_BUFFER, buffer_size, buffer); } size_t b_buffer_capacity(const b_buffer *buffer) { B_CLASS_DISPATCH_STATIC_0(B_TYPE_BUFFER, buffer_capacity, buffer); } enum b_status b_buffer_clear(b_buffer *buffer) { B_CLASS_DISPATCH_STATIC_0(B_TYPE_BUFFER, buffer_clear, buffer); } enum b_status b_buffer_push_back(b_buffer *buf, size_t count, void **p) { B_CLASS_DISPATCH_STATIC(B_TYPE_BUFFER, buffer_push_back, buf, count, p); } enum b_status b_buffer_push_front(b_buffer *buf, size_t count, void **p) { B_CLASS_DISPATCH_STATIC(B_TYPE_BUFFER, buffer_push_front, buf, count, p); } enum b_status b_buffer_pop_back(b_buffer *buf, size_t count) { B_CLASS_DISPATCH_STATIC(B_TYPE_BUFFER, buffer_pop_back, buf, count); } enum b_status b_buffer_pop_front(b_buffer *buf, size_t count) { B_CLASS_DISPATCH_STATIC(B_TYPE_BUFFER, buffer_pop_front, buf, count); } size_t b_buffer_get_size(const b_buffer *buf) { B_CLASS_DISPATCH_STATIC_0(B_TYPE_BUFFER, buffer_get_size, buf); } size_t b_buffer_get_item_size(const b_buffer *buf) { B_CLASS_DISPATCH_STATIC_0(B_TYPE_BUFFER, buffer_get_item_size, buf); } size_t b_buffer_get_capacity(const b_buffer *buf) { B_CLASS_DISPATCH_STATIC_0(B_TYPE_BUFFER, buffer_get_capacity, buf); } /*** PUBLIC ALIAS FUNCTIONS ***************************************************/ enum b_status b_buffer_append(b_buffer *buffer, const void *p, size_t count) { return b_buffer_insert(buffer, p, count, B_NPOS); } enum b_status b_buffer_prepend(b_buffer *buffer, const void *p, size_t count) { return b_buffer_insert(buffer, p, count, 0); } /*** VIRTUAL FUNCTIONS ********************************************************/ void buffer_init(b_object *obj, void *priv) { struct b_buffer_p *buffer = priv; } void buffer_fini(b_object *obj, void *priv) { struct b_buffer_p *buffer = priv; if (buffer->buf_data) { free(buffer->buf_data); buffer->buf_data = NULL; } } /*** CLASS DEFINITION *********************************************************/ B_TYPE_CLASS_DEFINITION_BEGIN(b_buffer) B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT) B_INTERFACE_ENTRY(to_string) = NULL; B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT) B_TYPE_CLASS_DEFINITION_END(b_buffer) B_TYPE_DEFINITION_BEGIN(b_buffer) B_TYPE_ID(0x323e6858, 0x7a43, 0x4484, 0xa6fb, 0xe3d1e47ae637); B_TYPE_CLASS(b_buffer_class); B_TYPE_INSTANCE_INIT(buffer_init); B_TYPE_INSTANCE_INIT(buffer_fini); B_TYPE_DEFINITION_END(b_buffer)