diff --git a/CMakeLists.txt b/CMakeLists.txt index dadddc8..d48b747 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,10 +2,10 @@ cmake_minimum_required(VERSION 3.12) set(PROJECT_NAME libguf) project(${PROJECT_NAME}) -set(SOURCES src/guf_common.c src/guf_str.c src/guf_dict.c src/guf_dbuf.c src/guf_obj.c) +set(SOURCES src/guf_str.c src/guf_dict.c) add_library(${PROJECT_NAME} STATIC ${SOURCES}) -target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}}/lib/guf) +# target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}}/lib/guf) # target_include_directories(${PROJECT_NAME} PRIVATE src) add_executable(libguf_test ${SOURCES} src/guf_test.c) diff --git a/src/guf_assert.h b/src/guf_assert.h index 04f1b7a..65caca4 100644 --- a/src/guf_assert.h +++ b/src/guf_assert.h @@ -1,3 +1,15 @@ +#ifndef GUF_ASSERT_H +#define GUF_ASSERT_H #include #include +#include +#define GUF_ASSERT(COND) assert(COND) +#define GUF_ASSERT_RELEASE(COND) do { \ + if (!(COND)) { \ + fprintf(stderr, "libguf release assertion failed: " #COND ", file " __FILE__ ", line %d\n", __LINE__); \ + exit(EXIT_FAILURE); \ + } \ +} while (0); + +#endif \ No newline at end of file diff --git a/src/guf_common.c b/src/guf_common.c deleted file mode 100644 index f26229d..0000000 --- a/src/guf_common.c +++ /dev/null @@ -1,177 +0,0 @@ -#include "guf_common.h" -#include -#include - -#include "guf_dict.h" -#include "guf_str.h" - -bool guf_is_big_endian(void) -{ - unsigned i = 1; - const char *bytes = (const char*)&i; - return bytes[0] != 1; -} - -// typedef struct alloc_info { -// size_t num_alloc, num_free; -// } alloc_info; - - -// static bool init = false; -// static guf_dict alloc_table; -// static guf_dict pointer_cnt; - -// bool guf_alloc_init(void) -// { -// alloc_table = GUF_DICT_UNINITIALISED; -// pointer_cnt = GUF_DICT_UNINITIALISED; - -// guf_dict_kv_funcs alloc_info_funcs = GUF_DICT_FUNCS_NULL; -// alloc_info_funcs.type_size = sizeof(alloc_info); - -// bool success = guf_dict_init(&alloc_table, 64, &GUF_DICT_FUNCS_GUF_STR, &alloc_info_funcs); -// if (!success) { -// return false; -// } - -// guf_dict_kv_funcs void_ptr_funcs = GUF_DICT_FUNCS_NULL; -// void_ptr_funcs.type_size = sizeof(void*); - -// guf_dict_kv_funcs size_t_funcs = GUF_DICT_FUNCS_NULL; -// size_t_funcs.type_size = sizeof(size_t); - -// success = guf_dict_init(&pointer_cnt, 128, &void_ptr_funcs, &size_t_funcs); - -// if (!success) { -// return false; -// } - -// if (success) { -// init = true; -// } -// return success; -// } - -// static void track_alloc(void *ptr, const char *name) -// { -// if (!init) { -// return; -// } - -// if (guf_dict_contains_key(&pointer_cnt, &ptr)) { -// GUF_ASSERT_RELEASE(false); -// } else { -// size_t cnt = 1; -// bool succ = guf_dict_insert(&pointer_cnt, &ptr, &cnt, GUF_DICT_CPY_KEY_VAL); -// GUF_ASSERT_RELEASE(succ); -// } - -// guf_str name_str = guf_str_new_view_from_cstr(name); - -// if (guf_dict_contains_key(&alloc_table, &name_str)) { -// alloc_info *ai = guf_dict_get_val(&alloc_table, &name_str); -// GUF_ASSERT_RELEASE(ai); -// ai->num_alloc += 1; -// return; -// } else { -// guf_str new_str = guf_str_new(name); -// GUF_ASSERT_RELEASE(guf_str_is_valid(&new_str)); -// alloc_info ai = {.num_alloc = 1, .num_free = 0}; -// bool succ = guf_dict_insert(&alloc_table, &new_str, &ai, 0); -// GUF_ASSERT_RELEASE(succ); -// GUF_ASSERT(guf_dict_contains_key(&alloc_table, &name_str)); -// } -// } - -// static void track_free(void *ptr, const char *name) -// { -// if (!init) { -// return; -// } - -// GUF_ASSERT_RELEASE(guf_dict_contains_key(&pointer_cnt, &ptr)); - -// size_t *cnt = guf_dict_get_val(&pointer_cnt, &ptr); -// GUF_ASSERT_RELEASE(cnt); -// if (*cnt == 0) { -// fprintf(stderr, "Double free for %s\n", name); -// GUF_ASSERT_RELEASE(false); -// } else{ -// GUF_ASSERT(*cnt == 1); -// *cnt = 0; -// } - -// const guf_str name_str = guf_str_new_view_from_cstr(name); - -// if (guf_dict_contains_key(&alloc_table, &name_str)) { -// alloc_info *ai = guf_dict_get_val(&alloc_table, &name_str); -// GUF_ASSERT_RELEASE(ai); -// GUF_ASSERT_RELEASE(ai->num_alloc > 0); -// ai->num_free += 1; -// } -// } - -// void *guf_malloc(size_t size, const char *name) -// { -// void *ptr = malloc(size); -// if (!ptr) { -// return ptr; -// } - -// track_alloc(ptr, name); - -// return ptr; -// } - -// void *guf_calloc(size_t count, size_t size, const char *name) -// { -// void *ptr = calloc(count, size); -// if (!ptr) { -// return ptr; -// } - -// track_alloc(ptr, name); - -// return ptr; -// } - -// void *guf_realloc(void *ptr, size_t size, const char *name) -// { -// void *new_ptr = realloc(ptr, size); -// if (!ptr) { -// return new_ptr; -// } - -// track_alloc(ptr, name); - -// return new_ptr; -// } - -// void guf_free(void *ptr, const char *name) -// { -// if (!ptr) { -// return; -// } - -// track_free(ptr, name); -// free(ptr); - -// return; -// } - -// void guf_alloc_print(void) -// { -// if (!init) { -// printf("guf_alloc_print: guf_alloc not initialised\n"); -// return; -// } - -// printf("size: %zu\n", alloc_table.size); - -// for (guf_dict_iter it = guf_dict_iter_begin(&alloc_table); !guf_dict_iter_is_end(&it); guf_dict_iter_advance(&it)) { -// const guf_str *key = it.key; -// alloc_info *val = it.val; -// // printf("idx: %zu elem %zu\n", it.idx, it.elems_seen); -// printf("'%s':\n - %zu alloc(s)\n - %zu free(s)\n\n", guf_str_get_const_c_str(key), val->num_alloc, val->num_free); -// } -// } \ No newline at end of file diff --git a/src/guf_common.h b/src/guf_common.h index ffd4f01..72d8ebf 100644 --- a/src/guf_common.h +++ b/src/guf_common.h @@ -1,72 +1,26 @@ #ifndef GUF_COMMON_H #define GUF_COMMON_H -#include #include #include +#include +#include +#include + +#include "guf_common_utils.h" +#include "guf_hash.h" #include "guf_assert.h" -#define GUF_DICT_USE_32_BIT_HASH - -#ifdef GUF_DICT_USE_32_BIT_HASH - typedef uint32_t guf_hash_size_t; -#else - typedef uint64_t guf_hash_size_t; -#endif - -#define GUF_ASSERT(COND) assert(COND) -#define GUF_ASSERT_RELEASE(COND) do { \ - if (!(COND)) { \ - fprintf(stderr, "libguf release assertion failed: " #COND ", file " __FILE__ ", line %d\n", __LINE__); \ - exit(EXIT_FAILURE); \ - } \ -} while (0); - - -#define GUF_STATIC_BUF_SIZE(BUF) (sizeof((BUF)) / (sizeof((BUF)[0]))) - -#define GUF_ABS(X) ((X) >= 0 ? (X) : -(X)) -#define GUF_MIN(X, Y) ((X) <= (Y) ? (X) : (Y)) -#define GUF_MAX(X, Y) ((X) >= (Y) ? (X) : (Y)) -#define GUF_CLAMP(X, MIN, MAX) GUF_MAX(GUF_MIN((X), (MAX)), (MIN)) - -static inline bool guf_is_mul_overflow_size_t(size_t a, size_t b) -{ - size_t c = a * b; - return a != 0 && ((c / a) != b); -} - -static inline size_t guf_safe_mul_size_t(size_t a, size_t b) -{ - GUF_ASSERT_RELEASE(!guf_is_mul_overflow_size_t(a, b)); - return a * b; -} - -static inline bool guf_is_safe_size_calc(ptrdiff_t count, ptrdiff_t sizeof_elem) -{ - if (count < 0 || sizeof_elem <= 0) { - return false; - } - size_t size = guf_safe_mul_size_t(count, sizeof_elem); - return size <= PTRDIFF_MAX; -} - -static inline ptrdiff_t guf_safe_size_calc(ptrdiff_t count, ptrdiff_t sizeof_elem) -{ - GUF_ASSERT_RELEASE(count >= 0); - GUF_ASSERT_RELEASE(sizeof_elem > 0); - size_t size = guf_safe_mul_size_t(count, sizeof_elem); - GUF_ASSERT_RELEASE(size <= PTRDIFF_MAX); - return size; -} - -bool guf_is_big_endian(void); - -bool guf_alloc_init(void); -void *guf_malloc(size_t size, const char *name); -void *guf_calloc(size_t count, size_t size, const char *name); -void *guf_realloc(void *ptr, size_t size, const char *name); -void guf_free(void *ptr, const char *name); -void guf_alloc_print(void); +typedef enum guf_obj_cpy_opt { + GUF_CPY_VALUE = 0, + GUF_CPY_DEEP = 1, + GUF_CPY_MOVE = 2, +} guf_obj_cpy_opt; +// bool guf_alloc_init(void); +// void *guf_malloc(size_t size, const char *name); +// void *guf_calloc(size_t count, size_t size, const char *name); +// void *guf_realloc(void *ptr, size_t size, const char *name); +// void guf_free(void *ptr, const char *name); +// void guf_alloc_print(void); #endif diff --git a/src/guf_common_utils.h b/src/guf_common_utils.h new file mode 100644 index 0000000..9dcf7f3 --- /dev/null +++ b/src/guf_common_utils.h @@ -0,0 +1,63 @@ +#ifndef GUF_COMMON_UTILS_H +#define GUF_COMMON_UTILS_H +#include "guf_assert.h" +#include + +// The GUFCAT/GUF_TOK_CAT indirection is necessary because the ## operation alone does not evaluate the macro arguments. +#define GUF_TOK_CAT(a, b) a##b +#define GUFCAT(a, b) GUF_TOK_CAT(a, b) + +#define GUF_FOREACH(CNT_PTR, CNT_TYPE, IT_NAME) for (GUFCAT(CNT_TYPE, _iter) IT_NAME = GUFCAT(CNT_TYPE, _begin)(CNT_PTR); IT_NAME.cur != IT_NAME.end; IT_NAME = IT_NAME.next(&IT_NAME, 1)) + +#define GUF_STATIC_BUF_SIZE(BUF) (sizeof((BUF)) / (sizeof((BUF)[0]))) + +#define GUF_ABS(X) ((X) >= 0 ? (X) : -(X)) +#define GUF_MIN(X, Y) ((X) <= (Y) ? (X) : (Y)) +#define GUF_MAX(X, Y) ((X) >= (Y) ? (X) : (Y)) +#define GUF_CLAMP(X, MIN, MAX) GUF_MAX(GUF_MIN((X), (MAX)), (MIN)) + +static inline int guf_abs_int(int x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(x > INT_MIN ); return -x;} +static inline long guf_abs_lng(long x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(x > LONG_MIN ); return -x;} +static inline int8_t guf_abs_i8 (int8_t x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(x > INT8_MIN ); return -x;} +static inline int16_t guf_abs_i16(int16_t x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(x > INT16_MIN); return -x;} +static inline int32_t guf_abs_i32(int32_t x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(x > INT32_MIN); return -x;} +static inline int64_t guf_abs_i64(int64_t x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(x > INT64_MIN); return -x;} + +static inline bool guf_is_mul_overflow_size_t(size_t a, size_t b) +{ + size_t c = a * b; + return a != 0 && ((c / a) != b); +} + +static inline size_t guf_safe_mul_size_t(size_t a, size_t b) +{ + GUF_ASSERT_RELEASE(!guf_is_mul_overflow_size_t(a, b)); + return a * b; +} + +static inline bool guf_is_safe_size_calc(ptrdiff_t count, ptrdiff_t sizeof_elem) +{ + if (count < 0 || sizeof_elem <= 0) { + return false; + } + size_t size = guf_safe_mul_size_t(count, sizeof_elem); + return size <= PTRDIFF_MAX; +} + +static inline ptrdiff_t guf_safe_size_calc(ptrdiff_t count, ptrdiff_t sizeof_elem) +{ + GUF_ASSERT_RELEASE(count >= 0); + GUF_ASSERT_RELEASE(sizeof_elem > 0); + size_t size = guf_safe_mul_size_t(count, sizeof_elem); + GUF_ASSERT_RELEASE(size <= PTRDIFF_MAX); + return size; +} + +static inline bool guf_is_big_endian(void) +{ + unsigned i = 1; + const char *bytes = (const char*)&i; + return bytes[0] != 1; +} + +#endif \ No newline at end of file diff --git a/src/guf_cstr.h b/src/guf_cstr.h new file mode 100644 index 0000000..88990ae --- /dev/null +++ b/src/guf_cstr.h @@ -0,0 +1,92 @@ +#ifndef GUF_CSTR_H +#define GUF_CSTR_H +#include +#include "guf_common.h" + +typedef const char* guf_const_cstr; +typedef char* guf_heap_cstr; + +#define GUF_OBJ_TYPE guf_const_cstr +#include "guf_obj.h" + +#define GUF_OBJ_TYPE guf_heap_cstr +#include "guf_obj.h" + +static inline guf_heap_cstr *guf_heap_cstr_cpy_init(guf_heap_cstr *dst, const guf_heap_cstr *src) +{ + GUF_ASSERT_RELEASE(dst && src); + if (*src == NULL) { + *dst = NULL; + return dst; + } + *dst = strdup(*src); + GUF_ASSERT_RELEASE(*dst); + return dst; +} + +static inline guf_heap_cstr *guf_heap_cstr_move_init(guf_heap_cstr *dst, guf_heap_cstr *src) +{ + GUF_ASSERT_RELEASE(dst && src); + *dst = *src; + *src = NULL; + return dst; +} + +static inline void guf_heap_cstr_free(guf_heap_cstr *a) +{ + GUF_ASSERT_RELEASE(a); + free(*a); +} + +static inline int guf_heap_cstr_cmp(const guf_heap_cstr *a, const guf_heap_cstr *b) +{ + + GUF_ASSERT_RELEASE(a && b); + GUF_ASSERT_RELEASE(*a && *b); + return strcmp(*a, *b); +} + +static inline GUF_OBJ_OPS_DEFINE_CMP_INVERSE(guf_heap_cstr, guf_heap_cstr_cmp, guf_heap_cstr_cmp_inv) + +static inline bool guf_heap_cstr_eq(const guf_heap_cstr *a, const guf_heap_cstr *b) +{ + GUF_ASSERT_RELEASE(a && b); + GUF_ASSERT_RELEASE(*a && *b); + return 0 == strcmp(*a, *b); +} + +static guf_heap_cstr_ops guf_heap_cstr_operations = { + .copy_init = guf_heap_cstr_cpy_init, + .move_init = guf_heap_cstr_move_init, + .free = guf_heap_cstr_free, + .cmp = guf_heap_cstr_cmp, + .cmp_inv = guf_heap_cstr_cmp_inv, + .eq = guf_heap_cstr_eq +}; + +static inline int guf_const_cstr_cmp(const guf_const_cstr *a, const guf_const_cstr *b) +{ + GUF_ASSERT_RELEASE(a && b); + GUF_ASSERT_RELEASE(*a && *b); + return strcmp(*a, *b); +} + +static inline GUF_OBJ_OPS_DEFINE_CMP_INVERSE(guf_const_cstr, guf_const_cstr_cmp, guf_const_cstr_cmp_inv) + +static inline bool guf_const_cstr_eq(const guf_const_cstr *a, const guf_const_cstr *b) +{ + GUF_ASSERT_RELEASE(a && b); + GUF_ASSERT_RELEASE(*a && *b); + return 0 == strcmp(*a, *b); +} + +static guf_const_cstr_ops guf_const_cstr_operations = { + .copy_init = NULL, + .move_init = NULL, + .free = NULL, + .cmp = guf_const_cstr_cmp, + .cmp_inv = guf_const_cstr_cmp_inv, + .eq = guf_const_cstr_eq +}; + +#endif \ No newline at end of file diff --git a/src/guf_darr.h b/src/guf_darr.h deleted file mode 100644 index 2c81986..0000000 --- a/src/guf_darr.h +++ /dev/null @@ -1,234 +0,0 @@ -#ifndef GUF_DARR_H -#define GUF_DARR_H -#include -#include -#include -#include -#include "guf_assert.h" - -#define GUF_DARR_NEW_CAPACITY(CAP) ((CAP) * 2) -#define GUF_DARR_FOREACH(ARR, ELEM_T, ELEM_PTR) assert((ARR).capacity); for (ELEM_T *ELEM_PTR = (ARR).data, *end = (ARR).data + (ARR).size; ELEM_PTR != end; ++ELEM_PTR) - -// TODO: move and copy semantics? (TYPE vs pointer to TYPE); append_val vs append_ptr -// cpy makes only sense for ptrs or ref/handle types -#define GUF_DARR_DEFINE(TYPE, TYPENAME, ELEM_CPY, ELEM_FREE) \ -typedef struct guf_darr_##TYPENAME { \ - TYPE *data; \ - size_t size, capacity; \ - TYPE (*elem_cpy)(const TYPE elem); /* Can be NULL */ \ - void (*elem_free)(TYPE elem); /* Can be NULL */ \ -} guf_darr_##TYPENAME; \ -\ -bool guf_darr_##TYPENAME##_init(guf_darr_##TYPENAME *arr, size_t start_cap) { \ - assert(arr); \ - if (!arr) { \ - return false; \ - } \ - if (start_cap < 1) { \ - start_cap = 1; \ - } \ - const size_t buf_size = start_cap * sizeof(TYPE); \ - if (buf_size < start_cap) { /* Overflow */ \ - return false; \ - } \ - arr->data = malloc(buf_size); \ - if (!arr->data) { \ - arr->size = arr->capacity = 0; \ - return false; \ - } \ - arr->size = 0; \ - arr->capacity = start_cap; \ - arr->elem_cpy = ELEM_CPY; \ - arr->elem_free = ELEM_FREE; \ - return true; \ -}\ -\ -bool guf_darr_##TYPENAME##_append(guf_darr_##TYPENAME *arr, TYPE elem) { \ - bool valid = arr && arr->data && arr->capacity && arr->size <= arr->capacity; \ - assert(valid); \ - if (!valid) { \ - return false; \ - }\ - if (arr->size == arr->capacity) { \ - const size_t new_cap = GUF_DARR_NEW_CAPACITY(arr->capacity); \ - if (new_cap <= arr->capacity) { /* Overflow */ \ - return false; \ - } \ - const size_t buf_size = new_cap * sizeof(TYPE); \ - if (buf_size < new_cap) { /* Overflow */ \ - return false; \ - } \ - TYPE *data_new = realloc(arr->data, buf_size); \ - if (!data_new) { \ - return false; \ - } \ - arr->data = data_new; \ - arr->capacity = new_cap; \ - } \ - assert(arr->size < arr->capacity); \ - if (arr->elem_cpy) { \ - arr->data[arr->size++] = arr->elem_cpy(elem); \ - } else { \ - arr->data[arr->size++] = elem; \ - } \ - return true; \ -}\ -\ -bool guf_darr_##TYPENAME##_insert_at(guf_darr_##TYPENAME *arr, TYPE elem, size_t idx) { \ - bool valid = arr && arr->data && arr->capacity && arr->size <= arr->capacity; \ - assert(valid); \ - if (!valid) { \ - return false; \ - }\ - assert(idx < arr->size); \ - if (idx >= arr->size) { \ - return false; \ - } \ - assert(arr->size != 0); \ - if (arr->size == arr->capacity) { \ - const size_t new_cap = GUF_DARR_NEW_CAPACITY(arr->capacity); \ - if (new_cap <= arr->capacity) { /* Overflow */ \ - return false; \ - } \ - const size_t buf_size = new_cap * sizeof(TYPE); \ - if (buf_size < new_cap) { /* Overflow */ \ - return false; \ - } \ - TYPE *data_new = realloc(arr->data, buf_size); \ - if (!data_new) { \ - return false; \ - } \ - arr->data = data_new; \ - arr->capacity = new_cap; \ - } \ - assert(arr->size < arr->capacity); \ - const size_t new_last_idx = arr->size; \ - for (size_t i = new_last_idx; i > idx; --i) { \ - arr->data[i] = arr->data[i - 1]; \ - } \ - if (arr->elem_cpy) { \ - arr->data[idx] = arr->elem_cpy(elem); \ - } else { \ - arr->data[idx] = elem; \ - } \ - ++arr->size; \ - return true; \ -}\ -\ -void guf_darr_##TYPENAME##_pop_back(guf_darr_##TYPENAME *arr) { \ - bool valid = arr && arr->data && arr->capacity && arr->size <= arr->capacity; \ - assert(valid); \ - if (!valid) { \ - return; \ - }\ - if (arr->size == 0) { \ - return; \ - } \ - if (arr->elem_free) { \ - arr->elem_free(arr->data[arr->size - 1]); \ - } \ - --arr->size; \ -}\ -\ -TYPE *guf_darr_##TYPENAME##_back(const guf_darr_##TYPENAME *arr) { \ - bool valid = arr && arr->data && arr->capacity && arr->size <= arr->capacity; \ - assert(valid); \ - if (!valid) { \ - return NULL; \ - }\ - if (arr->size == 0) { \ - return NULL; \ - } \ - return arr->data + (arr->size - 1);\ -}\ -\ -TYPE *guf_darr_##TYPENAME##_front(const guf_darr_##TYPENAME *arr) { \ - bool valid = arr && arr->data && arr->capacity && arr->size <= arr->capacity; \ - assert(valid); \ - if (!valid) { \ - return NULL; \ - }\ - if (arr->size == 0) { \ - return NULL; \ - } \ - return arr->data + 0;\ -}\ -\ -TYPE *guf_darr_##TYPENAME##_at(const guf_darr_##TYPENAME *arr, size_t idx) { \ - bool valid = arr && arr->data && arr->capacity && arr->size <= arr->capacity; \ - assert(valid); \ - if (!valid) { \ - return NULL; \ - }\ - if (idx >= arr->size) { \ - return NULL; \ - } \ - assert(arr->size != 0); \ - return arr->data + idx; \ -}\ -\ -bool guf_darr_##TYPENAME##_erase_at(guf_darr_##TYPENAME *arr, size_t idx) { \ - bool valid = arr && arr->data && arr->capacity && arr->size <= arr->capacity; \ - assert(valid); \ - if (!valid) { \ - return false; \ - }\ - if (idx >= arr->size) { \ - return false; \ - } \ - assert(arr->size != 0); \ - if (arr->elem_free) { \ - arr->elem_free(arr->data[idx]); \ - } \ - if (idx == arr->size - 1) { \ - --arr->size; \ - return true; \ - }\ - if (idx + 1 < idx) { /* Overflow */ \ - return false; \ - } \ - for (size_t i = idx + 1; i < arr->size; ++i) { \ - arr->data[i - 1] = arr->data[i]; \ - } \ - --arr->size; \ - return true; \ -}\ -\ -bool guf_darr_##TYPENAME##_shrink_to_fit(guf_darr_##TYPENAME *arr) { \ - bool valid = arr && arr->data && arr->capacity && arr->size <= arr->capacity; \ - assert(valid); \ - if (!valid) { \ - return false; \ - }\ - if (arr->size == arr->capacity) { \ - return true; \ - }\ - const size_t new_cap = arr->size == 0 ? 1 : arr->size; \ - TYPE *data_new = realloc(arr->data, sizeof(TYPE) * new_cap); \ - if (!data_new) { \ - return false; \ - } \ - arr->data = data_new; \ - arr->capacity = new_cap; \ - return true; \ -}\ -\ -bool guf_darr_##TYPENAME##_free(guf_darr_##TYPENAME *arr) { \ - bool valid = arr && arr->data && arr->capacity && arr->size <= arr->capacity; \ - assert(valid); \ - if (!valid) { \ - return false; \ - }\ - if (arr->elem_free) { \ - for (size_t i = 0; i < arr->size; ++i) { \ - arr->elem_free(arr->data[i]); \ - } \ - } \ - free(arr->data); \ - arr->data = NULL; \ - arr->capacity = arr->size = 0; \ - return true; \ -}\ - -#endif - diff --git a/src/guf_dbuf.c b/src/guf_dbuf.c deleted file mode 100644 index 5f3731b..0000000 --- a/src/guf_dbuf.c +++ /dev/null @@ -1,260 +0,0 @@ -#include -#include "guf_dbuf.h" -#include "guf_common.h" - -static inline bool dbuf_valid_and_not_empty(const guf_dbuf* dbuf) { - return dbuf && guf_obj_meta_sizeof_obj(dbuf->elem_meta) > 0 && dbuf->data && dbuf->capacity > 0 && dbuf->size > 0 && dbuf->size <= dbuf->capacity; -} - -static inline bool dbuf_valid_and_maybe_empty(const guf_dbuf* dbuf) { - GUF_ASSERT_RELEASE((!dbuf->data && !dbuf->capacity) || (dbuf->data && dbuf->capacity)); - return dbuf && guf_obj_meta_sizeof_obj(dbuf->elem_meta) > 0 && dbuf->capacity >= 0 && dbuf->size >= 0 && dbuf->size <= dbuf->capacity; -} - -bool guf_dbuf_reserve(guf_dbuf *dbuf, ptrdiff_t min_capacity) -{ - GUF_ASSERT_RELEASE(dbuf_valid_and_maybe_empty(dbuf)); - GUF_ASSERT_RELEASE(min_capacity >= 0); - - const ptrdiff_t sizeof_elem = guf_obj_meta_sizeof_obj(dbuf->elem_meta); - - if (min_capacity <= dbuf->capacity) { - return true; - } - - if (!dbuf->data) { - GUF_ASSERT_RELEASE(guf_is_safe_size_calc(min_capacity, sizeof_elem)); - void *data = calloc(min_capacity, sizeof_elem); - GUF_ASSERT(data); - if (!data) { - return false; - } - dbuf->data = data; - } else { - void *data = realloc(dbuf->data, guf_safe_size_calc(min_capacity, sizeof_elem)); - GUF_ASSERT(data); - if (!data) { - return false; - } - dbuf->data = data; - } - dbuf->capacity = min_capacity; - return true; -} - -bool guf_dbuf_init(guf_dbuf *dbuf, guf_obj_meta elem_meta, ptrdiff_t start_cap) -{ - GUF_ASSERT_RELEASE(dbuf); - GUF_ASSERT_RELEASE(start_cap >= 0); - - const ptrdiff_t sizeof_elem = guf_obj_meta_sizeof_obj(elem_meta); - GUF_ASSERT_RELEASE(sizeof_elem > 0); - dbuf->elem_meta = elem_meta; - - dbuf->size = dbuf->capacity = 0; - - if (start_cap == 0) { - dbuf->data = NULL; - return true; - } - - bool success = guf_dbuf_reserve(dbuf, start_cap); - if (success) { - dbuf->capacity = start_cap; - } - GUF_ASSERT(success); - return success; -} - -guf_dbuf guf_dbuf_new(guf_obj_meta elem_meta) -{ - guf_dbuf dbuf = {0}; - bool success = guf_dbuf_init(&dbuf, elem_meta, 0); - GUF_ASSERT_RELEASE(success); - return dbuf; -} - -guf_dbuf guf_dbuf_new_with_capacity(guf_obj_meta elem_meta, ptrdiff_t capacity) -{ - GUF_ASSERT_RELEASE(capacity >= 0); - guf_dbuf dbuf = {0}; - bool success = guf_dbuf_init(&dbuf, elem_meta, capacity); - GUF_ASSERT_RELEASE(success); - return dbuf; -} - -static inline void *get_elem(guf_dbuf *dbuf, ptrdiff_t idx) -{ - GUF_ASSERT_RELEASE(dbuf_valid_and_not_empty(dbuf)); - GUF_ASSERT_RELEASE(idx >= 0); - GUF_ASSERT_RELEASE(idx < dbuf->size && idx < dbuf->capacity); - char *ptr = (char*)dbuf->data; - return ptr + guf_safe_size_calc(idx, guf_obj_meta_sizeof_obj(dbuf->elem_meta)); -} - -static inline ptrdiff_t next_capacity(ptrdiff_t old_cap) -{ - GUF_ASSERT_RELEASE(old_cap >= 0); - size_t new_cap = 0; - if (old_cap == 0) { - new_cap = GUF_DBUF_INITIAL_CAP; - } else if (old_cap < 8) { - new_cap = (size_t)old_cap * 2ull; - } else { - new_cap = (size_t)old_cap * 3ull / 2ull; - } - GUF_ASSERT_RELEASE(new_cap > (size_t)old_cap); // Fail on overflow. - GUF_ASSERT_RELEASE(new_cap <= PTRDIFF_MAX); - return new_cap; -} - -static inline bool grow_if_full(guf_dbuf *dbuf) -{ - GUF_ASSERT_RELEASE(dbuf->capacity >= 0 && dbuf->size >= 0); - if (dbuf->size == dbuf->capacity) { - bool success = guf_dbuf_reserve(dbuf, next_capacity(dbuf->capacity)); - if (!success) { - return false; - } - } - GUF_ASSERT_RELEASE(dbuf->size < dbuf->capacity); - return true; -} - -static inline void *cpy_to(guf_dbuf *dbuf, ptrdiff_t idx, void *elem, guf_obj_cpy_opt cpy_opt) -{ - GUF_ASSERT_RELEASE(dbuf_valid_and_not_empty(dbuf)); - GUF_ASSERT_RELEASE(elem); - GUF_ASSERT_RELEASE(idx >= 0 && idx < dbuf->capacity && idx < dbuf->size); - - void *dst = get_elem(dbuf, idx); - dst = guf_cpy(dst, elem, dbuf->elem_meta, cpy_opt); - GUF_ASSERT_RELEASE(dst); - return dst; -} - -void *guf_dbuf_push(guf_dbuf *dbuf, void *elem, guf_obj_cpy_opt cpy_opt) -{ - GUF_ASSERT_RELEASE(dbuf_valid_and_maybe_empty(dbuf)); - - bool success = grow_if_full(dbuf); - GUF_ASSERT(success); - if (!success) { - return NULL; - } - - return cpy_to(dbuf, dbuf->size++, elem, cpy_opt); -} - -void *guf_dbuf_insert(guf_dbuf *dbuf, void *elem, ptrdiff_t idx, guf_obj_cpy_opt cpy_opt) -{ - GUF_ASSERT_RELEASE(dbuf_valid_and_maybe_empty(dbuf)); - GUF_ASSERT_RELEASE(idx >= 0 && idx <= dbuf->size); - - if (idx == dbuf->size) { - return guf_dbuf_push(dbuf, elem, cpy_opt); - } - GUF_ASSERT_RELEASE(idx < dbuf->size); - - bool success = grow_if_full(dbuf); - GUF_ASSERT(success); - if (!success) { - return NULL; - } - - for (ptrdiff_t free_idx = dbuf->size++; free_idx > idx; --free_idx) { - void *dst = get_elem(dbuf, free_idx); - void *src = get_elem(dbuf, free_idx - 1); - guf_cpy(dst, src, dbuf->elem_meta, GUF_CPY_VALUE); - } - return cpy_to(dbuf, idx, elem, cpy_opt); -} - -void guf_dbuf_erase(guf_dbuf *dbuf, ptrdiff_t idx) -{ - GUF_ASSERT_RELEASE(dbuf_valid_and_not_empty(dbuf)); - GUF_ASSERT_RELEASE(idx >= 0); - GUF_ASSERT_RELEASE(idx < dbuf->size); - - void *to_erase = get_elem(dbuf, idx); - if (dbuf->elem_meta.has_ops && dbuf->elem_meta.data.ops->free) { - dbuf->elem_meta.data.ops->free(to_erase); - } - - for (ptrdiff_t free_idx = idx; free_idx < dbuf->size - 1; ++free_idx) { - void *dst = get_elem(dbuf, free_idx); - void *src = get_elem(dbuf, free_idx + 1); - guf_cpy(dst, src, dbuf->elem_meta, GUF_CPY_VALUE); - } -} - -void *guf_dbuf_pop(guf_dbuf *dbuf) -{ - GUF_ASSERT_RELEASE(dbuf_valid_and_not_empty(dbuf)); - void *popped = get_elem(dbuf, dbuf->size - 1); - dbuf->size -= 1; - return popped; -} - -void *guf_dbuf_at(guf_dbuf *dbuf, ptrdiff_t idx) -{ - GUF_ASSERT_RELEASE(dbuf_valid_and_not_empty(dbuf)); - GUF_ASSERT_RELEASE(idx >= 0 && idx < dbuf->size) - return get_elem(dbuf, idx); -} - -void *guf_dbuf_front(guf_dbuf *dbuf) -{ - GUF_ASSERT_RELEASE(dbuf_valid_and_not_empty(dbuf)); - return get_elem(dbuf, 0); -} - -void *guf_dbuf_back(guf_dbuf *dbuf) -{ - GUF_ASSERT_RELEASE(dbuf_valid_and_not_empty(dbuf)); - return get_elem(dbuf, (ptrdiff_t)dbuf->size - 1); -} - -bool guf_dbuf_shrink_to_fit(guf_dbuf *dbuf) -{ - GUF_ASSERT_RELEASE(dbuf_valid_and_maybe_empty(dbuf)); - - const ptrdiff_t new_capacity = dbuf->size; - if (new_capacity == dbuf->capacity) { - return true; - } - - GUF_ASSERT_RELEASE(dbuf->data); - - void *data = realloc(dbuf->data, guf_safe_size_calc(new_capacity, guf_obj_meta_sizeof_obj(dbuf->elem_meta))); - GUF_ASSERT(data); - if (!data) { - return false; - } - dbuf->data = data; - dbuf->capacity = new_capacity; - return true; -} - -void guf_dbuf_free(guf_dbuf *dbuf) -{ - GUF_ASSERT_RELEASE(dbuf_valid_and_maybe_empty(dbuf)); - - if (dbuf->capacity == 0) { - GUF_ASSERT_RELEASE(!dbuf->data); - GUF_ASSERT_RELEASE(dbuf->size == 0); - return; - } - - GUF_ASSERT_RELEASE(dbuf->data); - - if (dbuf->elem_meta.has_ops && dbuf->elem_meta.data.ops->free) { - for (ptrdiff_t idx = 0; idx < dbuf->size; ++idx) { - // printf("freeing %s\n",*(char**)get_elem(dbuf, idx)); - dbuf->elem_meta.data.ops->free(get_elem(dbuf, idx)); - } - } - free(dbuf->data); - dbuf->data = NULL; - dbuf->capacity = dbuf->size = 0; -} diff --git a/src/guf_dbuf.h b/src/guf_dbuf.h index 8d77e0c..4ad2b5a 100644 --- a/src/guf_dbuf.h +++ b/src/guf_dbuf.h @@ -1,81 +1,355 @@ -#ifndef GUF_DBUF_H -#define GUF_DBUF_H - #include #include #include #include #include "guf_assert.h" -#include "guf_obj.h" +#include "guf_common.h" + +#ifndef GUF_DBUF_H +#define GUF_DBUF_H + #define GUF_DBUF_FOREACH(DBUF, ELEM_TYPE, ELEM_PTR_NAME) for (ELEM_TYPE *ELEM_PTR_NAME = (DBUF).data, *end = (DBUF).data ? (DBUF).data + (DBUF).size : NULL; ELEM_PTR_NAME != end; ++ELEM_PTR_NAME) +#endif // Used for the first growth if dbuf->capacity is zero. -#define GUF_DBUF_INITIAL_CAP 8 +#ifndef GUF_DBUF_INITIAL_CAP + #define GUF_DBUF_INITIAL_CAP 8 +#endif -typedef struct guf_dbuf { - bool is_init; - void *data; +#ifndef GUF_CNT_T + #error "Undefined container template GUF_CONTAINER_T" +#endif + +#ifndef GUF_CNT_NAME + #error "Undefined container template GUF_CONTAINER_T" +#endif + +#ifndef GUF_CNT_T_OPS + #define GUF_OBJ_TYPE GUF_CNT_T + // #define GUF_OBJ_OPS_TYPENAME GUFCAT(GUF_CNT_T, _ops) + #include "guf_obj.h" + #define GUF_CNT_T_OPS GUF_OBJ_OPS_EMPTY(GUFCAT(GUF_CNT_T, _ops)) +#endif + +#define GUF_CNT_T_OPS_CPY GUFCAT(GUFCAT(GUF_CNT_T, _ops), _cpy) + +typedef struct GUF_CNT_NAME { + GUF_CNT_T *data; ptrdiff_t size, capacity; - guf_obj_meta elem_meta; -} guf_dbuf; +} GUF_CNT_NAME; -bool guf_dbuf_init(guf_dbuf *dbuf, guf_obj_meta elem_meta, ptrdiff_t start_cap); -guf_dbuf guf_dbuf_new_with_capacity(guf_obj_meta elem_meta, ptrdiff_t start_cap); -guf_dbuf guf_dbuf_new(guf_obj_meta elem_meta); +static inline bool GUFCAT(GUF_CNT_NAME, _valid_and_not_empty)(const GUF_CNT_NAME* dbuf) +{ + return dbuf && dbuf->data && dbuf->capacity > 0 && dbuf->size > 0 && dbuf->size <= dbuf->capacity; +} -void guf_dbuf_free(guf_dbuf *dbuf); +static inline bool GUFCAT(GUF_CNT_NAME, _valid_and_maybe_empty)(const GUF_CNT_NAME* dbuf) +{ + GUF_ASSERT_RELEASE((!dbuf->data && !dbuf->capacity) || (dbuf->data && dbuf->capacity)); + return dbuf && dbuf->capacity >= 0 && dbuf->size >= 0 && dbuf->size <= dbuf->capacity; +} -bool guf_dbuf_reserve(guf_dbuf *dbuf, ptrdiff_t min_capacity); -bool guf_dbuf_shrink_to_fit(guf_dbuf *dbuf); +bool GUFCAT(GUF_CNT_NAME, _reserve)(GUF_CNT_NAME *dbuf, ptrdiff_t min_capacity) +{ + GUF_ASSERT_RELEASE(GUFCAT(GUF_CNT_NAME, _valid_and_maybe_empty)(dbuf)); + GUF_ASSERT_RELEASE(min_capacity >= 0); -void *guf_dbuf_push(guf_dbuf *dbuf, void *elem, guf_obj_cpy_opt cpy_opt); -void *guf_dbuf_insert(guf_dbuf *dbuf, void *elem, ptrdiff_t idx, guf_obj_cpy_opt cpy_opt); -void guf_dbuf_erase(guf_dbuf *dbuf, ptrdiff_t idx); -void *guf_dbuf_pop(guf_dbuf *dbuf); + if (min_capacity <= dbuf->capacity) { + return true; + } -void *guf_dbuf_at(guf_dbuf *dbuf, ptrdiff_t idx); -void *guf_dbuf_front(guf_dbuf *dbuf); -void *guf_dbuf_back(guf_dbuf *dbuf); + if (!dbuf->data) { + GUF_CNT_T *data = calloc(min_capacity, sizeof(GUF_CNT_T)); + GUF_ASSERT(data); + if (!data) { + return false; + } + dbuf->data = data; + } else { + GUF_CNT_T *data = realloc(dbuf->data, guf_safe_size_calc(min_capacity, sizeof(GUF_CNT_T))); + GUF_ASSERT(data); + if (!data) { + return false; + } + dbuf->data = data; + } + dbuf->capacity = min_capacity; + return true; +} -void guf_dbuf_sort(guf_dbuf *dbuf, void (*cmp)(const void *a, const void *b)); -void guf_dbuf_ascending(guf_dbuf *dbuf); -void guf_dbuf_descending(guf_dbuf *dbuf); +static inline bool GUFCAT(GUF_CNT_NAME, _init)(GUF_CNT_NAME *dbuf, ptrdiff_t start_cap) +{ + GUF_ASSERT_RELEASE(dbuf); + GUF_ASSERT_RELEASE(start_cap >= 0); -// Convenience macros: -#define GUF_DBUF_NEW(elem_type) guf_dbuf_new((guf_obj_meta){.has_ops = false, .data.sizeof_obj = sizeof(elem_type)}) -#define GUF_DBUF_NEW_WITH_CAP(elem_type, capacity) guf_dbuf_new_with_capacity((guf_obj_meta){.has_ops = false, .data.sizeof_obj = sizeof(elem_type)}, capacity) + dbuf->size = dbuf->capacity = 0; -// #define GUF_DBUF_NEW_FROM_OPS(obj_ops_ptr) guf_dbuf_new((guf_obj_meta){.has_ops = true, .data = obj_ops_ptr}) -// #define GUF_DBUF_NEW_FROM_OPS_WITH_CAP(obj_ops_ptr, capacity) guf_dbuf_new_with_capacity(-1, (obj_ops_ptr), (capacity)) + if (start_cap == 0) { + dbuf->data = NULL; + return true; + } -#define GUF_DBUF_PUSH_VAL(dbuf_ptr, elem_type, elem_val) do { \ - elem_type tmp_lvalue = elem_val; \ - void *res = guf_dbuf_push(dbuf_ptr, &tmp_lvalue, GUF_CPY_VALUE); \ - GUF_ASSERT_RELEASE(res); \ -} while (0); \ + bool success = GUFCAT(GUF_CNT_NAME, _reserve)(dbuf, start_cap); + if (success) { + dbuf->capacity = start_cap; + } + GUF_ASSERT(success); + return success; +} -#define GUF_DBUF_PUSH_VAL_CPY(dbuf_ptr, elem_type, elem_val) do { \ - elem_type tmp_lvalue = elem_val; \ - void *res = guf_dbuf_push(dbuf_ptr, &tmp_lvalue, GUF_CPY_DEEP); \ - GUF_ASSERT_RELEASE(res); \ -} while (0); \ +static inline GUF_CNT_NAME GUFCAT(GUF_CNT_NAME, _new_with_capacity)(ptrdiff_t start_cap) +{ + GUF_ASSERT_RELEASE(start_cap >= 0); + GUF_CNT_NAME dbuf = {0}; + bool success = GUFCAT(GUF_CNT_NAME, _init)(&dbuf, start_cap); + GUF_ASSERT_RELEASE(success); + return dbuf; +} -#define GUF_DBUF_TRY_PUSH_VAL(dbuf_ptr, elem_type, elem_val, success_bool_name) do { \ - elem_type tmp_lvalue = elem_val; \ - void *res = guf_dbuf_push(dbuf_ptr, &tmp_lvalue, GUF_CPY_VALUE); \ - success_bool_name = res != NULL; \ -} while (0); \ +GUF_CNT_NAME GUFCAT(GUF_CNT_NAME, _new)(void) +{ + GUF_CNT_NAME dbuf = {0}; + bool success = GUFCAT(GUF_CNT_NAME, _init)(&dbuf, 0); + GUF_ASSERT_RELEASE(success); + return dbuf; +} -#define GUF_DBUF_TRY_PUSH_VAL_CPY(dbuf_ptr, elem_type, elem_val, success_bool_name); do { \ - elem_type tmp_lvalue = elem_val; \ - void *res = guf_dbuf_push(dbuf_ptr, &tmp_lvalue, GUF_CPY_DEEP); \ - success_bool_name = res != NULL; \ -} while (0); \ +static inline ptrdiff_t GUFCAT(GUF_CNT_NAME, _next_capacity)(ptrdiff_t old_cap) +{ + GUF_ASSERT_RELEASE(old_cap >= 0); + size_t new_cap = 0; + if (old_cap == 0) { + new_cap = GUF_DBUF_INITIAL_CAP; + } else if (old_cap < 8) { + new_cap = (size_t)old_cap * 2ull; + } else { + new_cap = (size_t)old_cap * 3ull / 2ull; + } + GUF_ASSERT_RELEASE(new_cap > (size_t)old_cap); // Fail on overflow. + GUF_ASSERT_RELEASE(new_cap <= PTRDIFF_MAX); + return new_cap; +} -#define GUF_DBUF_AT_VAL(dbuf_ptr, elem_type, idx) *(elem_type*)guf_dbuf_at(dbuf_ptr, idx) -#define GUF_DBUF_POP_VAL(dbuf_ptr, elem_type) *(elem_type*)guf_dbuf_pop(dbuf_ptr) -#define GUF_DBUF_LAST_VAL(dbuf_ptr, elem_type) *(elem_type*)guf_dbuf_back(dbuf_ptr) -#define GUF_DBUF_FIRST_VAL(dbuf_ptr, elem_type) *(elem_type*)guf_dbuf_front(dbuf_ptr) +static inline bool GUFCAT(GUF_CNT_NAME, _grow_if_full)(GUF_CNT_NAME *dbuf) +{ + GUF_ASSERT_RELEASE(dbuf->capacity >= 0 && dbuf->size >= 0); + if (dbuf->size == dbuf->capacity) { + bool success = GUFCAT(GUF_CNT_NAME, _reserve)(dbuf, GUFCAT(GUF_CNT_NAME, _next_capacity)(dbuf->capacity)); + if (!success) { + return false; + } + } + GUF_ASSERT_RELEASE(dbuf->size < dbuf->capacity); + return true; +} -#define GUF_DBUF_FOREACH(DBUF, ELEM_TYPE, ELEM_PTR_NAME) for (ELEM_TYPE *ELEM_PTR_NAME = (ELEM_TYPE*)(DBUF).data, *end = ((ELEM_TYPE*)(DBUF).data) + (DBUF).size; ELEM_PTR_NAME != end; ++ELEM_PTR_NAME) +GUF_CNT_T *GUFCAT(GUF_CNT_NAME, _push)(GUF_CNT_NAME *dbuf, GUF_CNT_T *elem, guf_obj_cpy_opt cpy_opt) +{ + GUF_ASSERT_RELEASE(GUFCAT(GUF_CNT_NAME,_valid_and_maybe_empty)(dbuf)); + GUF_ASSERT_RELEASE(!(cpy_opt == GUF_CPY_VALUE && GUF_CNT_T_OPS.free)); // Don't allow copy by value if there's a free operation. + + bool success = GUFCAT(GUF_CNT_NAME, _grow_if_full)(dbuf); + GUF_ASSERT(success); + if (!success) { + return NULL; + } -#endif \ No newline at end of file + GUF_CNT_T *dst = dbuf->data + dbuf->size++; + return GUF_CNT_T_OPS_CPY(dst, elem, &GUF_CNT_T_OPS, cpy_opt); +} + +GUF_CNT_T *GUFCAT(GUF_CNT_NAME, _push_val)(GUF_CNT_NAME *dbuf, GUF_CNT_T elem) +{ + GUF_ASSERT_RELEASE(!GUF_CNT_T_OPS.free); // Don't allow copy by value if there's a free operation. + return GUFCAT(GUF_CNT_NAME, _push)(dbuf, &elem, GUF_CPY_VALUE); +} + +GUF_CNT_T *GUFCAT(GUF_CNT_NAME, _push_val_cpy)(GUF_CNT_NAME *dbuf, GUF_CNT_T elem) +{ + return GUFCAT(GUF_CNT_NAME, _push)(dbuf, &elem, GUF_CPY_DEEP); +} + +GUF_CNT_T *GUFCAT(GUF_CNT_NAME, _insert)(GUF_CNT_NAME *dbuf, GUF_CNT_T *elem, ptrdiff_t idx, guf_obj_cpy_opt cpy_opt) +{ + GUF_ASSERT_RELEASE(GUFCAT(GUF_CNT_NAME,_valid_and_maybe_empty)(dbuf)); + GUF_ASSERT_RELEASE(idx >= 0 && idx <= dbuf->size); + GUF_ASSERT_RELEASE(!(cpy_opt == GUF_CPY_VALUE && GUF_CNT_T_OPS.free)); // Don't allow copy by value if there's a free operation. + + if (idx == dbuf->size) { + return GUFCAT(GUF_CNT_NAME, _push)(dbuf, elem, cpy_opt); + } + + GUF_ASSERT_RELEASE(idx < dbuf->size); + + bool success = GUFCAT(GUF_CNT_NAME, _grow_if_full)(dbuf); + GUF_ASSERT(success); + if (!success) { + return NULL; + } + + for (ptrdiff_t free_idx = dbuf->size++; free_idx > idx; --free_idx) { + GUF_CNT_T *dst = dbuf->data + free_idx; + GUF_CNT_T *src = dst - 1; + GUF_CNT_T_OPS_CPY(dst, src, &GUF_CNT_T_OPS, GUF_CPY_VALUE); + } + return GUF_CNT_T_OPS_CPY(dbuf->data + idx, elem, &GUF_CNT_T_OPS, cpy_opt); +} + +void GUFCAT(GUF_CNT_NAME, _erase)(GUF_CNT_NAME *dbuf, ptrdiff_t idx) +{ + GUF_ASSERT_RELEASE(GUFCAT(GUF_CNT_NAME, _valid_and_not_empty)(dbuf)); + GUF_ASSERT_RELEASE(idx >= 0); + GUF_ASSERT_RELEASE(idx < dbuf->size); + + if (GUF_CNT_T_OPS.free) { + GUF_CNT_T_OPS.free(dbuf->data + idx); + } + + for (ptrdiff_t free_idx = idx; free_idx < dbuf->size - 1; ++free_idx) { + GUF_CNT_T *dst = dbuf->data + free_idx; + GUF_CNT_T *src = dst + 1; + GUF_CNT_T_OPS_CPY(dst, src, &GUF_CNT_T_OPS, GUF_CPY_VALUE); + } +} + +void GUFCAT(GUF_CNT_NAME, pop)(GUF_CNT_NAME *dbuf) +{ + GUF_ASSERT_RELEASE(GUFCAT(GUF_CNT_NAME, _valid_and_not_empty)(dbuf)); + GUF_CNT_T *popped = dbuf->data + --dbuf->size; + if (GUF_CNT_T_OPS.free) { + GUF_CNT_T_OPS.free(popped); + } +} + +GUF_CNT_T GUFCAT(GUF_CNT_NAME, pop_cpy)(GUF_CNT_NAME *dbuf, guf_obj_cpy_opt cpy_opt) +{ + GUF_ASSERT_RELEASE(GUFCAT(GUF_CNT_NAME, _valid_and_not_empty)(dbuf)); + GUF_CNT_T *popped = dbuf->data + --dbuf->size; + GUF_CNT_T popped_val; + GUF_CNT_T *success = GUF_CNT_T_OPS_CPY(&popped_val, popped, &GUF_CNT_T_OPS, cpy_opt); + GUF_ASSERT_RELEASE(success); + + if (cpy_opt == GUF_CPY_DEEP && GUF_CNT_T_OPS.free) { + GUF_CNT_T_OPS.free(popped); + } + return popped_val; +} + +GUF_CNT_T *GUFCAT(GUF_CNT_NAME, _at)(GUF_CNT_NAME *dbuf, ptrdiff_t idx) +{ + GUF_ASSERT_RELEASE(GUFCAT(GUF_CNT_NAME, _valid_and_not_empty)(dbuf)); + GUF_ASSERT_RELEASE(idx >= 0 && idx < dbuf->size) + return dbuf->data + idx; +} + +GUF_CNT_T *GUFCAT(GUF_CNT_NAME, _front)(GUF_CNT_NAME *dbuf) +{ + GUF_ASSERT_RELEASE(GUFCAT(GUF_CNT_NAME, _valid_and_not_empty)(dbuf)); + return dbuf->data + 0; +} +GUF_CNT_T *GUFCAT(GUF_CNT_NAME, back)(GUF_CNT_NAME *dbuf) +{ + GUF_ASSERT_RELEASE(GUFCAT(GUF_CNT_NAME, _valid_and_not_empty)(dbuf)); + return dbuf->data + (dbuf->size - 1); + +} + +bool GUFCAT(GUF_CNT_NAME, _shrink_to_fit)(GUF_CNT_NAME *dbuf) +{ + GUF_ASSERT_RELEASE(GUFCAT(GUF_CNT_NAME, _valid_and_maybe_empty)(dbuf)); + const ptrdiff_t new_capacity = dbuf->size; + if (new_capacity == dbuf->capacity) { + return true; + } + GUF_ASSERT_RELEASE(new_capacity < dbuf->capacity); + GUF_ASSERT_RELEASE(dbuf->data); + + GUF_CNT_T *data = realloc(dbuf->data, guf_safe_size_calc(new_capacity, sizeof(GUF_CNT_T))); + GUF_ASSERT(data); + if (!data) { + return false; + } + dbuf->data = data; + dbuf->capacity = new_capacity; + return true; +} + +void GUFCAT(GUF_CNT_NAME, _free)(GUF_CNT_NAME *dbuf) +{ + GUF_ASSERT_RELEASE(GUFCAT(GUF_CNT_NAME, _valid_and_maybe_empty)(dbuf)); + if (dbuf->capacity == 0) { + GUF_ASSERT_RELEASE(!dbuf->data); + GUF_ASSERT_RELEASE(dbuf->size == 0); + return; + } + GUF_ASSERT_RELEASE(dbuf->data); + if (GUF_CNT_T_OPS.free) { + for (ptrdiff_t idx = 0; idx < dbuf->size; ++idx) { + GUF_CNT_T_OPS.free(dbuf->data + idx); + } + } + free(dbuf->data); + dbuf->data = NULL; + dbuf->capacity = dbuf->size = 0; +} + +// void guf_dbuf_sort(guf_dbuf *dbuf, void (*cmp)(const void *a, const void *b)); +// void guf_dbuf_ascending(guf_dbuf *dbuf); +// void guf_dbuf_descending(guf_dbuf *dbuf); + +typedef struct GUFCAT(GUF_CNT_NAME, _iter) { + GUF_CNT_T *cur, *end, *begin; + struct GUFCAT(GUF_CNT_NAME, _iter) (*next)(const struct GUFCAT(GUF_CNT_NAME, _iter) *it, ptrdiff_t step); +} GUFCAT(GUF_CNT_NAME, _iter); + +static inline GUFCAT(GUF_CNT_NAME, _iter) GUFCAT(GUF_CNT_NAME, _iter_next)(const GUFCAT(GUF_CNT_NAME, _iter) *it, ptrdiff_t step) +{ + GUF_ASSERT_RELEASE(it); + if (it->begin == NULL && it->end == NULL) { + return *it; + } + GUF_ASSERT_RELEASE(it->begin != NULL && it->end != NULL); + GUF_ASSERT_RELEASE(it->cur < it->end); + + GUFCAT(GUF_CNT_NAME, _iter) next_it = *it; + intptr_t next_ptr = (intptr_t)it->cur + step * sizeof(GUF_CNT_T); + + if (next_ptr >= (intptr_t)it->end) { + next_it.cur = it->end; + } else if (next_ptr < (intptr_t)it->begin) { // TODO: different end for begin + next_it.cur = it->end; + } else { + GUF_ASSERT_RELEASE(next_ptr >= (intptr_t)it->begin); + GUF_ASSERT_RELEASE(next_ptr <= (intptr_t)it->end); + GUF_ASSERT_RELEASE(it->cur + step >= it->begin && it->cur + step <= it->end); + next_it.cur = it->cur + step; + } + return next_it; +} + +static inline GUFCAT(GUF_CNT_NAME, _iter) GUFCAT(GUF_CNT_NAME, _begin)(const GUF_CNT_NAME* dbuf) +{ + GUFCAT(GUF_CNT_NAME, _valid_and_maybe_empty)(dbuf); + return (GUFCAT(GUF_CNT_NAME, _iter)) { + .cur = dbuf->data, + .begin = dbuf->data, + .end = dbuf->data ? dbuf->data + dbuf->size : NULL, + .next = GUFCAT(GUF_CNT_NAME, _iter_next) + }; +} + +static inline GUFCAT(GUF_CNT_NAME, _iter) GUFCAT(GUF_CNT_NAME, _end)(const GUF_CNT_NAME* dbuf) +{ + GUFCAT(GUF_CNT_NAME, _valid_and_maybe_empty)(dbuf); + return (GUFCAT(GUF_CNT_NAME, _iter)) { + .cur = dbuf->data ? dbuf->data + dbuf->size : NULL, + .begin = dbuf->data, + .end = dbuf->data ? dbuf->data + dbuf->size : NULL, + .next = GUFCAT(GUF_CNT_NAME, _iter_next) + }; +} + +#undef GUF_DBUF_INITIAL_CAP +#undef GUF_CNT_T +#undef GUF_CNT_T_OPS +#undef GUF_CNT_T_OPS_CPY +#undef GUF_CNT_NAME \ No newline at end of file diff --git a/src/guf_dict.h b/src/guf_dict.h index 7c6ac47..4e9f50e 100755 --- a/src/guf_dict.h +++ b/src/guf_dict.h @@ -12,24 +12,24 @@ typedef enum guf_dict_probe_type {GUF_DICT_PROBE_LINEAR = 0, GUF_DICT_PROBE_QUAD #define GUF_DICT_MAX_LOAD_FAC_FX10_DEFAULT 666ul #define GUF_DICT_PROBE_TYPE_DEFAULT GUF_DICT_PROBE_QUADRATIC -#define GUF_HASH32_INIT 2166136261ul -#define GUF_HASH64_INIT 14695981039346656037ull -uint32_t guf_hash32(const void *data, size_t num_bytes, uint32_t hash); -uint64_t guf_hash64(const void *data, size_t num_bytes, uint64_t hash); +// #define GUF_HASH32_INIT 2166136261ul +// #define GUF_HASH64_INIT 14695981039346656037ull +// uint32_t guf_hash32(const void *data, size_t num_bytes, uint32_t hash); +// uint64_t guf_hash64(const void *data, size_t num_bytes, uint64_t hash); -#ifdef GUF_DICT_USE_32_BIT_HASH - #define GUF_HASH_INIT GUF_HASH32_INIT - static inline uint32_t guf_hash(const void *data, size_t num_bytes, uint32_t hash) { - return guf_hash32(data, num_bytes, hash); - } - #define GUF_DICT_HASH_MAX UINT32_MAX -#else - #define GUF_HASH_INIT GUF_HASH64_INIT - static inline uint64_t guf_hash(const void *data, size_t num_bytes, uint64_t hash) { - return guf_hash64(data, num_bytes, hash); - } - #define GUF_DICT_HASH_MAX UINT64_MAX -#endif +// #ifdef GUF_USE_32_BIT_HASH +// #define GUF_HASH_INIT GUF_HASH32_INIT +// static inline uint32_t guf_hash(const void *data, size_t num_bytes, uint32_t hash) { +// return guf_hash32(data, num_bytes, hash); +// } +// #define GUF_DICT_HASH_MAX UINT32_MAX +// #else +// #define GUF_HASH_INIT GUF_HASH64_INIT +// static inline uint64_t guf_hash(const void *data, size_t num_bytes, uint64_t hash) { +// return guf_hash64(data, num_bytes, hash); +// } +// #define GUF_DICT_HASH_MAX UINT64_MAX +// #endif typedef struct guf_dict_kv_funcs { // Only used for keys: diff --git a/src/guf_hash.h b/src/guf_hash.h new file mode 100644 index 0000000..3929e81 --- /dev/null +++ b/src/guf_hash.h @@ -0,0 +1,59 @@ +#ifndef GUF_HASH_H +#define GUF_HASH_H +#include "guf_common.h" + +// #define GUF_USE_32_BIT_HASH /* Define GUF_USE_32_BIT_HASH to make guflib use 32 bit hashes */ + +/* + FNV-1a (32-bit and 64-bit) hash functions. + Generally, you should always call csr_hash with GUF_HASH_INIT as the hash argument, unless you want to create "chains" of hashes. + cf. http://www.isthe.com/chongo/tech/comp/fnv/ (last retrieved: 2023-11-30) +*/ + +#define GUF_HASH32_INIT 2166136261ul +#define GUF_HASH64_INIT 14695981039346656037ull + +static inline uint32_t guf_hash32(const void *data, ptrdiff_t num_bytes, uint32_t hash) +{ + GUF_ASSERT_RELEASE(data); + GUF_ASSERT_RELEASE(num_bytes > 0); + const unsigned char *data_bytes = (const unsigned char*)data; // This does not break strict-aliasing rules I think... + const uint32_t FNV_32_PRIME = 16777619ul; + for (size_t i = 0; i < (size_t)num_bytes; ++i) { + hash ^= data_bytes[i]; + hash *= FNV_32_PRIME; + } + return hash; +} + +static inline uint64_t guf_hash64(const void *data, ptrdiff_t num_bytes, uint64_t hash) +{ + GUF_ASSERT_RELEASE(data); + GUF_ASSERT_RELEASE(num_bytes > 0); + const unsigned char *data_bytes = (const unsigned char*)data; // This does not break strict-aliasing rules I think... + const uint64_t FNV_64_PRIME = 1099511628211ull; + for (size_t i = 0; i < (size_t)num_bytes; ++i) { + hash ^= data_bytes[i]; + hash *= FNV_64_PRIME; + } + return hash; +} + +#ifdef GUF_USE_32_BIT_HASH + typedef uint32_t guf_hash_size_t; + #define GUF_HASH_INIT GUF_HASH32_INIT + + static inline guf_hash_size_t guf_hash(const void *data, ptrdiff_t num_bytes, uint32_t hash) { + return guf_hash32(data, num_bytes, hash); + } + #define GUF_HASH_MAX UINT32_MAX +#else + typedef uint64_t guf_hash_size_t; + #define GUF_HASH_INIT GUF_HASH64_INIT + static inline guf_hash_size_t guf_hash(const void *data, ptrdiff_t num_bytes, uint64_t hash) { + return guf_hash64(data, num_bytes, hash); + } + #define GUF_HASH_MAX UINT64_MAX +#endif + +#endif \ No newline at end of file diff --git a/src/guf_obj.c b/src/guf_obj.c deleted file mode 100644 index 50c1afb..0000000 --- a/src/guf_obj.c +++ /dev/null @@ -1,74 +0,0 @@ -#include "guf_obj.h" - -static int cstr_ptr_cmp(const void *a, const void *b){ - GUF_ASSERT_RELEASE(a && b); - // typeof dst/src: pointer to const char* (const char**) - const char **a_ptr = (const char**)a; - const char **b_ptr = (const char**)b; - return strcmp(*a_ptr, *b_ptr); -} - -static GUF_OBJ_DEFINE_CMP_DESC(cstr_ptr_cmp, cstr_ptr_cmp_desc) - -static bool cstr_ptr_eq(const void *a, const void *b) { - GUF_ASSERT_RELEASE(a && b); - return 0 == cstr_ptr_cmp(a, b); -} - -static void *cstr_default_init(void *dst) -{ - GUF_ASSERT_RELEASE(dst); - char **dst_ptr = (char**)dst; - *dst_ptr = NULL; - return dst; -} - -static void *cstr_cpy_init(void *dst, const void *src) -{ - GUF_ASSERT_RELEASE(dst && src); - char **dst_ptr = (char**)dst; - const char **src_ptr = (const char**)src; - char *cpy = strdup(*src_ptr); - GUF_ASSERT_RELEASE(cpy); - *dst_ptr = cpy; - return dst; -} - -void *cstr_move_init(void *dst, void *src) -{ - GUF_ASSERT_RELEASE(dst && src); - char **dst_ptr = (char**)dst; - char **src_ptr = (char**)src; - *dst_ptr = *src_ptr; - *src_ptr = NULL; - return dst; -} - -void cstr_ptr_free(void *ptr) -{ - GUF_ASSERT_RELEASE(ptr); - char **cstr_ptr = (char**)ptr; - free(*cstr_ptr); -} - -static const guf_obj_ops guf_cstr_ops = { - .sizeof_obj = sizeof(guf_cstr_type), - .cmp = cstr_ptr_cmp, - .cmp_desc = cstr_ptr_cmp_desc, - .eq = cstr_ptr_eq , - .default_init = cstr_default_init, - .copy_init = cstr_cpy_init, - .move_init = cstr_move_init, - .free = cstr_ptr_free, - .hash = NULL, -}; - -const guf_obj_meta guf_cstr_obj_meta = { - .has_ops = true, - .data.ops = &guf_cstr_ops -}; - -const guf_obj_meta guf_const_cstr_obj_meta = { - .has_ops = false, - .data.sizeof_obj = sizeof(guf_const_cstr_type) -}; \ No newline at end of file diff --git a/src/guf_obj.h b/src/guf_obj.h index 9c92b4d..fd08975 100644 --- a/src/guf_obj.h +++ b/src/guf_obj.h @@ -1,127 +1,48 @@ -#ifndef GUF_OBJ_H -#define GUF_OBJ_H #include #include "guf_common.h" -typedef enum guf_obj_cpy_opt { - GUF_CPY_VALUE = 0, - GUF_CPY_DEEP = 1, - GUF_CPY_MOVE = 2, -} guf_obj_cpy_opt; +#ifndef GUF_OBJ_H +#define GUF_OBJ_H + #define GUF_OBJ_OPS_DEFINE_CMP_INVERSE(obj_type, cmp_fn, cmp_inverted_name) int cmp_inverted_name(const obj_type *a, const obj_type *b) {return -cmp_fn(a, b);} + #define GUF_OBJ_OPS_VALUE_TYPE(obj_ops_type, eq, cmp, cmp_inv) (obj_ops_type){.copy_init = NULL, .move_init = NULL, .free = NULL, .eq = eq, .cmp = cmp, .cmp_inv = cmp_inv} + #define GUF_OBJ_OPS_EMPTY(obj_ops_type) (obj_ops_type){.copy_init = NULL, .move_init = NULL, .free = NULL, .eq = NULL, .cmp = NULL, .cmp_inv = NULL} +#endif -typedef struct guf_obj_ops { - ptrdiff_t sizeof_obj; - void *(*default_init)(void *dst_obj); // Default constructor. - void *(*copy_init)(void *dst_obj, const void *src_obj); // Copy constructor (deep copies src). - void *(*move_init)(void *dst_obj, void *src_obj); // Move constructor ("steals" from src). - void (*free)(void *obj); - bool (*eq)(const void *obj_a, const void *obj_b); - int (*cmp)(const void *obj_a, const void *obj_b); - int (*cmp_desc)(const void *obj_a, const void *obj_b); // Define with GUF_OBJ_DEFINE_CMP_DESC - guf_hash_size_t (*hash)(const void *obj); - const char *type_str; -} guf_obj_ops; +#ifndef GUF_OBJ_TYPE + #error "GUF_OBJ_TYPE not set" +#endif -#define GUF_OBJ_DEFINE_CMP_DESC(CMP_FN, CMP_DESC_FN_NAME) int CMP_DESC_FN_NAME(const void *a, const void *b) {return -CMP_FN(a, b);} +#ifndef GUF_OBJ_OPS_TYPENAME + #define GUF_OBJ_OPS_TYPENAME GUFCAT(GUF_OBJ_TYPE, _ops) +#endif -typedef struct guf_obj_meta { - bool has_ops; - union { - const guf_obj_ops *ops; - ptrdiff_t sizeof_obj; - } data; -} guf_obj_meta; +typedef struct GUF_OBJ_OPS_TYPENAME { + GUF_OBJ_TYPE *(*copy_init)(GUF_OBJ_TYPE *dst, const GUF_OBJ_TYPE *src); + GUF_OBJ_TYPE *(*move_init)(GUF_OBJ_TYPE *dst, GUF_OBJ_TYPE *src); + void (*free)(GUF_OBJ_TYPE *obj); + bool (*eq)(const GUF_OBJ_TYPE *a, const GUF_OBJ_TYPE *b); + int (*cmp)(const GUF_OBJ_TYPE *a, const GUF_OBJ_TYPE *b); + int (*cmp_inv)(const GUF_OBJ_TYPE *a, const GUF_OBJ_TYPE *b); // Define with GUF_OBJ_OPS_DEFINE_CMP_REVERSE. +} GUF_OBJ_OPS_TYPENAME; -static inline ptrdiff_t guf_obj_meta_sizeof_obj(guf_obj_meta meta) +static inline GUF_OBJ_TYPE *GUFCAT(GUF_OBJ_OPS_TYPENAME, _cpy) (GUF_OBJ_TYPE *dst, GUF_OBJ_TYPE *src, const GUF_OBJ_OPS_TYPENAME *ops, guf_obj_cpy_opt cpy_opt) { - ptrdiff_t size = meta.has_ops ? meta.data.ops->sizeof_obj : meta.data.sizeof_obj; - GUF_ASSERT_RELEASE(size > 0); - return size; -} - -static inline bool guf_obj_meta_same(guf_obj_meta a, guf_obj_meta b) { - if (a.has_ops != b.has_ops) { - return false; - } - if (a.has_ops) { - return a.data.ops == b.data.ops; - } else { - return a.data.sizeof_obj == b.data.sizeof_obj; + GUF_ASSERT_RELEASE(dst); + GUF_ASSERT_RELEASE(src); + GUF_ASSERT_RELEASE(ops); + if (cpy_opt == GUF_CPY_VALUE) { + dst = memcpy(dst, src, sizeof(GUF_OBJ_TYPE)); + GUF_ASSERT_RELEASE(dst); // Should never fail. + } else if (cpy_opt == GUF_CPY_DEEP) { + GUF_ASSERT_RELEASE(ops->copy_init); + dst = ops->copy_init(dst, src); + } else if (cpy_opt == GUF_CPY_MOVE) { + GUF_ASSERT_RELEASE(ops->move_init); + dst = ops->move_init(dst, src); } + GUF_ASSERT(dst); + return dst; } -static inline void *guf_cpy(void *dst_ptr, void *src_ptr, guf_obj_meta obj_meta, guf_obj_cpy_opt cpy_opt) -{ - GUF_ASSERT_RELEASE(dst_ptr); - GUF_ASSERT_RELEASE(src_ptr); - - if (obj_meta.has_ops) { - GUF_ASSERT_RELEASE(obj_meta.data.ops != NULL); - } - - const ptrdiff_t sizeof_obj = obj_meta.has_ops ? obj_meta.data.ops->sizeof_obj : obj_meta.data.sizeof_obj; - const guf_obj_ops *ops = obj_meta.has_ops ? obj_meta.data.ops : NULL; - GUF_ASSERT_RELEASE(sizeof_obj > 0); - - switch (cpy_opt) { - case GUF_CPY_VALUE: - dst_ptr = memcpy(dst_ptr, src_ptr, sizeof_obj); - GUF_ASSERT_RELEASE(dst_ptr); // This should never fail. - break; - case GUF_CPY_DEEP: - GUF_ASSERT_RELEASE(ops->copy_init != NULL); - dst_ptr = ops->copy_init(dst_ptr, src_ptr); - break; - case GUF_CPY_MOVE: - GUF_ASSERT_RELEASE(ops->move_init != NULL); - dst_ptr = ops->move_init(dst_ptr, src_ptr); - break; - default: - GUF_ASSERT_RELEASE(false); - } - GUF_ASSERT(dst_ptr); - return dst_ptr; -} - -static inline guf_obj_meta guf_obj_get_meta(void *obj) -{ - guf_obj_meta *meta_ptr = (guf_obj_meta*)obj; // IMPORTANT: Assumes the obj's first member is of type guf_obj_meta, otherwise this is undefined behaviour. - GUF_ASSERT_RELEASE(meta_ptr); - return *meta_ptr; -} - -static inline void *guf_obj_copy(void *dst_obj, void *src_obj, guf_obj_cpy_opt cpy_opts) -{ - guf_obj_meta meta = guf_obj_get_meta(dst_obj); - guf_obj_meta meta_src = guf_obj_get_meta(src_obj); - GUF_ASSERT_RELEASE(guf_obj_meta_same(meta, meta_src)); - return guf_cpy(dst_obj, src_obj, meta, cpy_opts); -} - -#define GUF_OBJ_META_NAME guf_obj_meta_member - -#define GUF_OBJ_DECLARE_OBJ_META() guf_obj_meta GUF_OBJ_META_NAME; -#define GUF_OBJ_GET_META_TYPESAFE(PTR) (PTR)->GUF_OBJ_META_NAME - -#define GUF_OBJ_FREE_TYPESAFE(ptr) if (GUF_OBJ_GET_META_TYPESAFE(ptr).has_ops && GUF_OBJ_GET_META_TYPESAFE(ptr).data.ops->free) {GUF_OBJ_GET_META_TYPESAFE(ptr).data.ops->free(ptr);} -#define GUF_OBJ_FREE(PTR) if (guf_obj_get_meta(PTR).has_ops && guf_obj_get_meta(PTR).data.ops->free) { guf_obj_get_meta(PTR).data.ops->free(PTR); } - -#define GUF_OBJ_LIFETIME_BLOCK_TYPESAFE(ptr, code_block) \ -do { \ - code_block \ - GUF_OBJ_FREE_TYPESAFE((ptr)); \ -} while (0); - -#define GUF_OBJ_LIFETIME_BLOCK(ptr, code_block) \ -do { \ - code_block \ - GUF_OBJ_FREE((ptr)); \ -} while (0); \ - - -typedef const char* guf_const_cstr_type; -typedef char* guf_cstr_type; -extern const guf_obj_meta guf_cstr_obj_meta; -extern const guf_obj_meta guf_const_cstr_obj_meta; - -#endif \ No newline at end of file +#undef GUF_OBJ_TYPE +#undef GUF_OBJ_OPS_TYPENAME \ No newline at end of file diff --git a/src/guf_str.h b/src/guf_str.h index b1e230e..c7659ed 100644 --- a/src/guf_str.h +++ b/src/guf_str.h @@ -5,7 +5,7 @@ #include #include "guf_common.h" -#include "guf_obj.h" +// #include "guf_obj.h" #define GUF_STR_ABORT_ON_ALLOC_FAILURE 1 diff --git a/src/guf_test.c b/src/guf_test.c index be36a58..e836e56 100644 --- a/src/guf_test.c +++ b/src/guf_test.c @@ -1,9 +1,22 @@ #include #include #include +#include "guf_cstr.h" +#define GUF_DBUF_INITIAL_CAP 128 +#define GUF_CNT_NAME dbuf_int +#define GUF_CNT_T int +#include "guf_dbuf.h" + +#define GUF_CNT_NAME dbuf_const_cstr +#define GUF_CNT_T guf_const_cstr +#define GUF_CNT_T_OPS guf_const_cstr_operations +#include "guf_dbuf.h" + +#define GUF_CNT_NAME dbuf_heap_cstr +#define GUF_CNT_T guf_heap_cstr +#define GUF_CNT_T_OPS guf_heap_cstr_operations #include "guf_dbuf.h" -#include "guf_str.h" typedef struct guf_test { const char *name, *expected_output; @@ -13,81 +26,66 @@ typedef struct guf_test { bool passed; } guf_test; -static void guf_dbuf_test(guf_test *test) -{ - guf_dbuf ints = GUF_DBUF_NEW(int); - for (int i = 0; i < 2048; ++i) { - GUF_DBUF_PUSH_VAL(&ints, int, i); - } - - int last_int = GUF_DBUF_LAST_VAL(&ints, int); - int first_int = GUF_DBUF_FIRST_VAL(&ints, int); - int nth = GUF_DBUF_AT_VAL(&ints, int, 14); - - printf("First: %d, Last: %d, 14th: %d\n", first_int, last_int, nth); - - guf_dbuf strings = GUF_DBUF_NEW(guf_const_cstr_type); - GUF_DBUF_PUSH_VAL(&strings, guf_const_cstr_type, "First elem"); - GUF_DBUF_PUSH_VAL(&strings, guf_const_cstr_type, "Second elem"); - GUF_DBUF_PUSH_VAL(&strings, guf_const_cstr_type, "Third elem"); - - int i = 0; - GUF_DBUF_FOREACH(strings, guf_const_cstr_type, elem) { - printf("elem %d: %s\n", i++, *elem); - } - - guf_dbuf mut_strings = guf_dbuf_new(guf_cstr_obj_meta); - char foo[] = "Hello, world!"; - char bar[] = "Hej, verden!"; - char *baz = calloc(64, sizeof(char)); - strcpy(baz, "Farvel, I forbandede hundehoveder!"); - - GUF_DBUF_PUSH_VAL_CPY(&mut_strings, guf_cstr_type, &foo[0]); - GUF_DBUF_PUSH_VAL_CPY(&mut_strings, guf_cstr_type, &bar[0]); - - guf_dbuf_push(&mut_strings, &baz, GUF_CPY_MOVE); - GUF_ASSERT_RELEASE(baz == NULL); - - // char *popped = GUF_DBUF_POP_VAL(&mut_strings, cstr_type); - // printf("popped: %s\n", popped); - // free(popped); - - printf("First str_mut: %s, second: %s, last: %s\n", GUF_DBUF_FIRST_VAL(&mut_strings, guf_cstr_type), GUF_DBUF_AT_VAL(&mut_strings, guf_cstr_type, 1), GUF_DBUF_LAST_VAL(&mut_strings, guf_cstr_type)); - - guf_dbuf_free(&mut_strings); -} - int main(void) { - bool success = true; - guf_dbuf_test(NULL); - // guf_test_arr_register(); + dbuf_int integers = dbuf_int_new(); + dbuf_int_push_val(&integers, 420); + printf("initial cap %td\n", integers.capacity); + dbuf_int_push_val(&integers, 520); + dbuf_int_push_val(&integers, 620); + dbuf_int_push_val(&integers, 720); - // bool alloc_init = guf_alloc_init(); - // GUF_ASSERT_RELEASE(alloc_init); + int i = 0; + GUF_DBUF_FOREACH(integers, int, elem) { + printf("elem %d: %d\n", i, *elem); + ++i; + } - // void *ptr = guf_malloc(sizeof(int) * 42, "int alloc"); + GUF_FOREACH(&integers, dbuf_int, it) { + printf("it-elem: %d", *it.cur); + if (it.next(&it, 1).cur != it.end) { + printf(", it-next: %d", *it.next(&it, 1).cur); + } + if (it.next(&it, -1).cur != it.end) { + printf(", it-prev: %d", *it.next(&it, -1).cur); + } + printf("\n"); + } - // void *ptr2 = guf_malloc(sizeof(int) * 4, "int alloc 2 "); + for (dbuf_int_iter it = dbuf_int_begin(&integers); it.cur != it.end; it = it.next(&it, 2)) { + printf("every other: %d\n", *it.cur); + } - // void *ptr3 = guf_malloc(sizeof(int) * 4, "int alloc 3aaaaaaaaaafsjfjsdkfjksldjflssdfsdfjjjsdflkdjflsd"); + dbuf_const_cstr strings = dbuf_const_cstr_new(); + dbuf_const_cstr_push_val(&strings, "First"); + printf("initial cap %td\n", strings.capacity); - // guf_free(ptr, "int alloc"); - // guf_free(ptr3, "int alloc 3"); - // guf_free(ptr2, "int alloc 2"); + dbuf_const_cstr_push_val(&strings, "Second"); + guf_const_cstr foo = "Hello, World!"; + dbuf_const_cstr_push(&strings, &foo, GUF_CPY_VALUE); - // guf_alloc_print(); + GUF_FOREACH(&strings, dbuf_const_cstr, it) { + printf("str: %s\n", *it.cur); + } - // GUF_ARR_FOREACH(test_arr, guf_test, test) { - // test->test_fn(test); - // if (guf_str_equals(&test->expected_output, &test->output)) { - // printf("Test %s passed!\n", guf_str_get_const_c_str(&test->name)); - // } else { - // printf("Test %s failed!\n", guf_str_get_const_c_str(&test->name)); - // } - // } + dbuf_heap_cstr mut_strings = dbuf_heap_cstr_new(); + dbuf_heap_cstr_push_val_cpy(&mut_strings, "First mut!"); + dbuf_heap_cstr_push_val_cpy(&mut_strings, "Second mut!"); + + char *move_me_pls = calloc(128, sizeof(char)); + strcpy(move_me_pls, "Third mut"); + dbuf_heap_cstr_push(&mut_strings, &move_me_pls, GUF_CPY_MOVE); + GUF_ASSERT_RELEASE(move_me_pls == NULL); + + GUF_FOREACH(&mut_strings, dbuf_heap_cstr, it) { + printf("str: %s\n", *it.cur); + } + + dbuf_heap_cstr_free(&mut_strings); + dbuf_const_cstr_free(&strings); + dbuf_int_free(&integers); return success ? EXIT_SUCCESS : EXIT_FAILURE; } \ No newline at end of file