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