#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; }