diff --git a/cig.h b/cig.h index cf801f4..3ae9417 100644 --- a/cig.h +++ b/cig.h @@ -6,6 +6,7 @@ #include #include #include +#include typedef union any_align { char c; int i; long l; long long ll; float f; double d; void *p; long double ld; } any_align_t; #define MAX_ALIGN ((size_t) sizeof(any_align_t)) @@ -106,9 +107,13 @@ allocator_t allocator_from_arena(arena_allocator_t *this); // dynamic arrays ////////////////////////////////////////////////////////////// typedef struct dyn_array_header { - size_t size, capacity, itemsize; + size_t n_items, capacity, itemsize; allocator_t allocator; - uint8_t bytes[]; + union { + // allocates a little more memory than needed, but who cares? + uint8_t bytes[1]; + any_align_t _[1]; + }; } dyn_array_header_t; typedef struct dyn_array_create_func_args { @@ -142,7 +147,7 @@ void dyn_array_shrink_func(void *this, size_t n_items_to_remove, const char *fil #define arr_reset(THIS)\ do {\ dyn_array_header_t *header = PTR_FROM_FIELD_PTR(dyn_array_header_t, bytes, THIS);\ - header->size = 0;\ + header->n_items = 0;\ } while (0) size_t arr_len(void *this); @@ -156,6 +161,28 @@ size_t arr_cap(void *this); #define arr_pop(THIS) (arr_shrink(THIS, 1), THIS[arr_len(THIS)]) + +/* Compile-time assert that works in expression contexts */ +#define STATIC_ASSERT(expr) ((void)sizeof(char[(expr) ? 1 : -1])) + + +bool dyn_array_contains_func(void *this, uint8_t *value); + +/* + arr_contains(THIS, TYPE, VALUE) + + - SIZE CHECK: compile-time check that sizeof(*THIS) == sizeof(TYPE) + - TYPE is the type of the value to search for + - VALUE is stored in a compound literal of TYPE + - Pure C99, no extensions needed + - Callers with typeof support can make wrapper macros +*/ +#define arr_contains(THIS, TYPE, VALUE)\ + (\ + STATIC_ASSERT(sizeof(*(THIS)) == sizeof(TYPE)),\ + dyn_array_contains_func((THIS), (uint8_t*)&(TYPE){(VALUE)})\ + ) + // CLI ///////////////////////////////////////////////////////////////////////// #define CLI_UNIQUE1 __macro_internal_34bba35b8b9b20a75f9881e3795630e25d36e620d9c9741e2e9141ba82ec6ef7__ diff --git a/dyn_array.c b/dyn_array.c index 0c5d627..fd8bcd9 100644 --- a/dyn_array.c +++ b/dyn_array.c @@ -39,7 +39,7 @@ static inline void *todo_remove_create_func(dyn_array_create_non_crashing_func_a args.file, args.line ); - header->size = 0; + header->n_items = 0; header->capacity = args.initial_capacity; header->itemsize = args.itemsize; header->allocator = args.allocator; @@ -48,7 +48,7 @@ static inline void *todo_remove_create_func(dyn_array_create_non_crashing_func_a static inline void *todo_remove_grow_func(void *this, size_t n_new_items, const char *file, int line) { dyn_array_header_t *header = PTR_FROM_FIELD_PTR(dyn_array_header_t, bytes, this); - size_t new_size = header->size + n_new_items; + size_t new_size = header->n_items + n_new_items; if (header->capacity < new_size) { size_t cap_times_2 = header->capacity * 2; @@ -65,7 +65,7 @@ static inline void *todo_remove_grow_func(void *this, size_t n_new_items, const ); header->capacity = new_capacity; } - header->size = new_size; + header->n_items = new_size; return &header->bytes; } @@ -80,18 +80,35 @@ void dyn_array_shrink_func(void *this, size_t n_items_to_remove, const char *fil exit(1); } dyn_array_header_t *header = PTR_FROM_FIELD_PTR(dyn_array_header_t, bytes, this); - header->size -= n_items_to_remove; + header->n_items -= n_items_to_remove; } size_t arr_len(void *this) { if (this == NULL) { return 0; } dyn_array_header_t *header = PTR_FROM_FIELD_PTR(dyn_array_header_t, bytes, this); - return header->size; + return header->n_items; } -size_t dyn_array_capacity(void *this) { +size_t arr_cap(void *this) { if (this == NULL) { return 0; } dyn_array_header_t *header = PTR_FROM_FIELD_PTR(dyn_array_header_t, bytes, this); return header->capacity; } + +bool dyn_array_contains_func(void *this, uint8_t *value) { + dyn_array_header_t *header = PTR_FROM_FIELD_PTR(dyn_array_header_t, bytes, this); + for (size_t i = 0; i < header->n_items; i++) { + bool is_equal = true; + for (size_t off = 0; off < header->itemsize; off++) { + if (header->bytes[i*header->itemsize+off] != value[off]) { + is_equal = false; + break; + } + } + if (is_equal) { + return true; + } + } + return false; +} diff --git a/test_dynamic_array.c b/test_dynamic_array.c index 96b7fad..8b470f5 100644 --- a/test_dynamic_array.c +++ b/test_dynamic_array.c @@ -50,3 +50,21 @@ Test(dynamic_arrays, pop) { } } } + +Test(dynamic_arrays, contains) { + with_borrow(alloc) { + int *numbers = make_arr(alloc, int); + arr_append(numbers, 20); + cr_expect(arr_contains(numbers, int, 20)); + arr_reset(numbers); + + for ( size_t y = 0; y < 1000; y++ ) { + for ( size_t i = 0; i < 100; i++ ) { + if (!arr_contains(numbers, int, i)) { + arr_append(numbers, i); + } + } + } + cr_assert_eq(arr_len(numbers), 100); + } +}