442 lines
9.9 KiB
C
442 lines
9.9 KiB
C
#include <fx/core/iterator.h>
|
|
#include <fx/ds/buffer.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
/*** PRIVATE DATA *************************************************************/
|
|
|
|
struct fx_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 fx_status resize_buffer(struct fx_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 FX_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 FX_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 FX_SUCCESS;
|
|
}
|
|
|
|
static void *buffer_steal(struct fx_buffer_p *buf)
|
|
{
|
|
void *p = buf->buf_data;
|
|
|
|
buf->buf_data = NULL;
|
|
buf->buf_len = 0;
|
|
buf->buf_cap = 0;
|
|
|
|
return p;
|
|
}
|
|
|
|
static enum fx_status buffer_reserve(struct fx_buffer_p *buf, size_t capacity)
|
|
{
|
|
if (buf->buf_cap >= capacity) {
|
|
return FX_SUCCESS;
|
|
}
|
|
|
|
return resize_buffer(buf, capacity);
|
|
}
|
|
|
|
static enum fx_status buffer_resize(struct fx_buffer_p *buf, size_t length)
|
|
{
|
|
enum fx_status status = resize_buffer(buf, length);
|
|
|
|
if (!FX_OK(status)) {
|
|
return status;
|
|
}
|
|
|
|
buf->buf_len = length;
|
|
return FX_SUCCESS;
|
|
}
|
|
|
|
static enum fx_status buffer_insert(
|
|
struct fx_buffer_p *buffer, const void *p, size_t count, size_t at)
|
|
{
|
|
if (at == FX_NPOS) {
|
|
at = buffer->buf_len;
|
|
}
|
|
|
|
if (at > buffer->buf_len) {
|
|
return FX_ERR_OUT_OF_BOUNDS;
|
|
}
|
|
|
|
fx_status status = FX_SUCCESS;
|
|
|
|
if (buffer->buf_len + count > buffer->buf_cap) {
|
|
status = resize_buffer(buffer, buffer->buf_cap + count);
|
|
|
|
if (status != FX_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 FX_SUCCESS;
|
|
}
|
|
|
|
static enum fx_status buffer_remove(struct fx_buffer_p *buffer, size_t at, size_t count)
|
|
{
|
|
if (at >= buffer->buf_len) {
|
|
return FX_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 FX_SUCCESS;
|
|
}
|
|
|
|
static void *buffer_ptr(const struct fx_buffer_p *buffer)
|
|
{
|
|
return buffer->buf_data;
|
|
}
|
|
|
|
static void *buffer_get(const struct fx_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 fx_buffer_p *buffer)
|
|
{
|
|
return buffer->buf_len;
|
|
}
|
|
|
|
static size_t buffer_capacity(const struct fx_buffer_p *buffer)
|
|
{
|
|
return buffer->buf_cap;
|
|
}
|
|
|
|
static enum fx_status buffer_clear(struct fx_buffer_p *buffer)
|
|
{
|
|
buffer->buf_len = 0;
|
|
return FX_SUCCESS;
|
|
}
|
|
|
|
static enum fx_status buffer_push_back(
|
|
struct fx_buffer_p *buf, size_t count, void **p)
|
|
{
|
|
enum fx_status status = FX_SUCCESS;
|
|
|
|
if (buf->buf_len + count > buf->buf_cap) {
|
|
status = resize_buffer(buf, buf->buf_len + count);
|
|
}
|
|
|
|
if (!FX_OK(status)) {
|
|
return status;
|
|
}
|
|
|
|
buf->buf_len += count;
|
|
*p = buffer_get(buf, buf->buf_len - count);
|
|
|
|
return FX_SUCCESS;
|
|
}
|
|
|
|
static enum fx_status buffer_push_front(
|
|
struct fx_buffer_p *buf, size_t count, void **p)
|
|
{
|
|
enum fx_status status = FX_SUCCESS;
|
|
|
|
if (buf->buf_len + count > buf->buf_cap) {
|
|
status = resize_buffer(buf, buf->buf_len + count);
|
|
}
|
|
|
|
if (!FX_OK(status)) {
|
|
return status;
|
|
}
|
|
|
|
void *src = buf->buf_data;
|
|
void *dest = fx_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 FX_SUCCESS;
|
|
}
|
|
|
|
static enum fx_status buffer_pop_back(struct fx_buffer_p *buf, size_t count)
|
|
{
|
|
if (count > buf->buf_len) {
|
|
return FX_ERR_OUT_OF_BOUNDS;
|
|
}
|
|
|
|
buf->buf_len -= count;
|
|
|
|
return FX_SUCCESS;
|
|
}
|
|
|
|
static enum fx_status buffer_pop_front(struct fx_buffer_p *buf, size_t count)
|
|
{
|
|
if (count > buf->buf_len) {
|
|
return FX_ERR_OUT_OF_BOUNDS;
|
|
}
|
|
|
|
void *src = fx_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 FX_SUCCESS;
|
|
}
|
|
|
|
static size_t buffer_get_size(const struct fx_buffer_p *buf)
|
|
{
|
|
return buf->buf_len;
|
|
}
|
|
|
|
static size_t buffer_get_item_size(const struct fx_buffer_p *buf)
|
|
{
|
|
return buf->buf_itemsz;
|
|
}
|
|
|
|
static size_t buffer_get_capacity(const struct fx_buffer_p *buf)
|
|
{
|
|
return buf->buf_cap;
|
|
}
|
|
|
|
/*** PUBLIC FUNCTIONS *********************************************************/
|
|
|
|
fx_buffer *fx_buffer_create(size_t item_sz)
|
|
{
|
|
fx_buffer *buffer = fx_object_create(FX_TYPE_BUFFER);
|
|
if (!buffer) {
|
|
return NULL;
|
|
}
|
|
|
|
struct fx_buffer_p *p = fx_object_get_private(buffer, FX_TYPE_BUFFER);
|
|
|
|
p->buf_itemsz = item_sz;
|
|
|
|
return buffer;
|
|
}
|
|
|
|
fx_buffer *fx_buffer_create_from_bytes(const void *buf, size_t len)
|
|
{
|
|
fx_buffer *buffer = fx_object_create(FX_TYPE_BUFFER);
|
|
if (!buffer) {
|
|
return NULL;
|
|
}
|
|
|
|
struct fx_buffer_p *p = fx_object_get_private(buffer, FX_TYPE_BUFFER);
|
|
|
|
p->buf_len = len;
|
|
p->buf_cap = len;
|
|
p->buf_itemsz = 1;
|
|
p->buf_data = calloc(len, 1);
|
|
if (!p->buf_data) {
|
|
fx_buffer_unref(buffer);
|
|
return NULL;
|
|
}
|
|
|
|
memcpy(p->buf_data, buf, len);
|
|
|
|
return buffer;
|
|
}
|
|
|
|
fx_buffer *fx_buffer_create_from_array(const void *buf, size_t item_sz, size_t len)
|
|
{
|
|
fx_buffer *buffer = fx_object_create(FX_TYPE_BUFFER);
|
|
if (!buffer) {
|
|
return NULL;
|
|
}
|
|
|
|
struct fx_buffer_p *p = fx_object_get_private(buffer, FX_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) {
|
|
fx_buffer_unref(buffer);
|
|
return NULL;
|
|
}
|
|
|
|
memcpy(p->buf_data, buf, len * item_sz);
|
|
|
|
return buffer;
|
|
}
|
|
|
|
void *fx_buffer_steal(fx_buffer *buf)
|
|
{
|
|
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BUFFER, buffer_steal, buf);
|
|
}
|
|
|
|
enum fx_status fx_buffer_reserve(fx_buffer *buf, size_t capacity)
|
|
{
|
|
FX_CLASS_DISPATCH_STATIC(FX_TYPE_BUFFER, buffer_reserve, buf, capacity);
|
|
}
|
|
|
|
enum fx_status fx_buffer_resize(fx_buffer *buf, size_t length)
|
|
{
|
|
FX_CLASS_DISPATCH_STATIC(FX_TYPE_BUFFER, buffer_resize, buf, length);
|
|
}
|
|
|
|
enum fx_status fx_buffer_insert(
|
|
fx_buffer *buffer, const void *p, size_t count, size_t at)
|
|
{
|
|
FX_CLASS_DISPATCH_STATIC(FX_TYPE_BUFFER, buffer_insert, buffer, p, count, at);
|
|
}
|
|
|
|
enum fx_status fx_buffer_remove(fx_buffer *buffer, size_t at, size_t count)
|
|
{
|
|
FX_CLASS_DISPATCH_STATIC(FX_TYPE_BUFFER, buffer_remove, buffer, at, count);
|
|
}
|
|
|
|
void *fx_buffer_ptr(const fx_buffer *buffer)
|
|
{
|
|
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BUFFER, buffer_ptr, buffer);
|
|
}
|
|
|
|
void *fx_buffer_get(const fx_buffer *buffer, size_t at)
|
|
{
|
|
FX_CLASS_DISPATCH_STATIC(FX_TYPE_BUFFER, buffer_get, buffer, at);
|
|
}
|
|
|
|
size_t fx_buffer_size(const fx_buffer *buffer)
|
|
{
|
|
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BUFFER, buffer_size, buffer);
|
|
}
|
|
|
|
size_t fx_buffer_capacity(const fx_buffer *buffer)
|
|
{
|
|
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BUFFER, buffer_capacity, buffer);
|
|
}
|
|
|
|
enum fx_status fx_buffer_clear(fx_buffer *buffer)
|
|
{
|
|
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BUFFER, buffer_clear, buffer);
|
|
}
|
|
|
|
enum fx_status fx_buffer_push_back(fx_buffer *buf, size_t count, void **p)
|
|
{
|
|
FX_CLASS_DISPATCH_STATIC(FX_TYPE_BUFFER, buffer_push_back, buf, count, p);
|
|
}
|
|
|
|
enum fx_status fx_buffer_push_front(fx_buffer *buf, size_t count, void **p)
|
|
{
|
|
FX_CLASS_DISPATCH_STATIC(FX_TYPE_BUFFER, buffer_push_front, buf, count, p);
|
|
}
|
|
|
|
enum fx_status fx_buffer_pop_back(fx_buffer *buf, size_t count)
|
|
{
|
|
FX_CLASS_DISPATCH_STATIC(FX_TYPE_BUFFER, buffer_pop_back, buf, count);
|
|
}
|
|
|
|
enum fx_status fx_buffer_pop_front(fx_buffer *buf, size_t count)
|
|
{
|
|
FX_CLASS_DISPATCH_STATIC(FX_TYPE_BUFFER, buffer_pop_front, buf, count);
|
|
}
|
|
|
|
size_t fx_buffer_get_size(const fx_buffer *buf)
|
|
{
|
|
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BUFFER, buffer_get_size, buf);
|
|
}
|
|
|
|
size_t fx_buffer_get_item_size(const fx_buffer *buf)
|
|
{
|
|
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BUFFER, buffer_get_item_size, buf);
|
|
}
|
|
|
|
size_t fx_buffer_get_capacity(const fx_buffer *buf)
|
|
{
|
|
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BUFFER, buffer_get_capacity, buf);
|
|
}
|
|
|
|
/*** PUBLIC ALIAS FUNCTIONS ***************************************************/
|
|
|
|
enum fx_status fx_buffer_append(fx_buffer *buffer, const void *p, size_t count)
|
|
{
|
|
return fx_buffer_insert(buffer, p, count, FX_NPOS);
|
|
}
|
|
|
|
enum fx_status fx_buffer_prepend(fx_buffer *buffer, const void *p, size_t count)
|
|
{
|
|
return fx_buffer_insert(buffer, p, count, 0);
|
|
}
|
|
|
|
/*** VIRTUAL FUNCTIONS ********************************************************/
|
|
|
|
void buffer_init(fx_object *obj, void *priv)
|
|
{
|
|
struct fx_buffer_p *buffer = priv;
|
|
}
|
|
|
|
void buffer_fini(fx_object *obj, void *priv)
|
|
{
|
|
struct fx_buffer_p *buffer = priv;
|
|
|
|
if (buffer->buf_data) {
|
|
free(buffer->buf_data);
|
|
buffer->buf_data = NULL;
|
|
}
|
|
}
|
|
|
|
/*** CLASS DEFINITION *********************************************************/
|
|
|
|
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_buffer)
|
|
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
|
FX_INTERFACE_ENTRY(to_string) = NULL;
|
|
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
|
FX_TYPE_CLASS_DEFINITION_END(fx_buffer)
|
|
|
|
FX_TYPE_DEFINITION_BEGIN(fx_buffer)
|
|
FX_TYPE_ID(0x323e6858, 0x7a43, 0x4484, 0xa6fb, 0xe3d1e47ae637);
|
|
FX_TYPE_CLASS(fx_buffer_class);
|
|
FX_TYPE_INSTANCE_PRIVATE(struct fx_buffer_p);
|
|
FX_TYPE_INSTANCE_INIT(buffer_init);
|
|
FX_TYPE_INSTANCE_FINI(buffer_fini);
|
|
FX_TYPE_DEFINITION_END(fx_buffer)
|