object: add generic byte-buffer data structure
This commit is contained in:
325
object/buffer.c
Normal file
325
object/buffer.c
Normal file
@@ -0,0 +1,325 @@
|
||||
#include "buffer.h"
|
||||
|
||||
#include <blue/core/iterator.h>
|
||||
#include <blue/object/buffer.h>
|
||||
#include <blue/object/type.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user