commit
143a64f7de
@ -0,0 +1,2 @@ |
|||||||
|
build/ |
||||||
|
.cache/ |
@ -0,0 +1,3 @@ |
|||||||
|
# barray |
||||||
|
|
||||||
|
This is a tiny library containing a dynamic array implementation |
@ -0,0 +1,35 @@ |
|||||||
|
#ifndef _BARRAY_H |
||||||
|
#define _BARRAY_H |
||||||
|
|
||||||
|
#include <stddef.h> |
||||||
|
#include <stdint.h> |
||||||
|
|
||||||
|
typedef struct { |
||||||
|
void* ptr; |
||||||
|
size_t len; |
||||||
|
size_t cap; |
||||||
|
size_t elem_size; |
||||||
|
} BArray; |
||||||
|
|
||||||
|
typedef enum { |
||||||
|
BARRAY_NO_ERR, |
||||||
|
BARRAY_ERR_ALLOC_ERR, |
||||||
|
BARRAY_ERR_OUT_OF_BOUNDS, |
||||||
|
BARRAY_ERR_SIZE_OVERFLOW, |
||||||
|
BARRAY_ERR_NULL, |
||||||
|
BARRAY_ERR_ELEM_SIZE_ZERO |
||||||
|
} BArray_ErrCode; |
||||||
|
|
||||||
|
BArray barray_create(size_t elem_size, size_t initial_cap, BArray_ErrCode* errc); |
||||||
|
void barray_grow(BArray* array, BArray_ErrCode* errc); |
||||||
|
void barray_grow_to(BArray* array, size_t new_cap, BArray_ErrCode* errc); |
||||||
|
void barray_shrink_to_fit(BArray* array, BArray_ErrCode* errc); |
||||||
|
void barray_force_shrink(BArray* array, size_t new_cap, BArray_ErrCode* errc); |
||||||
|
void* barray_get(BArray* array, size_t ix, BArray_ErrCode* errc); |
||||||
|
void barray_set(BArray* array, size_t ix, void* value, BArray_ErrCode* errc); |
||||||
|
void barray_put(BArray* array, size_t ix, void* value, BArray_ErrCode* errc); |
||||||
|
void barray_append(BArray* array, void* value, BArray_ErrCode* errc); |
||||||
|
void barray_remove(BArray* array, size_t ix, BArray_ErrCode* errc); |
||||||
|
void barray_clear(BArray* array, BArray_ErrCode* errc); |
||||||
|
void barray_destroy(BArray* array, BArray_ErrCode* errc); |
||||||
|
#endif /* _BARRAY_H */ |
@ -0,0 +1 @@ |
|||||||
|
include = include_directories('.') |
@ -0,0 +1,10 @@ |
|||||||
|
project('barray', 'c', |
||||||
|
version: '0.0.1', |
||||||
|
meson_version: '>=0.50.0', |
||||||
|
default_options: [ 'warning_level=3', |
||||||
|
'c_std=c2x', |
||||||
|
] |
||||||
|
) |
||||||
|
|
||||||
|
subdir('include') |
||||||
|
subdir('src') |
@ -0,0 +1,285 @@ |
|||||||
|
#include "barray.h" |
||||||
|
|
||||||
|
#include <stdlib.h> |
||||||
|
#include <string.h> |
||||||
|
#include <assert.h> |
||||||
|
|
||||||
|
static BArray BARRAY_INVALID = { NULL, 0, 0, 0 }; |
||||||
|
|
||||||
|
BArray barray_create(size_t elem_size, size_t initial_cap, BArray_ErrCode* errc) { |
||||||
|
assert(errc != NULL); |
||||||
|
if (elem_size == 0) { |
||||||
|
*errc = BARRAY_ERR_ELEM_SIZE_ZERO; |
||||||
|
return BARRAY_INVALID; |
||||||
|
} |
||||||
|
if (initial_cap == 0) { |
||||||
|
*errc = BARRAY_NO_ERR; |
||||||
|
return (BArray) { NULL, 0, 0, elem_size }; |
||||||
|
} |
||||||
|
void* ptr = malloc(elem_size * initial_cap); |
||||||
|
if (ptr == NULL) { |
||||||
|
*errc = BARRAY_ERR_ALLOC_ERR; |
||||||
|
return BARRAY_INVALID; |
||||||
|
} |
||||||
|
*errc = BARRAY_NO_ERR; |
||||||
|
return (BArray) { ptr, 0, initial_cap, elem_size }; |
||||||
|
} |
||||||
|
|
||||||
|
void barray_grow(BArray* array, BArray_ErrCode* errc) { |
||||||
|
assert(errc != NULL); |
||||||
|
if (array == NULL) { |
||||||
|
*errc = BARRAY_ERR_NULL; |
||||||
|
return; |
||||||
|
} |
||||||
|
if (array->elem_size == 0) { |
||||||
|
*errc = BARRAY_ERR_ELEM_SIZE_ZERO; |
||||||
|
return; |
||||||
|
} |
||||||
|
size_t cap = array->cap; |
||||||
|
size_t new_cap; |
||||||
|
if (cap <= 8) { |
||||||
|
new_cap = 16; |
||||||
|
} else if (cap <= 16) { |
||||||
|
new_cap = 32; |
||||||
|
} else if (cap <= 32) { |
||||||
|
new_cap = 64; |
||||||
|
} else if (cap <= 64) { |
||||||
|
new_cap = 128; |
||||||
|
} else if (cap <= 128) { |
||||||
|
new_cap = 256; |
||||||
|
} else if (cap <= 256) { |
||||||
|
new_cap = 512; |
||||||
|
} else if (cap <= 512) { |
||||||
|
new_cap = 1024; |
||||||
|
} else { |
||||||
|
new_cap = (cap / 512) + (cap % 512 == 0 ? 1 : 2); |
||||||
|
if (new_cap < cap) { |
||||||
|
*errc = BARRAY_ERR_SIZE_OVERFLOW; |
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void* new_ptr = realloc(array->ptr, new_cap * array->elem_size); |
||||||
|
if (new_ptr == NULL) { |
||||||
|
*errc = BARRAY_ERR_ALLOC_ERR; |
||||||
|
return; |
||||||
|
} |
||||||
|
*errc = BARRAY_NO_ERR; |
||||||
|
array->ptr = new_ptr; |
||||||
|
array->cap = new_cap; |
||||||
|
} |
||||||
|
|
||||||
|
void barray_grow_to(BArray* array, size_t new_cap, BArray_ErrCode* errc) { |
||||||
|
assert(errc != NULL); |
||||||
|
if (array == NULL) { |
||||||
|
*errc = BARRAY_ERR_NULL; |
||||||
|
return; |
||||||
|
} |
||||||
|
if (array->elem_size == 0) { |
||||||
|
*errc = BARRAY_ERR_ELEM_SIZE_ZERO; |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if (new_cap < array->cap) { |
||||||
|
*errc = BARRAY_NO_ERR; |
||||||
|
return; |
||||||
|
} |
||||||
|
void* new_ptr = realloc(array->ptr, new_cap * array->elem_size); |
||||||
|
if (new_ptr == NULL) { |
||||||
|
*errc = BARRAY_ERR_ALLOC_ERR; |
||||||
|
return; |
||||||
|
} |
||||||
|
*errc = BARRAY_NO_ERR; |
||||||
|
array->ptr = new_ptr; |
||||||
|
array->cap = new_cap; |
||||||
|
} |
||||||
|
|
||||||
|
void barray_shrink_to_fit(BArray* array, BArray_ErrCode* errc) { |
||||||
|
assert(errc != NULL); |
||||||
|
if (array == NULL) { |
||||||
|
*errc = BARRAY_ERR_NULL; |
||||||
|
return; |
||||||
|
} |
||||||
|
if (array->elem_size == 0) { |
||||||
|
*errc = BARRAY_ERR_ELEM_SIZE_ZERO; |
||||||
|
return; |
||||||
|
} |
||||||
|
assert(array->cap >= array->len); |
||||||
|
if (array->cap == array->len) { |
||||||
|
*errc = BARRAY_NO_ERR; |
||||||
|
return; |
||||||
|
} |
||||||
|
size_t new_cap = array->len; |
||||||
|
void* new_ptr = realloc(array->ptr, new_cap * array->elem_size); |
||||||
|
if (new_ptr == NULL) { |
||||||
|
*errc = BARRAY_ERR_ALLOC_ERR; |
||||||
|
return; |
||||||
|
} |
||||||
|
*errc = BARRAY_NO_ERR; |
||||||
|
array->ptr = new_ptr; |
||||||
|
array->cap = new_cap; |
||||||
|
} |
||||||
|
|
||||||
|
void barray_force_shrink(BArray* array, size_t new_cap, BArray_ErrCode* errc) { |
||||||
|
assert(errc != NULL); |
||||||
|
if (array == NULL) { |
||||||
|
*errc = BARRAY_ERR_NULL; |
||||||
|
return; |
||||||
|
} |
||||||
|
if (array->elem_size == 0) { |
||||||
|
*errc = BARRAY_ERR_ELEM_SIZE_ZERO; |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if (new_cap >= array->cap) { |
||||||
|
*errc = BARRAY_NO_ERR; |
||||||
|
return; |
||||||
|
} |
||||||
|
void* new_ptr = realloc(array->ptr, new_cap * array->elem_size); |
||||||
|
if (new_ptr == NULL) { |
||||||
|
*errc = BARRAY_ERR_ALLOC_ERR; |
||||||
|
return; |
||||||
|
} |
||||||
|
*errc = BARRAY_NO_ERR; |
||||||
|
array->ptr = new_ptr; |
||||||
|
array->cap = new_cap; |
||||||
|
array->len = new_cap; |
||||||
|
} |
||||||
|
|
||||||
|
void* barray_get(BArray* array, size_t ix, BArray_ErrCode* errc) { |
||||||
|
assert(errc != NULL); |
||||||
|
if (array == NULL) { |
||||||
|
*errc = BARRAY_ERR_NULL; |
||||||
|
return NULL; |
||||||
|
} |
||||||
|
if (array->elem_size == 0) { |
||||||
|
*errc = BARRAY_ERR_ELEM_SIZE_ZERO; |
||||||
|
return NULL; |
||||||
|
} |
||||||
|
if (ix >= array->len) { |
||||||
|
*errc = BARRAY_ERR_OUT_OF_BOUNDS; |
||||||
|
return NULL; |
||||||
|
} |
||||||
|
*errc = BARRAY_NO_ERR; |
||||||
|
unsigned char* ptr = array->ptr; |
||||||
|
return (void*) &ptr[(ix * array->elem_size)]; |
||||||
|
} |
||||||
|
|
||||||
|
void barray_set(BArray* array, size_t ix, void* value, BArray_ErrCode* errc) { |
||||||
|
assert(errc != NULL); |
||||||
|
if (array == NULL) { |
||||||
|
*errc = BARRAY_ERR_NULL; |
||||||
|
return; |
||||||
|
} |
||||||
|
if (array->elem_size == 0) { |
||||||
|
*errc = BARRAY_ERR_ELEM_SIZE_ZERO; |
||||||
|
return; |
||||||
|
} |
||||||
|
if (ix >= array->len) { |
||||||
|
*errc = BARRAY_ERR_OUT_OF_BOUNDS; |
||||||
|
return; |
||||||
|
} |
||||||
|
if (value == NULL) { |
||||||
|
*errc = BARRAY_ERR_NULL; |
||||||
|
return; |
||||||
|
} |
||||||
|
*errc = BARRAY_NO_ERR; |
||||||
|
unsigned char* ptr = array->ptr; |
||||||
|
void* elem_ptr = (void*) &ptr[(ix * array->elem_size)]; |
||||||
|
memcpy(elem_ptr, value, array->elem_size); |
||||||
|
} |
||||||
|
|
||||||
|
void barray_put(BArray* array, size_t ix, void* value, BArray_ErrCode* errc) { |
||||||
|
assert(errc != NULL); |
||||||
|
if (array == NULL) { |
||||||
|
*errc = BARRAY_ERR_NULL; |
||||||
|
return; |
||||||
|
} |
||||||
|
if (array->elem_size == 0) { |
||||||
|
*errc = BARRAY_ERR_ELEM_SIZE_ZERO; |
||||||
|
return; |
||||||
|
} |
||||||
|
if (ix > array->len) { |
||||||
|
*errc = BARRAY_ERR_OUT_OF_BOUNDS; |
||||||
|
return; |
||||||
|
} |
||||||
|
if (value == NULL) { |
||||||
|
*errc = BARRAY_ERR_NULL; |
||||||
|
return; |
||||||
|
} |
||||||
|
if (array->cap > (array->len + 1)) { |
||||||
|
barray_grow(array, errc); |
||||||
|
if (*errc != BARRAY_NO_ERR) { |
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
unsigned char* ptr = array->ptr; |
||||||
|
if (ix == array->len) { |
||||||
|
goto nomove; |
||||||
|
} |
||||||
|
void* src = (void*) &ptr[(ix * array->elem_size)]; |
||||||
|
void* dest = (void*) &ptr[((ix + 1) * array->elem_size)]; |
||||||
|
memmove(dest, src, array->elem_size * (array->len - ix)); |
||||||
|
nomove: |
||||||
|
*errc = BARRAY_NO_ERR; |
||||||
|
void* elem_ptr = (void*) &ptr[(ix * array->elem_size)]; |
||||||
|
memcpy(elem_ptr, value, array->elem_size); |
||||||
|
array->len = array->len + 1; |
||||||
|
} |
||||||
|
|
||||||
|
void barray_append(BArray* array, void* value, BArray_ErrCode* errc) { |
||||||
|
assert(errc != NULL); |
||||||
|
if (array == NULL) { |
||||||
|
*errc = BARRAY_ERR_NULL; |
||||||
|
return; |
||||||
|
} |
||||||
|
barray_put(array, array->len, value, errc); |
||||||
|
} |
||||||
|
|
||||||
|
void barray_remove(BArray *array, size_t ix, BArray_ErrCode *errc) { |
||||||
|
assert(errc != NULL); |
||||||
|
if (array == NULL) { |
||||||
|
*errc = BARRAY_ERR_NULL; |
||||||
|
return; |
||||||
|
} |
||||||
|
if (array->elem_size == 0) { |
||||||
|
*errc = BARRAY_ERR_ELEM_SIZE_ZERO; |
||||||
|
return; |
||||||
|
} |
||||||
|
if (ix >= array->len) { |
||||||
|
*errc = BARRAY_ERR_OUT_OF_BOUNDS; |
||||||
|
return; |
||||||
|
} |
||||||
|
unsigned char* ptr = array->ptr; |
||||||
|
if (ix == array->len) { |
||||||
|
goto nomove; |
||||||
|
} |
||||||
|
void* src = (void*) &ptr[(ix * array->elem_size)]; |
||||||
|
void* dest = (void*) &ptr[((ix - 1) * array->elem_size)]; |
||||||
|
memmove(dest, src, array->elem_size * (array->len - ix)); |
||||||
|
nomove: |
||||||
|
*errc = BARRAY_NO_ERR; |
||||||
|
array->len = array->len - 1; |
||||||
|
} |
||||||
|
|
||||||
|
void barray_clear(BArray *array, BArray_ErrCode *errc) { |
||||||
|
assert(errc != NULL); |
||||||
|
if (array == NULL) { |
||||||
|
*errc = BARRAY_ERR_NULL; |
||||||
|
return; |
||||||
|
} |
||||||
|
*errc = BARRAY_NO_ERR; |
||||||
|
array->len = 0; |
||||||
|
} |
||||||
|
|
||||||
|
void barray_destroy(BArray *array, BArray_ErrCode* errc) { |
||||||
|
assert(errc != NULL); |
||||||
|
if (array == NULL) { |
||||||
|
*errc = BARRAY_ERR_NULL; |
||||||
|
} |
||||||
|
if (array->ptr != NULL) { |
||||||
|
free(array->ptr); |
||||||
|
} |
||||||
|
*errc = BARRAY_NO_ERR; |
||||||
|
*array = BARRAY_INVALID; |
||||||
|
} |
@ -0,0 +1,2 @@ |
|||||||
|
src = ['barray.c'] |
||||||
|
library('barray', src, include_directories: include) |
Loading…
Reference in new issue