├── .gitignore ├── README.md ├── include ├── generic_deque.h ├── generic_event.h ├── generic_grid.h ├── generic_hash_utils.h ├── generic_iterators │ ├── deque_iterator.h │ ├── list_iterator.h │ ├── map_iterator.h │ ├── queue_iterator.h │ ├── rbtree_iterator.h │ ├── set_iterator.h │ └── trie_iterator.h ├── generic_list.h ├── generic_map.h ├── generic_option.h ├── generic_pool.h ├── generic_queue.h ├── generic_rbtree.h ├── generic_set.h └── generic_trie.h ├── meson.build ├── meson_options.txt ├── tests ├── deque_test.c ├── event_test.c ├── grid_test.c ├── list_test.c ├── map_test.c ├── meson.build ├── option_test.c ├── pool_test.c ├── queue_test.c ├── rb_tree_test.c ├── set_test.c └── trie_test.c └── todolist.txt /.gitignore: -------------------------------------------------------------------------------- 1 | .clang_complete 2 | Build -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Generic Data Structures 2 | 3 | Generic Data Structures is a header-only project in C that can be used to generate strongly typed Data Structures, mostly various collection types. It works similar to c++ templates. 4 | 5 | The following collections are currently implemented: 6 | * [List + Stack](https://mystborn.github.io/GenericDataStructures/list/) 7 | * [Map](https://mystborn.github.io/GenericDataStructures/map/) 8 | * [Queue](https://mystborn.github.io/GenericDataStructures/queue/) 9 | * [Red Black Tree](https://mystborn.github.io/GenericDataStructures/redblacktree/) 10 | * [Set](https://mystborn.github.io/GenericDataStructures/set/) 11 | * [Grid](https://mystborn.github.io/GenericDataStructures/grid/) 12 | 13 | There a number of collections I'd like to add. If you want to contribute, please check the [todo list](https://github.com/mystborn/GenericDataStructures/blob/master/todolist.txt) to see what is currently pending implementation. 14 | 15 | ## Usage 16 | 17 | *For more information, please view the [documentation website](https://mystborn.github.io/GenericDataStructures/)* 18 | 19 | All of the data structures are split into two macros. One generally goes into a header file, and the other into a source file. The header macro can be placed in the same source file as the source macro if the data structure will only be used in that file. For example, the list macros are `LIST_DEFINE_H` for the header and `LIST_DEFINE_C` for the source. 20 | 21 | Here's an example that creates and uses a list of ints: 22 | 23 | ```c 24 | // main.h 25 | #include 26 | 27 | // The first argument is the name of the generated data structure, 28 | // the second argument is a name to prefix each function with, 29 | // and the final argument is the value stored by the list, in this 30 | // case int. 31 | 32 | LIST_DEFINE_H(IntList, int_list, int) 33 | 34 | 35 | // main.c 36 | 37 | #include "main.h" 38 | 39 | LIST_DEFINE_C(IntList, int_list, int) 40 | 41 | int main(void) { 42 | IntList* list = int_list_create(); 43 | 44 | // Add the square of the number 0..9 45 | for(int i = 0; i < 10; i++) 46 | int_list_add(list, i * i); 47 | 48 | // Print the squares 49 | for(int i = 0; i < int_list_count(list); i++) 50 | printf("%d^2 = %d\n", i, int_list_get(list, i)); 51 | 52 | int_list_free(list); 53 | 54 | return 0; 55 | } 56 | ``` 57 | 58 | ## Including 59 | 60 | This is a header-only project, so for the most part all you need to do is clone the repo to a subdirectory and at it to your include lists. If you're using meson, you can subproject easily like so: 61 | 62 | ##### Wrap File: 63 | 64 | ```ini 65 | [wrap-git] 66 | directory = GenericDataStructures 67 | url = https://github.com/mystborn/GenericDataStructures 68 | revision = master 69 | ``` 70 | 71 | ##### Meson: 72 | 73 | ```meson 74 | GenericDataStructures = subproject('GenericDataStructures') 75 | 76 | # Pass this with the rest of your dependencies when creating the library/executable. 77 | GenericDataStructures_dep = GenericDataStructures.get_variable('GenericDataStructures_dep') 78 | ``` 79 | 80 | ## Building 81 | 82 | As this is a header-only project, it doesn't need to be built. There are some tests included that will need to be built however. This project uses meson to build by default. The tests use the [check](https://libcheck.github.io/check/) unit testing framework. On windows, you'll need to specify where the library is. On linux, as long as it's installed normally, they'll be built automatically. To specify the location, use the `check_location` configuration option. Most likely installed at `C:\Program Files (x86)\check`. 83 | 84 | ```sh 85 | mkdir build 86 | cd build 87 | meson .. 88 | meson configure "-Dcheck_location=C:\Program Files (x86)\check" 89 | ninja test 90 | ``` 91 | -------------------------------------------------------------------------------- /include/generic_deque.h: -------------------------------------------------------------------------------- 1 | #ifndef GENERIC_DATA_STRUCTURES_DEQUE_H 2 | #define GENERIC_DATA_STRUCTURES_DEQUE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define DEQUE_DEFINE_H(type_name, function_prefix, value_type) \ 11 | typedef struct type_name { \ 12 | value_type* buffer; \ 13 | unsigned int count; \ 14 | unsigned int capacity; \ 15 | unsigned int start; \ 16 | unsigned int end; \ 17 | } type_name; \ 18 | \ 19 | type_name* function_prefix ## _create(void); \ 20 | type_name* function_prefix ## _create_capacity(unsigned int capacity); \ 21 | bool function_prefix ## _init(type_name* deque); \ 22 | bool function_prefix ## _init_capacity(type_name* deque, unsigned int capacity); \ 23 | void function_prefix ## _clear(type_name* deque, bool reset_capacity); \ 24 | bool function_prefix ## _push_front(type_name* deque, value_type value); \ 25 | bool function_prefix ## _push_back(type_name* deque, value_type value); \ 26 | value_type function_prefix ## _pop_front(type_name* deque); \ 27 | value_type function_prefix ## _pop_back(type_name* deque); \ 28 | \ 29 | static inline value_type function_prefix ## _peek_front(const type_name* deque) { \ 30 | assert(deque->count); \ 31 | return deque->buffer[deque->start]; \ 32 | } \ 33 | \ 34 | static inline value_type function_prefix ## _peek_back(const type_name* deque) { \ 35 | assert(deque->count); \ 36 | return deque->buffer[deque->end == 0 ? deque->capacity - 1 : deque->end - 1]; \ 37 | } \ 38 | \ 39 | static inline unsigned int function_prefix ## _count(const type_name* deque) { return deque->count; } \ 40 | static inline unsigned int function_prefix ## _capacity(const type_name* deque) { return deque->capacity; } \ 41 | static inline void function_prefix ## _free_resources(type_name* deque) { free(deque->buffer); } \ 42 | static inline void function_prefix ## _free(type_name* deque) { free(deque->buffer); free(deque); } \ 43 | 44 | 45 | #define DEQUE_DEFINE_C(type_name, function_prefix, value_type) \ 46 | type_name* function_prefix ## _create(void) { \ 47 | type_name* deque = malloc(sizeof(type_name)); \ 48 | if(!deque) \ 49 | return NULL; \ 50 | if(!function_prefix ## _init(deque)) { \ 51 | free(deque); \ 52 | return NULL; \ 53 | } \ 54 | return deque; \ 55 | } \ 56 | \ 57 | type_name* function_prefix ## _create_capacity(unsigned int capacity) { \ 58 | type_name* deque = malloc(sizeof(type_name)); \ 59 | if(!deque) \ 60 | return NULL; \ 61 | if(!function_prefix ## _init_capacity(deque, capacity)) { \ 62 | free(deque); \ 63 | return NULL; \ 64 | } \ 65 | return deque; \ 66 | } \ 67 | \ 68 | bool function_prefix ## _init(type_name* deque) { \ 69 | deque->start = 0; \ 70 | deque->end = 0; \ 71 | deque->count = 0; \ 72 | deque->capacity = 4; \ 73 | return (deque->buffer = malloc(deque->capacity * sizeof(value_type))) != NULL; \ 74 | } \ 75 | \ 76 | bool function_prefix ## _init_capacity(type_name* deque, unsigned int capacity) { \ 77 | deque->start = 0; \ 78 | deque->end = 0; \ 79 | deque->count = 0; \ 80 | deque->capacity = capacity == 0 ? 1 : capacity; \ 81 | return (deque->buffer = malloc(deque->capacity * sizeof(value_type))) != NULL; \ 82 | } \ 83 | \ 84 | void function_prefix ## _clear(type_name* deque, bool reset_capacity) { \ 85 | if(reset_capacity) { \ 86 | function_prefix ## _free_resources(deque); \ 87 | function_prefix ## _init(deque); \ 88 | } else { \ 89 | deque->start = 0; \ 90 | deque->end = 0; \ 91 | deque->count = 0; \ 92 | } \ 93 | } \ 94 | \ 95 | static bool function_prefix ## _resize(type_name* deque) { \ 96 | unsigned int offset = deque->capacity - deque->start; \ 97 | deque->capacity *= 2; \ 98 | value_type* buffer = malloc(deque->capacity * sizeof(value_type)); \ 99 | if(!buffer) { \ 100 | deque->capacity /= 2; \ 101 | return false; \ 102 | } \ 103 | if(deque->end > deque->start) { \ 104 | memcpy(buffer, deque->buffer + deque->start, deque->count * sizeof(value_type)); \ 105 | } else { \ 106 | unsigned offset = deque->count - deque->start; \ 107 | memcpy(buffer, deque->buffer + deque->start, offset * sizeof(value_type)); \ 108 | memcpy(buffer + offset, deque->buffer, deque->end * sizeof(value_type)); \ 109 | } \ 110 | deque->buffer = buffer; \ 111 | deque->start = 0; \ 112 | deque->end = deque->count; \ 113 | return true; \ 114 | } \ 115 | \ 116 | bool function_prefix ## _push_front(type_name* deque, value_type value) { \ 117 | if(deque->count == deque->capacity) { \ 118 | if(!function_prefix ## _resize(deque)) \ 119 | return false; \ 120 | } \ 121 | deque->start = deque->start == 0 ? deque->capacity - 1 : deque->start -1; \ 122 | deque->buffer[deque->start] = value; \ 123 | deque->count++; \ 124 | return true; \ 125 | } \ 126 | \ 127 | bool function_prefix ## _push_back(type_name* deque, value_type value) { \ 128 | if(deque->count == deque->capacity) { \ 129 | if(!function_prefix ## _resize(deque)) \ 130 | return false; \ 131 | } \ 132 | deque->buffer[deque->end] = value; \ 133 | deque->end = deque->end == deque->capacity - 1 ? 0 : deque->end + 1; \ 134 | deque->count++; \ 135 | return true; \ 136 | } \ 137 | \ 138 | value_type function_prefix ## _pop_front(type_name* deque) { \ 139 | assert(deque->count); \ 140 | deque->count--; \ 141 | value_type value = deque->buffer[deque->start]; \ 142 | deque->start = deque->start == deque->capacity - 1 ? 0 : deque->start + 1; \ 143 | return value; \ 144 | } \ 145 | \ 146 | value_type function_prefix ## _pop_back(type_name* deque) { \ 147 | assert(deque->count); \ 148 | deque->count--; \ 149 | deque->end = deque->end == 0 ? deque->capacity - 1 : deque->end - 1; \ 150 | return deque->buffer[deque->end]; \ 151 | } \ 152 | 153 | 154 | 155 | 156 | #endif -------------------------------------------------------------------------------- /include/generic_event.h: -------------------------------------------------------------------------------- 1 | #ifndef GENERIC_DATA_STRUCTURES_GENERIC_EVENT_H 2 | #define GENERIC_DATA_STRUCTURES_GENERIC_EVENT_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | // ============================================================================ 9 | // Generic Event via template-like macros 10 | // ============================================================================ 11 | 12 | #define ___EVENT_DEFINE_H_SHARED(type_name, function_prefix) \ 13 | struct type_name ## Subscription { \ 14 | void* data; \ 15 | type_name ## Delegate function; \ 16 | }; \ 17 | \ 18 | typedef struct type_name { \ 19 | struct type_name ## Subscription* subscriptions; \ 20 | unsigned int count; \ 21 | unsigned int capacity; \ 22 | } type_name; \ 23 | \ 24 | bool function_prefix ## _subscribe(type_name* ev, void* ctx, type_name ## Delegate function); \ 25 | bool function_prefix ## _unsubscribe(type_name* ev, void* ctx, type_name ## Delegate function); \ 26 | \ 27 | static inline void function_prefix ## _init(type_name* ev) { \ 28 | ev->count = 0; \ 29 | ev->capacity = 0; \ 30 | ev->subscriptions = NULL; \ 31 | } \ 32 | \ 33 | static inline type_name* function_prefix ## _create(void) { \ 34 | type_name* ev = malloc(sizeof(*ev)); \ 35 | if(!ev) \ 36 | return NULL; \ 37 | \ 38 | function_prefix ## _init(ev); \ 39 | return ev; \ 40 | } \ 41 | \ 42 | static inline void function_prefix ## _free(type_name* ev) { \ 43 | free(ev->subscriptions); \ 44 | free(ev); \ 45 | } \ 46 | \ 47 | static inline void function_prefix ## _free_resources(type_name* ev) { \ 48 | free(ev->subscriptions); \ 49 | } \ 50 | 51 | #define EVENT_DEFINE_0_H(type_name, function_prefix) \ 52 | typedef void (*type_name ## Delegate)(void*); \ 53 | \ 54 | ___EVENT_DEFINE_H_SHARED(type_name, function_prefix) \ 55 | \ 56 | static inline void function_prefix ## _trigger(type_name* ev) { \ 57 | for(unsigned int i = 0; i < ev->count; i++) { \ 58 | struct type_name ## Subscription subscription = ev->subscriptions[i]; \ 59 | (subscription.function)(subscription.data); \ 60 | } \ 61 | } \ 62 | 63 | 64 | #define EVENT_DEFINE_1_H(type_name, function_prefix, arg1) \ 65 | typedef void (*type_name ## Delegate)(void*, arg1); \ 66 | \ 67 | ___EVENT_DEFINE_H_SHARED(type_name, function_prefix) \ 68 | \ 69 | static inline void function_prefix ## _trigger(type_name* ev, arg1 a1) { \ 70 | for(unsigned int i = 0; i < ev->count; i++) { \ 71 | struct type_name ## Subscription subscription = ev->subscriptions[i]; \ 72 | (subscription.function)(subscription.data, a1); \ 73 | } \ 74 | } \ 75 | 76 | 77 | #define EVENT_DEFINE_2_H(type_name, function_prefix, arg1, arg2) \ 78 | typedef void (*type_name ## Delegate)(void*, arg1, arg2); \ 79 | \ 80 | ___EVENT_DEFINE_H_SHARED(type_name, function_prefix) \ 81 | \ 82 | static inline void function_prefix ## _trigger(type_name* ev, arg1 a1, arg2 a2) { \ 83 | for(unsigned int i = 0; i < ev->count; i++) { \ 84 | struct type_name ## Subscription subscription = ev->subscriptions[i]; \ 85 | (subscription.function)(subscription.data, a1, a2); \ 86 | } \ 87 | } \ 88 | 89 | 90 | #define EVENT_DEFINE_3_H(type_name, function_prefix, arg1, arg2, arg3) \ 91 | typedef void (*type_name ## Delegate)(void*, arg1, arg2, arg3); \ 92 | \ 93 | ___EVENT_DEFINE_H_SHARED(type_name, function_prefix) \ 94 | \ 95 | static inline void function_prefix ## _trigger(type_name* ev, arg1 a1, arg2 a2, arg3 a3) { \ 96 | for(unsigned int i = 0; i < ev->count; i++) { \ 97 | struct type_name ## Subscription subscription = ev->subscriptions[i]; \ 98 | (subscription.function)(subscription.data, a1, a2, a3); \ 99 | } \ 100 | } \ 101 | 102 | 103 | #define EVENT_DEFINE_4_H(type_name, function_prefix, arg1, arg2, arg3, arg4) \ 104 | typedef void (*type_name ## Delegate)(void*, arg1, arg2, arg3, arg4); \ 105 | \ 106 | ___EVENT_DEFINE_H_SHARED(type_name, function_prefix) \ 107 | \ 108 | static inline void function_prefix ## _trigger(type_name* ev, arg1 a1, arg2 a2, arg3 a3, arg4 a4) { \ 109 | for(unsigned int i = 0; i < ev->count; i++) { \ 110 | struct type_name ## Subscription subscription = ev->subscriptions[i]; \ 111 | (subscription.function)(subscription.data, a1, a2, a3, a4); \ 112 | } \ 113 | } \ 114 | 115 | 116 | #define EVENT_DEFINE_5_H(type_name, function_prefix, arg1, arg2, arg3, arg4, arg5) \ 117 | typedef void (*type_name ## Delegate)(void*, arg1, arg2, arg3, arg4, arg5); \ 118 | \ 119 | ___EVENT_DEFINE_H_SHARED(type_name, function_prefix) \ 120 | \ 121 | static inline void function_prefix ## _trigger(type_name* ev, arg1 a1, arg2 a2, arg3 a3, arg4 a4, arg5 a5) { \ 122 | for(unsigned int i = 0; i < ev->count; i++) { \ 123 | struct type_name ## Subscription subscription = ev->subscriptions[i]; \ 124 | (subscription.function)(subscription.data, a1, a2, a3, a4, a5); \ 125 | } \ 126 | } \ 127 | 128 | 129 | #define EVENT_DEFINE_6_H(type_name, function_prefix, arg1, arg2, arg3, arg4, arg5, arg6) \ 130 | typedef void (*type_name ## Delegate)(void*, arg1, arg2, arg3, arg4, arg5, arg6); \ 131 | \ 132 | ___EVENT_DEFINE_H_SHARED(type_name, function_prefix) \ 133 | \ 134 | static inline void function_prefix ## _trigger(type_name* ev, arg1 a1, arg2 a2, arg3 a3, arg4 a4, arg5 a5, arg6 a6) { \ 135 | for(unsigned int i = 0; i < ev->count; i++) { \ 136 | struct type_name ## Subscription subscription = ev->subscriptions[i]; \ 137 | (subscription.function)(subscription.data, a1, a2, a3, a4, a5, a6); \ 138 | } \ 139 | } \ 140 | 141 | 142 | #define EVENT_DEFINE_7_H(type_name, function_prefix, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \ 143 | typedef void (*type_name ## Delegate)(void*, arg1, arg2, arg3, arg4, arg5, arg6, arg7); \ 144 | \ 145 | ___EVENT_DEFINE_H_SHARED(type_name, function_prefix) \ 146 | \ 147 | static inline void function_prefix ## _trigger(type_name* ev, arg1 a1, arg2 a2, arg3 a3, arg4 a4, arg5 a5, arg6 a6, arg7 a7) { \ 148 | for(unsigned int i = 0; i < ev->count; i++) { \ 149 | struct type_name ## Subscription subscription = ev->subscriptions[i]; \ 150 | (subscription.function)(subscription.data, a1, a2, a3, a4, a5, a6, a7); \ 151 | } \ 152 | } \ 153 | 154 | 155 | #define EVENT_DEFINE_8_H(type_name, function_prefix, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) \ 156 | typedef void (*type_name ## Delegate)(void*, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); \ 157 | \ 158 | ___EVENT_DEFINE_H_SHARED(type_name, function_prefix) \ 159 | \ 160 | static inline void function_prefix ## _trigger(type_name* ev, arg1 a1, arg2 a2, arg3 a3, arg4 a4, arg5 a5, arg6 a6, arg7 a7, arg8 a8) { \ 161 | for(unsigned int i = 0; i < ev->count; i++) { \ 162 | struct type_name ## Subscription subscription = ev->subscriptions[i]; \ 163 | (subscription.function)(subscription.data, a1, a2, a3, a4, a5, a6, a7, a8); \ 164 | } \ 165 | } \ 166 | 167 | 168 | #define EVENT_DEFINE_9_H(type_name, function_prefix, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) \ 169 | typedef void (*type_name ## Delegate)(void*, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); \ 170 | \ 171 | ___EVENT_DEFINE_H_SHARED(type_name, function_prefix) \ 172 | \ 173 | static inline void function_prefix ## _trigger(type_name* ev, arg1 a1, arg2 a2, arg3 a3, arg4 a4, arg5 a5, arg6 a6, arg7 a7, arg8 a8, arg9 a9) { \ 174 | for(unsigned int i = 0; i < ev->count; i++) { \ 175 | struct type_name ## Subscription subscription = ev->subscriptions[i]; \ 176 | (subscription.function)(subscription.data, a1, a2, a3, a4, a5, a6, a7, a8, a9); \ 177 | } \ 178 | } \ 179 | 180 | 181 | #define EVENT_DEFINE_10_H(type_name, function_prefix, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10) \ 182 | typedef void (*type_name ## Delegate)(void*, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); \ 183 | \ 184 | ___EVENT_DEFINE_H_SHARED(type_name, function_prefix) \ 185 | \ 186 | static inline void function_prefix ## _trigger(type_name* ev, arg1 a1, arg2 a2, arg3 a3, arg4 a4, arg5 a5, arg6 a6, arg7 a7, arg8 a8, arg9 a9, arg10 a10) { \ 187 | for(unsigned int i = 0; i < ev->count; i++) { \ 188 | struct type_name ## Subscription subscription = ev->subscriptions[i]; \ 189 | (subscription.function)(subscription.data, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); \ 190 | } \ 191 | } \ 192 | 193 | 194 | #define EVENT_DEFINE_C(type_name, function_prefix) \ 195 | bool function_prefix ## _subscribe(type_name* ev, void* ctx, type_name ## Delegate function) { \ 196 | if(ev->count == ev->capacity) { \ 197 | unsigned int capacity = ev->capacity; \ 198 | if(capacity == 0) \ 199 | capacity = 2; \ 200 | else \ 201 | capacity *= 2; \ 202 | \ 203 | void* buffer = realloc(ev->subscriptions, capacity * sizeof(*ev->subscriptions)); \ 204 | if(!buffer) \ 205 | return false; \ 206 | \ 207 | ev->capacity = capacity; \ 208 | ev->subscriptions = buffer; \ 209 | } \ 210 | \ 211 | ev->subscriptions[ev->count].data = ctx; \ 212 | ev->subscriptions[ev->count++].function = function; \ 213 | \ 214 | return true; \ 215 | } \ 216 | \ 217 | bool function_prefix ## _unsubscribe(type_name* ev, void* ctx, type_name ## Delegate function) { \ 218 | for(unsigned int i = 0; i < ev->count; i++) { \ 219 | if(ev->subscriptions[i].data == ctx && ev->subscriptions[i].function == function) { \ 220 | if(i != ev->count - 1) \ 221 | memmove(&ev->subscriptions[i], &ev->subscriptions[i + 1], (ev->count - i) * sizeof(*ev->subscriptions)); \ 222 | \ 223 | ev->count--; \ 224 | return true; \ 225 | } \ 226 | } \ 227 | \ 228 | return false; \ 229 | } \ 230 | 231 | 232 | // ============================================================================ 233 | // Generic Event via void* 234 | // ============================================================================ 235 | 236 | struct GdsEventSubscription { 237 | void* data; 238 | void* function; 239 | }; 240 | 241 | typedef struct GdsEvent { 242 | struct GdsEventSubscription* subscriptions; 243 | int count; 244 | int capacity; 245 | } GdsEvent; 246 | 247 | bool gds_event_subscribe(GdsEvent* ev, void* ctx, void* function); 248 | bool gds_event_unsubscribe(GdsEvent* ev, void* ctx, void* function); 249 | 250 | static inline void gds_event_init(GdsEvent* ev) { 251 | ev->subscriptions = NULL; 252 | ev->count = 0; 253 | ev->capacity = 0; 254 | } 255 | 256 | static inline GdsEvent* gds_event_create(void) { 257 | GdsEvent* ev = malloc(sizeof(*ev)); 258 | if(!ev) 259 | return NULL; 260 | 261 | gds_event_init(ev); 262 | return ev; 263 | } 264 | 265 | static inline void gds_event_free_resources(GdsEvent* ev) { free(ev->subscriptions); } 266 | static inline void gds_event_free(GdsEvent* ev) { free(ev->subscriptions); free(ev); } 267 | 268 | #define GDS_EVENT_DEFAULT void (*)(void*) 269 | #define GDS_EVENT_SIGNATURE(...) void (*)(void*, ## __VA_ARGS__ ) 270 | 271 | #define GDS_EVENT_TRIGGER(ev, event_signature, ...) \ 272 | do { \ 273 | for(int ___gds_event_index = 0; ___gds_event_index < (ev)->count; ++___gds_event_index) { \ 274 | struct GdsEventSubscription ___gds_event_subscription = (ev)->subscriptions[___gds_event_index]; \ 275 | ((event_signature)(___gds_event_subscription.function))(___gds_event_subscription.data, ## __VA_ARGS__ ); \ 276 | } \ 277 | } while(0) 278 | 279 | 280 | #ifdef GENERIC_EVENT_IMPLEMENTATION 281 | #ifndef GENERIC_EVENT_IMPLEMENTATION_ONCE 282 | #define GENERIC_EVENT_IMPLEMENTATION_ONCE 283 | 284 | bool gds_event_subscribe(GdsEvent* ev, void* ctx, void* function) { 285 | if(ev->count == ev->capacity) { 286 | unsigned int capacity = ev->capacity; 287 | if(capacity == 0) 288 | capacity = 2; 289 | else 290 | capacity *= 2; 291 | 292 | void* buffer = realloc(ev->subscriptions, capacity * sizeof(*ev->subscriptions)); 293 | if(!buffer) 294 | return false; 295 | 296 | ev->capacity = capacity; 297 | ev->subscriptions = buffer; 298 | } 299 | 300 | ev->subscriptions[ev->count].data = ctx; 301 | ev->subscriptions[ev->count++].function = function; 302 | 303 | return true; 304 | } 305 | 306 | bool gds_event_unsubscribe(GdsEvent* ev, void* ctx, void* function) { 307 | for(unsigned int i = 0; i < ev->count; i++) { 308 | if(ev->subscriptions[i].data == ctx && ev->subscriptions[i].function == function) { 309 | if(i != ev->count - 1) { 310 | memmove(&ev->subscriptions, 311 | &ev->subscriptions[i + 1], 312 | (ev->count - i) * sizeof(*ev->subscriptions)); 313 | } 314 | 315 | ev->count--; 316 | return true; 317 | } 318 | } 319 | 320 | return false; 321 | } 322 | 323 | #endif // GENERIC_EVENT_IMPLEMENTATION_ONCE 324 | #endif // GENERIC_EVENT_IMPLEMENTATION 325 | 326 | #endif // GENERIC_DATA_STRUCTURES_GENERIC_EVENT_H -------------------------------------------------------------------------------- /include/generic_grid.h: -------------------------------------------------------------------------------- 1 | #ifndef GENERIC_DATA_STRUCTURES_GRID_H 2 | #define GENERIC_DATA_STRUCTURES_GRID_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define GRID_DEFINE_H(type_name, function_prefix, value_type) \ 9 | typedef struct type_name { \ 10 | value_type* grid; \ 11 | unsigned int width; \ 12 | unsigned int height; \ 13 | } type_name; \ 14 | \ 15 | type_name* function_prefix ## _create(unsigned int width, unsigned int height); \ 16 | bool function_prefix ## _init(type_name* grid, unsigned int width, unsigned int height); \ 17 | void function_prefix ## _free(type_name* grid); \ 18 | void function_prefix ## _free_resources(type_name* grid); \ 19 | void function_prefix ## _clear(type_name* grid, value_type default_value); \ 20 | \ 21 | static inline unsigned int function_prefix ## _width(type_name* grid) { \ 22 | return grid->width; \ 23 | } \ 24 | \ 25 | static inline unsigned int function_prefix ## _height(type_name* grid) { \ 26 | return grid->height; \ 27 | } \ 28 | \ 29 | static inline value_type function_prefix ## _get(type_name* grid, unsigned int x, unsigned int y) { \ 30 | assert(x < grid->width); \ 31 | assert(y < grid->height); \ 32 | return grid->grid[y * grid->width + x]; \ 33 | } \ 34 | \ 35 | static inline void function_prefix ## _set(type_name* grid, unsigned int x, unsigned int y, value_type value) { \ 36 | assert(x < grid->width); \ 37 | assert(y < grid->height); \ 38 | grid->grid[y * grid->width + x] = value; \ 39 | } \ 40 | 41 | #define GRID_DEFINE_C(type_name, function_prefix, value_type) \ 42 | bool function_prefix ## _init(type_name* grid, unsigned int width, unsigned int height) { \ 43 | grid->width = width; \ 44 | grid->height = height; \ 45 | return (grid->grid = malloc(width * height * sizeof(value_type))) != NULL; \ 46 | } \ 47 | \ 48 | type_name* function_prefix ## _create(unsigned int width, unsigned int height) { \ 49 | type_name* grid = malloc(sizeof(type_name)); \ 50 | if(!grid) \ 51 | return NULL; \ 52 | if(!function_prefix ## _init(grid, width, height)) { \ 53 | free(grid); \ 54 | return NULL; \ 55 | } \ 56 | return grid; \ 57 | } \ 58 | \ 59 | void function_prefix ## _free(type_name* grid) { \ 60 | free(grid->grid); \ 61 | free(grid); \ 62 | } \ 63 | \ 64 | void function_prefix ## _free_resources(type_name* grid) { \ 65 | free(grid->grid); \ 66 | } \ 67 | \ 68 | void function_prefix ## _clear(type_name* grid, value_type default_value) { \ 69 | for(unsigned int h = 0; h < grid->height; h++) { \ 70 | for(unsigned int w = 0; w < grid->width; w++) { \ 71 | grid->grid[h * grid->width + w] = default_value; \ 72 | } \ 73 | } \ 74 | } 75 | 76 | #endif -------------------------------------------------------------------------------- /include/generic_hash_utils.h: -------------------------------------------------------------------------------- 1 | #ifndef GENERIC_DATA_STRUCTURES_HASH_UTILS_H 2 | #define GENERIC_DATA_STRUCTURES_HASH_UTILS_H 3 | 4 | /* 5 | Defines some utility functions used by both the map and set structures. 6 | */ 7 | 8 | #include 9 | 10 | // A detailed explanation of this can be found here: 11 | // https://probablydance.com/2018/06/16/fibonacci-hashing-the-optimization-that-the-world-forgot-or-a-better-alternative-to-integer-modulo/ 12 | 13 | // The specific constant was found here: 14 | // http://book.huihoo.com/data-structures-and-algorithms-with-object-oriented-design-patterns-in-c++/html/page214.html 15 | 16 | static inline uint32_t ___fib_hash(uint32_t hash, uint32_t shift) { 17 | return (hash * 2654435769U) >> shift; 18 | } 19 | 20 | #define FNV_PRIME_32 0x01000193 21 | #define FNV_OFFSET_32 0x811c9dc5 22 | 23 | static uint32_t gds_fnv32(const char* data) { 24 | uint32_t hash = FNV_OFFSET_32; 25 | while(*(unsigned char*)data != 0) 26 | hash = (*(unsigned char*)data++ ^ hash) * FNV_PRIME_32; 27 | 28 | return hash; 29 | } 30 | 31 | #endif -------------------------------------------------------------------------------- /include/generic_iterators/deque_iterator.h: -------------------------------------------------------------------------------- 1 | #ifndef GENERIC_DATA_STRUCTURES_GENERIC_ITERATORS_DEQUE_ITERATOR_H 2 | #define GENERIC_DATA_STRUCTURES_GENERIC_ITERATORS_DEQUE_ITERATOR_H 3 | 4 | #define deque_iter_start(deque, out_value) \ 5 | { \ 6 | unsigned int ___deque_iter_pos = deque->start, ___deque_iter_i = 0; \ 7 | while(___deque_iter_i++ < deque->count) { \ 8 | out_value = deque->buffer[___deque_iter_pos]; \ 9 | ___deque_iter_pos = ___deque_iter_pos == deque->capacity - 1 ? 0 : ___deque_iter_pos + 1; \ 10 | 11 | #define deque_iter_end } } 12 | 13 | #endif -------------------------------------------------------------------------------- /include/generic_iterators/list_iterator.h: -------------------------------------------------------------------------------- 1 | #ifndef GENERIC_DATA_STRUCTURES_GENERIC_ITERATORS_LIST_ITERATOR_H 2 | #define GENERIC_DATA_STRUCTURES_GENERIC_ITERATORS_LIST_ITERATOR_H 3 | 4 | #define list_iter_start(list, out_value) \ 5 | for(int list_iter_i = 0; list_iter_i < (list)->count; list_iter_i++) { \ 6 | out_value = (list)->buffer[list_iter_i]; 7 | 8 | #define list_iter_end } 9 | 10 | #endif -------------------------------------------------------------------------------- /include/generic_iterators/map_iterator.h: -------------------------------------------------------------------------------- 1 | #ifndef GENERIC_DATA_STRUCTURES_GENERIC_ITERATORS_MAP_ITERATOR_H 2 | #define GENERIC_DATA_STRUCTURES_GENERIC_ITERATORS_MAP_ITERATOR_H 3 | 4 | #include 5 | 6 | #define map_iter_start(map, out_key, out_value) \ 7 | for(uint32_t map_iter_i = 0; map_iter_i < (map)->capacity; map_iter_i++) { \ 8 | if(!(map)->cells[map_iter_i].active) \ 9 | continue; \ 10 | (out_key) = (map)->cells[map_iter_i].key; \ 11 | (out_value) = (map)->cells[map_iter_i].value; 12 | 13 | #define map_iter_key_start(map, out_key) \ 14 | for(uint32_t map_iter_i = 0; map_iter_i < (map)->capacity; map_iter_i++) { \ 15 | if(!(map)->cells[map_iter_i].active) \ 16 | continue; \ 17 | out_key = (map)->cells[map_iter_i].key; 18 | 19 | #define map_iter_value_start(map, out_value) \ 20 | for(uint32_t map_iter_i = 0; map_iter_i < (map)->capacity; map_iter_i++) { \ 21 | if(!(map)->cells[map_iter_i].active) \ 22 | continue; \ 23 | out_value = (map)->cells[map_iter_i].value; 24 | 25 | #define map_iter_end } 26 | 27 | #endif -------------------------------------------------------------------------------- /include/generic_iterators/queue_iterator.h: -------------------------------------------------------------------------------- 1 | #ifndef GENERIC_DATA_STRUCTURES_GENERIC_ITERATORS_QUEUE_ITERATOR 2 | #define GENERIC_DATA_STRUCTURES_GENERIC_ITERATORS_QUEUE_ITERATOR 3 | 4 | #define queue_iter_start(queue, out_value) \ 5 | for(int queue_iter_i = (queue)->start; queue_iter_i != (queue)->end; queue_iter_i = (++queue_iter_i == (queue)->capacity ? 0 : queue_iter_i)) { \ 6 | out_value = (queue)->buffer[queue_iter_i]; 7 | 8 | #define queue_iter_end } 9 | 10 | #endif -------------------------------------------------------------------------------- /include/generic_iterators/rbtree_iterator.h: -------------------------------------------------------------------------------- 1 | #ifndef GENERIC_DATA_STRUCTURES_GENERIC_ITERATORS_RED_BLACK_TREE_ITERATOR_H 2 | #define GENERIC_DATA_STRUCTURES_GENERIC_ITERATORS_RED_BLACK_TREE_ITERATOR_H 3 | 4 | typedef enum RbTreeTravelDirection { 5 | RBTREE_TRAVEL_LEFT, 6 | RBTREE_TRAVEL_RIGHT, 7 | RBTREE_TRAVEL_UP 8 | } RbTreeTravelDirection; 9 | 10 | /* 11 | This algorithm is a specialized version of the one described here: 12 | https://www.geeksforgeeks.org/inorder-non-threaded-binary-tree-traversal-without-recursion-or-stack/ 13 | 14 | It has to take some extra steps to make sure the user can still use 15 | break and continue inside of the loop and get the expected result. 16 | 17 | The local variables are also somewhat obfuscated to avoid potentiall 18 | name collisions, but due to how C shadows variables, it is still 19 | possible to nest iter statements. 20 | */ 21 | 22 | #define rbtree_iter_start(tree_type, tree, out_key, out_value) \ 23 | { \ 24 | RbTreeTravelDirection rb_travel_direction = RBTREE_TRAVEL_LEFT; \ 25 | tree_type ## Node* rbtree_inorder_iter_node = (tree)->root; \ 26 | \ 27 | while(rbtree_inorder_iter_node != NULL) { \ 28 | switch(rb_travel_direction) { \ 29 | case RBTREE_TRAVEL_LEFT: \ 30 | { \ 31 | while(rbtree_inorder_iter_node->left != NULL) \ 32 | rbtree_inorder_iter_node = rbtree_inorder_iter_node->left; \ 33 | \ 34 | out_key = rbtree_inorder_iter_node->key; \ 35 | out_value = rbtree_inorder_iter_node->value; \ 36 | \ 37 | rb_travel_direction = rbtree_inorder_iter_node->right == NULL ? RBTREE_TRAVEL_UP : RBTREE_TRAVEL_RIGHT; \ 38 | break; \ 39 | } \ 40 | case RBTREE_TRAVEL_RIGHT: \ 41 | { \ 42 | rbtree_inorder_iter_node = rbtree_inorder_iter_node->right; \ 43 | while(rbtree_inorder_iter_node->left != NULL) \ 44 | rbtree_inorder_iter_node = rbtree_inorder_iter_node->left; \ 45 | \ 46 | out_key = rbtree_inorder_iter_node->key; \ 47 | out_value = rbtree_inorder_iter_node->value; \ 48 | \ 49 | rb_travel_direction = rbtree_inorder_iter_node->right == NULL ? RBTREE_TRAVEL_UP : RBTREE_TRAVEL_RIGHT; \ 50 | break; \ 51 | } \ 52 | case RBTREE_TRAVEL_UP: \ 53 | { \ 54 | if (rbtree_inorder_iter_node->parent == NULL || \ 55 | rbtree_inorder_iter_node->parent->right == rbtree_inorder_iter_node) \ 56 | { \ 57 | rbtree_inorder_iter_node = rbtree_inorder_iter_node->parent; \ 58 | continue; \ 59 | } \ 60 | \ 61 | rbtree_inorder_iter_node = rbtree_inorder_iter_node->parent; \ 62 | out_key = rbtree_inorder_iter_node->key; \ 63 | out_value = rbtree_inorder_iter_node->value; \ 64 | \ 65 | rb_travel_direction = rbtree_inorder_iter_node->right == NULL ? RBTREE_TRAVEL_UP : RBTREE_TRAVEL_RIGHT; \ 66 | break; \ 67 | } \ 68 | } 69 | 70 | #define rbtree_iter_keys_start(tree_type, tree, out_key) \ 71 | { \ 72 | RbTreeTravelDirection rb_travel_direction = RBTREE_TRAVEL_LEFT; \ 73 | tree_type ## Node* rbtree_inorder_iter_node = (tree)->root; \ 74 | \ 75 | while(rbtree_inorder_iter_node != NULL) { \ 76 | switch(rb_travel_direction) { \ 77 | case RBTREE_TRAVEL_LEFT: \ 78 | { \ 79 | while(rbtree_inorder_iter_node->left != NULL) \ 80 | rbtree_inorder_iter_node = rbtree_inorder_iter_node->left; \ 81 | \ 82 | out_key = rbtree_inorder_iter_node->key; \ 83 | \ 84 | rb_travel_direction = rbtree_inorder_iter_node->right == NULL ? RBTREE_TRAVEL_UP : RBTREE_TRAVEL_RIGHT; \ 85 | break; \ 86 | } \ 87 | case RBTREE_TRAVEL_RIGHT: \ 88 | { \ 89 | rbtree_inorder_iter_node = rbtree_inorder_iter_node->right; \ 90 | while(rbtree_inorder_iter_node->left != NULL) \ 91 | rbtree_inorder_iter_node = rbtree_inorder_iter_node->left; \ 92 | \ 93 | out_key = rbtree_inorder_iter_node->key; \ 94 | \ 95 | rb_travel_direction = rbtree_inorder_iter_node->right == NULL ? RBTREE_TRAVEL_UP : RBTREE_TRAVEL_RIGHT; \ 96 | break; \ 97 | } \ 98 | case RBTREE_TRAVEL_UP: \ 99 | { \ 100 | if (rbtree_inorder_iter_node->parent == NULL || \ 101 | rbtree_inorder_iter_node->parent->right == rbtree_inorder_iter_node) \ 102 | { \ 103 | rbtree_inorder_iter_node = rbtree_inorder_iter_node->parent; \ 104 | continue; \ 105 | } \ 106 | \ 107 | rbtree_inorder_iter_node = rbtree_inorder_iter_node->parent; \ 108 | out_key = rbtree_inorder_iter_node->key; \ 109 | \ 110 | rb_travel_direction = rbtree_inorder_iter_node->right == NULL ? RBTREE_TRAVEL_UP : RBTREE_TRAVEL_RIGHT; \ 111 | break; \ 112 | } \ 113 | } 114 | 115 | #define rbtree_iter_values_start(tree_type, tree, out_value) \ 116 | { \ 117 | RbTreeTravelDirection rb_travel_direction = RBTREE_TRAVEL_LEFT; \ 118 | tree_type ## Node* rbtree_inorder_iter_node = (tree)->root; \ 119 | \ 120 | while(rbtree_inorder_iter_node != NULL) { \ 121 | switch(rb_travel_direction) { \ 122 | case RBTREE_TRAVEL_LEFT: \ 123 | { \ 124 | while(rbtree_inorder_iter_node->left != NULL) \ 125 | rbtree_inorder_iter_node = rbtree_inorder_iter_node->left; \ 126 | \ 127 | out_value = rbtree_inorder_iter_node->value; \ 128 | \ 129 | rb_travel_direction = rbtree_inorder_iter_node->right == NULL ? RBTREE_TRAVEL_UP : RBTREE_TRAVEL_RIGHT; \ 130 | break; \ 131 | } \ 132 | case RBTREE_TRAVEL_RIGHT: \ 133 | { \ 134 | rbtree_inorder_iter_node = rbtree_inorder_iter_node->right; \ 135 | while(rbtree_inorder_iter_node->left != NULL) \ 136 | rbtree_inorder_iter_node = rbtree_inorder_iter_node->left; \ 137 | \ 138 | out_value = rbtree_inorder_iter_node->value; \ 139 | \ 140 | rb_travel_direction = rbtree_inorder_iter_node->right == NULL ? RBTREE_TRAVEL_UP : RBTREE_TRAVEL_RIGHT; \ 141 | break; \ 142 | } \ 143 | case RBTREE_TRAVEL_UP: \ 144 | { \ 145 | if (rbtree_inorder_iter_node->parent == NULL || \ 146 | rbtree_inorder_iter_node->parent->right == rbtree_inorder_iter_node) \ 147 | { \ 148 | rbtree_inorder_iter_node = rbtree_inorder_iter_node->parent; \ 149 | continue; \ 150 | } \ 151 | \ 152 | rbtree_inorder_iter_node = rbtree_inorder_iter_node->parent; \ 153 | out_value = rbtree_inorder_iter_node->value; \ 154 | \ 155 | rb_travel_direction = rbtree_inorder_iter_node->right == NULL ? RBTREE_TRAVEL_UP : RBTREE_TRAVEL_RIGHT; \ 156 | break; \ 157 | } \ 158 | } 159 | 160 | 161 | #define rbtree_iter_end } } 162 | 163 | #endif -------------------------------------------------------------------------------- /include/generic_iterators/set_iterator.h: -------------------------------------------------------------------------------- 1 | #ifndef GENERIC_DATA_STRUCTURES_GENERIC_ITERATORS_SET_ITERATOR_H 2 | #define GENERIC_DATA_STRUCTURES_GENERIC_ITERATORS_SET_ITERATOR_H 3 | 4 | #define set_iter_start(set, out_key) \ 5 | for(int set_iter_i = 0; set_iter_i < (set)->capacity; set_iter_i++) { \ 6 | if(!(set)->cells[set_iter_i].active) \ 7 | continue; \ 8 | out_key = (set)->cells[set_iter_i].value; 9 | 10 | #define set_iter_end } 11 | 12 | #endif -------------------------------------------------------------------------------- /include/generic_iterators/trie_iterator.h: -------------------------------------------------------------------------------- 1 | #ifndef GENERIC_DATA_STRUCTURES_GENERIC_ITERATORS_TRIE_ITERATOR_H 2 | #define GENERIC_DATA_STRUCTURES_GENERIC_ITERATORS_TRIE_ITERATOR_H 3 | 4 | #include "../generic_trie.h" 5 | 6 | 7 | // Todo: 8 | // This non-deterministically tries to process the same leaf node 9 | // twice, but always sequentially. Without knowing the cause, 10 | // currently the band-aid fix is to keep track of the last processed 11 | // node and if it's equal to the current node, skip it. 12 | // It would be nice to figure out what the cause is. In order to make reading 13 | // the code easier, here is a non-obfiscated, commented version: 14 | 15 | // Some notes about the comments: 16 | // - node: Holds a character and children nodes. 17 | // The children are held in a list until ___TRIE_ARRAY_SIZE children 18 | // are added, at which point it switches to a map because that's 19 | // when the lookups become faster than a simple brute force through the 20 | // list. 21 | // - leaf node: A node whose character was the final letter in an added word. 22 | // - obfuscation: The local variables in the macro need to be obfuscated in order to not 23 | // override user variables from the outer scope. I decided to write the 24 | // comments on a non-obfuscated version in order to make maintaining it 25 | // easier. 26 | 27 | /* 28 | 29 | #define char_trie_iter_start(type_name, trie, out_value) 30 | { 31 | // We allocate the out_value. 32 | // It's size is set to the number of elements, which should 33 | // be the length of the longest string in the trie, 34 | // plus one for the null terminator. 35 | 36 | // word exists so we have a value that can be deterministically 37 | // be freed by trie_set_iter_end. 38 | void* word = out_value = calloc(trie->max_depth + 1, sizeof(trie->root->value)); 39 | int count = 0; 40 | int capacity = 4; 41 | 42 | // This is used to fix the aforementioned bug where a node tries 43 | // to be processed twice in a row. 44 | type_name ## Node* last = NULL; 45 | 46 | // Unfortunately the only way to iterate with a macro like this is to use 47 | // a stack (I think. I you have a better solution, please share). 48 | // The IterState struct keeps track of the array index in either the nodes 49 | // local array or the maps buffer, in addition to the node itself. 50 | struct type_name ## IterState* stack = malloc(sizeof(struct type_name ## IterState) * capacity); 51 | 52 | // Start with the root node at the first index. 53 | stack[count++] = (struct type_name ## IterState){ trie->root, 0 }; 54 | 55 | // Keep iterating while there's still a node on the stack. 56 | while(count > 0) { 57 | // Get the node to process from the end of the stack. 58 | struct type_name ## IterState* state = &stack[count - 1]; 59 | 60 | // Ignoring the root node, set the nodes character in the 61 | // out_value array. 62 | if(___TRIE_DEPTH(state->node->depth) != 0) { 63 | out_value[___TRIE_DEPTH(state->node->depth) - 1] = state->node->value; 64 | } 65 | 66 | // Keep track if a child node was found. 67 | // If a child node is found, push it onto the stack, 68 | // increment the states index so it isn't processed again, 69 | // and go to the next iteration. 70 | // Otherwise, this nodes children have all been processed, 71 | // so it can be processed itself if it's a leaf node. 72 | bool found = false; 73 | if(state->node->count <= ___TRIE_ARRAY_SIZE) { 74 | // If the node is exclusively using the array, 75 | // just make sure the current state index 76 | // is less than the number of children. 77 | // If so, there are still children. Otherwise 78 | // process the current node as there are no more 79 | // children. 80 | 81 | if(state->index < state->node->count) { 82 | found = true; 83 | 84 | // Increase the stack size if the capacity has been reached. 85 | if(count == capacity) { 86 | capacity *= 2; 87 | stack = realloc(stack, sizeof(*stack) * capacity); 88 | } 89 | 90 | // Push the child onto the stack, and increment the current states index 91 | // so the child isn't processed again. 92 | stack[count++] = (struct type_name ## IterState){ &state->node->array[state->index], 0 }; 93 | state->index++; 94 | } 95 | } else { 96 | 97 | // If the node is using the map, we iterate through the maps 98 | // internal buffer. This relies on implementation details of the 99 | // map, which is dangerous. While the states index is less than 100 | // the maps total capacity, it's possible there are still children. 101 | // Otherwise process the current node. 102 | for(; state->index < state->node->map->capacity; state->index++) { 103 | 104 | // Uses an implementation detail of the map to see if 105 | // a cell holds actual data. Skip it if there is no data. 106 | // If there was data, a child has been found. 107 | if(!state->node->map->cells[state->index].active) 108 | continue; 109 | 110 | found = true; 111 | 112 | // Increase the stack size if the capacity has been reached. 113 | if(count == capacity) { 114 | capacity *= 2; 115 | stack = realloc(stack, sizeof(*stack) * capacity); 116 | } 117 | stack[count++] = (struct type_name ## IterState){ state->node->map->cells[state->index].value, 0 }; 118 | state->index++; 119 | break; 120 | } 121 | } 122 | 123 | // If there was a child, continue on to the next iteration. 124 | if(found) 125 | continue; 126 | 127 | // If the only node left is the root node, 128 | // we're done iterating. Break out of the loop. 129 | if(___TRIE_DEPTH(state->node->depth) == 0) 130 | break; 131 | 132 | // Pop the current node off of the stack. 133 | count--; 134 | 135 | // If the current node isn't a leaf node, then it doesn't 136 | // need to be processed. 137 | if((state->node->depth & ___TRIE_NODE_IS_LEAF) == 0) { 138 | continue; 139 | } 140 | 141 | // The band-aid fix for the aforementioned bug. 142 | // If the current node is the same as the last processed node, 143 | // skip it. 144 | if(state->node == last) 145 | continue; 146 | 147 | last = state->node; 148 | 149 | // Make sure the out_value is NULL terminated at the correct position. 150 | out_value[___TRIE_DEPTH(state->node->depth)] = 0; 151 | 152 | */ 153 | 154 | // Obviously this macro is just a monster. It should really be used sparingly. 155 | 156 | // IF YOU MAKE CHANGES TO THIS, PLEASE UPDATE THE NON-OBFISCATED VERSION AS WELL! 157 | // You don't need to comment it (though that would be appreciated), but at least make 158 | // sure the two forms match. 159 | 160 | #define trie_set_iter_start(type_name, trie, out_value) \ 161 | { \ 162 | void* ___trie_iter_value = out_value = calloc((trie)->max_depth + 1, sizeof((trie)->root->value)); \ 163 | assert(out_value); \ 164 | int ___iter_trie_count = 0; \ 165 | int ___iter_trie_capacity = 4; \ 166 | type_name ## Node* ___iter_trie_last = NULL; \ 167 | struct type_name ## IterState* ___iter_trie_stack = malloc(sizeof(struct type_name ## IterState) * ___iter_trie_capacity); \ 168 | assert(___iter_trie_stack); \ 169 | ___iter_trie_stack[___iter_trie_count++] = (struct type_name ## IterState){ (trie)->root, 0 }; \ 170 | while(___iter_trie_count > 0) { \ 171 | struct type_name ## IterState* ___trie_iter_state = &___iter_trie_stack[___iter_trie_count - 1]; \ 172 | if(___TRIE_DEPTH(___trie_iter_state->node->depth) != 0) { \ 173 | out_value[___TRIE_DEPTH(___trie_iter_state->node->depth) - 1] = ___trie_iter_state->node->value; \ 174 | } \ 175 | bool ___iter_trie_found = false; \ 176 | if(___trie_iter_state->node->count <= ___TRIE_ARRAY_SIZE) { \ 177 | if(___trie_iter_state->index < ___trie_iter_state->node->count) { \ 178 | ___iter_trie_found = true; \ 179 | if(___iter_trie_count == ___iter_trie_capacity) { \ 180 | ___iter_trie_capacity *= 2; \ 181 | ___iter_trie_stack = realloc(___iter_trie_stack, sizeof(*___iter_trie_stack) * ___iter_trie_capacity); \ 182 | assert(___iter_trie_stack); \ 183 | } \ 184 | ___iter_trie_stack[___iter_trie_count++] = (struct type_name ## IterState){ &___trie_iter_state->node->array[___trie_iter_state->index], 0 }; \ 185 | ___trie_iter_state->index++; \ 186 | } \ 187 | } else { \ 188 | for(; ___trie_iter_state->index < ___trie_iter_state->node->map->capacity; ___trie_iter_state->index++) { \ 189 | if(!___trie_iter_state->node->map->cells[___trie_iter_state->index].active) \ 190 | continue; \ 191 | ___iter_trie_found = true; \ 192 | if(___iter_trie_count == ___iter_trie_capacity) { \ 193 | ___iter_trie_capacity *= 2; \ 194 | ___iter_trie_stack = realloc(___iter_trie_stack, sizeof(*___iter_trie_stack) * ___iter_trie_capacity); \ 195 | assert(___iter_trie_stack); \ 196 | } \ 197 | ___iter_trie_stack[___iter_trie_count++] = (struct type_name ## IterState){ ___trie_iter_state->node->map->cells[___trie_iter_state->index].value, 0 }; \ 198 | ___trie_iter_state->index++; \ 199 | break; \ 200 | } \ 201 | } \ 202 | \ 203 | if(___iter_trie_found) \ 204 | continue; \ 205 | \ 206 | if(___TRIE_DEPTH(___trie_iter_state->node->depth) == 0) \ 207 | break; \ 208 | \ 209 | ___iter_trie_count--; \ 210 | \ 211 | if((___trie_iter_state->node->depth & ___TRIE_NODE_IS_LEAF) == 0) { \ 212 | continue; \ 213 | } \ 214 | \ 215 | if(___trie_iter_state->node == ___iter_trie_last) \ 216 | continue; \ 217 | \ 218 | ___iter_trie_last = ___trie_iter_state->node; \ 219 | \ 220 | out_value[___TRIE_DEPTH(___trie_iter_state->node->depth)] = 0; \ 221 | 222 | 223 | #define trie_set_iter_end } free(___trie_iter_value); free(___iter_trie_stack); } 224 | 225 | 226 | #define trie_map_iter_key_start(type_name, trie, out_key) \ 227 | { \ 228 | void* ___trie_iter_key = out_key = calloc((trie)->max_depth + 1, sizeof((trie)->root->key)); \ 229 | assert(out_key); \ 230 | int ___iter_trie_count = 0; \ 231 | int ___iter_trie_capacity = 4; \ 232 | type_name ## Node* ___iter_trie_last = NULL; \ 233 | struct type_name ## IterState* ___iter_trie_stack = malloc(sizeof(struct type_name ## IterState) * ___iter_trie_capacity); \ 234 | assert(___iter_trie_stack); \ 235 | ___iter_trie_stack[___iter_trie_count++] = (struct type_name ## IterState){ (trie)->root, 0 }; \ 236 | while(___iter_trie_count > 0) { \ 237 | struct type_name ## IterState* ___trie_iter_state = &___iter_trie_stack[___iter_trie_count - 1]; \ 238 | if(___TRIE_DEPTH(___trie_iter_state->node->depth) != 0) { \ 239 | out_key[___TRIE_DEPTH(___trie_iter_state->node->depth) - 1] = ___trie_iter_state->node->key; \ 240 | } \ 241 | bool ___iter_trie_found = false; \ 242 | if(___trie_iter_state->node->count <= ___TRIE_ARRAY_SIZE) { \ 243 | if(___trie_iter_state->index < ___trie_iter_state->node->count) { \ 244 | ___iter_trie_found = true; \ 245 | if(___iter_trie_count == ___iter_trie_capacity) { \ 246 | ___iter_trie_capacity *= 2; \ 247 | ___iter_trie_stack = realloc(___iter_trie_stack, sizeof(*___iter_trie_stack) * ___iter_trie_capacity); \ 248 | assert(___iter_trie_stack); \ 249 | } \ 250 | ___iter_trie_stack[___iter_trie_count++] = (struct type_name ## IterState){ &___trie_iter_state->node->array[___trie_iter_state->index], 0 }; \ 251 | ___trie_iter_state->index++; \ 252 | } \ 253 | } else { \ 254 | for(; ___trie_iter_state->index < ___trie_iter_state->node->map->capacity; ___trie_iter_state->index++) { \ 255 | if(!___trie_iter_state->node->map->cells[___trie_iter_state->index].active) \ 256 | continue; \ 257 | ___iter_trie_found = true; \ 258 | if(___iter_trie_count == ___iter_trie_capacity) { \ 259 | ___iter_trie_capacity *= 2; \ 260 | ___iter_trie_stack = realloc(___iter_trie_stack, sizeof(*___iter_trie_stack) * ___iter_trie_capacity); \ 261 | assert(___iter_trie_stack); \ 262 | } \ 263 | ___iter_trie_stack[___iter_trie_count++] = (struct type_name ## IterState){ ___trie_iter_state->node->map->cells[___trie_iter_state->index].value, 0 }; \ 264 | ___trie_iter_state->index++; \ 265 | break; \ 266 | } \ 267 | } \ 268 | \ 269 | if(___iter_trie_found) \ 270 | continue; \ 271 | \ 272 | if(___TRIE_DEPTH(___trie_iter_state->node->depth) == 0) \ 273 | break; \ 274 | \ 275 | ___iter_trie_count--; \ 276 | \ 277 | if((___trie_iter_state->node->depth & ___TRIE_NODE_IS_LEAF) == 0) { \ 278 | continue; \ 279 | } \ 280 | \ 281 | if(___trie_iter_state->node == ___iter_trie_last) \ 282 | continue; \ 283 | \ 284 | ___iter_trie_last = ___trie_iter_state->node; \ 285 | \ 286 | out_key[___TRIE_DEPTH(___trie_iter_state->node->depth)] = 0; \ 287 | 288 | 289 | #define trie_map_iter_start(type_name, trie, out_key, out_value) \ 290 | trie_map_iter_key_start(type_name, trie, out_key) \ 291 | out_value = ___trie_iter_state->node->value; \ 292 | 293 | 294 | #define trie_map_iter_value_start(type_name, trie, out_value) \ 295 | { \ 296 | void* ___trie_iter_key = NULL; \ 297 | int ___iter_trie_count = 0; \ 298 | int ___iter_trie_capacity = 4; \ 299 | type_name ## Node* ___iter_trie_last = NULL; \ 300 | struct type_name ## IterState* ___iter_trie_stack = malloc(sizeof(struct type_name ## IterState) * ___iter_trie_capacity); \ 301 | assert(___iter_trie_stack); \ 302 | ___iter_trie_stack[___iter_trie_count++] = (struct type_name ## IterState){ (trie)->root, 0 }; \ 303 | while(___iter_trie_count > 0) { \ 304 | struct type_name ## IterState* ___trie_iter_state = &___iter_trie_stack[___iter_trie_count - 1]; \ 305 | bool ___iter_trie_found = false; \ 306 | if(___trie_iter_state->node->count <= ___TRIE_ARRAY_SIZE) { \ 307 | if(___trie_iter_state->index < ___trie_iter_state->node->count) { \ 308 | ___iter_trie_found = true; \ 309 | if(___iter_trie_count == ___iter_trie_capacity) { \ 310 | ___iter_trie_capacity *= 2; \ 311 | ___iter_trie_stack = realloc(___iter_trie_stack, sizeof(*___iter_trie_stack) * ___iter_trie_capacity); \ 312 | assert(___iter_trie_stack); \ 313 | } \ 314 | ___iter_trie_stack[___iter_trie_count++] = (struct type_name ## IterState){ &___trie_iter_state->node->array[___trie_iter_state->index], 0 }; \ 315 | ___trie_iter_state->index++; \ 316 | } \ 317 | } else { \ 318 | for(; ___trie_iter_state->index < ___trie_iter_state->node->map->capacity; ___trie_iter_state->index++) { \ 319 | if(!___trie_iter_state->node->map->cells[___trie_iter_state->index].active) \ 320 | continue; \ 321 | ___iter_trie_found = true; \ 322 | if(___iter_trie_count == ___iter_trie_capacity) { \ 323 | ___iter_trie_capacity *= 2; \ 324 | ___iter_trie_stack = realloc(___iter_trie_stack, sizeof(*___iter_trie_stack) * ___iter_trie_capacity); \ 325 | assert(___iter_trie_stack); \ 326 | } \ 327 | ___iter_trie_stack[___iter_trie_count++] = (struct type_name ## IterState){ ___trie_iter_state->node->map->cells[___trie_iter_state->index].value, 0 }; \ 328 | ___trie_iter_state->index++; \ 329 | break; \ 330 | } \ 331 | } \ 332 | \ 333 | if(___iter_trie_found) \ 334 | continue; \ 335 | \ 336 | if(___TRIE_DEPTH(___trie_iter_state->node->depth) == 0) \ 337 | break; \ 338 | \ 339 | ___iter_trie_count--; \ 340 | \ 341 | if((___trie_iter_state->node->depth & ___TRIE_NODE_IS_LEAF) == 0) { \ 342 | continue; \ 343 | } \ 344 | \ 345 | if(___trie_iter_state->node == ___iter_trie_last) \ 346 | continue; \ 347 | \ 348 | ___iter_trie_last = ___trie_iter_state->node; \ 349 | \ 350 | out_value = ___trie_iter_state->node->value; \ 351 | 352 | 353 | #define trie_map_iter_end } free(___trie_iter_key); free(___iter_trie_stack); } 354 | 355 | #endif -------------------------------------------------------------------------------- /include/generic_list.h: -------------------------------------------------------------------------------- 1 | #ifndef GENERIC_DATA_STRUCTURES_LIST_H 2 | #define GENERIC_DATA_STRUCTURES_LIST_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | // Todo: 11 | // bool add_range(type_name* list, value_type* values, unsigned int count); 12 | // bool insert_range(type_name* list, unsigned int index, value_type* values, unsigned int count); 13 | 14 | #define LIST_DEFINE_H(type_name, function_prefix, value_type) \ 15 | typedef struct type_name { \ 16 | value_type* buffer; \ 17 | unsigned int count; \ 18 | unsigned int capacity; \ 19 | } type_name; \ 20 | \ 21 | type_name* function_prefix ## _create(void); \ 22 | bool function_prefix ## _init(type_name* list); \ 23 | bool function_prefix ## _init_capacity(type_name* list, unsigned int capacity); \ 24 | bool function_prefix ## _add(type_name* list, value_type value); \ 25 | bool function_prefix ## _insert(type_name* list, unsigned int index, value_type value); \ 26 | \ 27 | static inline void function_prefix ## _clear(type_name* list) { list->count = 0; } \ 28 | \ 29 | static inline unsigned int function_prefix ## _count(type_name* list) { return list->count; } \ 30 | \ 31 | static inline void function_prefix ## _free_resources(type_name* list) { free(list->buffer); } \ 32 | \ 33 | static inline void function_prefix ## _free(type_name* list) { free(list->buffer); free(list); } \ 34 | \ 35 | static inline value_type function_prefix ## _get(type_name* list, unsigned int index) { \ 36 | assert(index < list->count); \ 37 | return list->buffer[index]; \ 38 | } \ 39 | \ 40 | static inline void function_prefix ## _set(type_name* list, unsigned int index, value_type value) { \ 41 | assert(index <= list->count); \ 42 | if(index == list->count) \ 43 | function_prefix ## _add(list, value); \ 44 | else \ 45 | list->buffer[index] = value; \ 46 | } \ 47 | \ 48 | static inline void function_prefix ## _remove(type_name* list, unsigned int index) { \ 49 | assert(index < list->count); \ 50 | if(index == --list->count) \ 51 | return; \ 52 | else \ 53 | memmove(list->buffer + index, list->buffer + index + 1, (list->count - index) * sizeof(value_type)); \ 54 | } \ 55 | \ 56 | static inline value_type function_prefix ## _peek(type_name* list) { \ 57 | assert(list->count); \ 58 | return list->buffer[list->count - 1]; \ 59 | } \ 60 | \ 61 | static inline value_type function_prefix ## _pop(type_name* list) { \ 62 | assert(list->count); \ 63 | return list->buffer[--list->count]; \ 64 | } \ 65 | \ 66 | static inline void function_prefix ## _shrink_to_fit(type_name* list) { \ 67 | list->buffer = realloc(list->buffer, (list->count == 0 ? 1 : list->count) * sizeof(value_type)); \ 68 | list->capacity = list->count == 0 ? 1 : list->count; \ 69 | } \ 70 | 71 | 72 | #define LIST_DEFINE_C(type_name, function_prefix, value_type) \ 73 | type_name* function_prefix ## _create(void) { \ 74 | type_name* list = malloc(sizeof(type_name)); \ 75 | if(!list) \ 76 | return list; \ 77 | if(!function_prefix ## _init(list)) { \ 78 | free(list); \ 79 | return NULL; \ 80 | } \ 81 | return list; \ 82 | } \ 83 | \ 84 | bool function_prefix ## _init(type_name* list) { \ 85 | list->capacity = 4; \ 86 | list->count = 0; \ 87 | return (list->buffer = malloc(4 * sizeof(value_type))) != NULL; \ 88 | } \ 89 | \ 90 | bool function_prefix ## _init_capacity(type_name* list, unsigned int capacity) { \ 91 | assert(capacity); \ 92 | list->capacity = capacity; \ 93 | list->count = 0; \ 94 | return (list->buffer = malloc(capacity * sizeof(value_type))) != NULL; \ 95 | } \ 96 | \ 97 | bool function_prefix ## _add(type_name* list, value_type value) { \ 98 | if(list->count == list->capacity) { \ 99 | list->capacity *= 2; \ 100 | value_type* buffer = realloc(list->buffer, list->capacity * sizeof(value_type)); \ 101 | if(!buffer) \ 102 | return false; \ 103 | list->buffer = buffer; \ 104 | } \ 105 | list->buffer[list->count++] = value; \ 106 | return true; \ 107 | } \ 108 | \ 109 | bool function_prefix ## _insert(type_name* list, unsigned int index, value_type value) { \ 110 | if(index > list->count) return false; \ 111 | if(index == list->count) \ 112 | return function_prefix ## _add(list, value); \ 113 | if(list->count == list->capacity) { \ 114 | list->capacity *= 2; \ 115 | value_type* buffer = realloc(list->buffer, list->capacity * sizeof(value_type)); \ 116 | if(!buffer) \ 117 | return false; \ 118 | list->buffer = buffer; \ 119 | } \ 120 | memmove(list->buffer + index + 1, list->buffer + index, (list->count++ - index) * sizeof(value_type)); \ 121 | list->buffer[index] = value; \ 122 | return true; \ 123 | } \ 124 | 125 | 126 | 127 | #endif -------------------------------------------------------------------------------- /include/generic_map.h: -------------------------------------------------------------------------------- 1 | #ifndef GENERIC_DATA_STRUCTURES_MAP_H 2 | #define GENERIC_DATA_STRUCTURES_MAP_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "generic_hash_utils.h" 11 | 12 | #define MAP_DEFINE_H(type_name, function_prefix, key_type, value_type) \ 13 | typedef struct type_name ## Cell { \ 14 | key_type key; \ 15 | value_type value; \ 16 | uint32_t hash; \ 17 | bool active; \ 18 | } type_name ## Cell; \ 19 | \ 20 | typedef struct { \ 21 | type_name ## Cell* cells; \ 22 | uint32_t count; \ 23 | uint32_t capacity; \ 24 | uint32_t load_factor; \ 25 | uint32_t shift; \ 26 | } type_name;\ 27 | \ 28 | static inline uint32_t function_prefix ## _count(type_name* map) { return map->count; } \ 29 | static inline uint32_t function_prefix ## _capacity(type_name* map) { return map->load_factor; } \ 30 | static inline uint32_t function_prefix ## _allocated(type_name* map) { return map->capacity; } \ 31 | static inline void function_prefix ## _free(type_name* map) { free(map->cells); free(map); } \ 32 | static inline void function_prefix ## _free_resources(type_name* map) { free(map->cells); } \ 33 | \ 34 | type_name* function_prefix ## _create(void); \ 35 | bool function_prefix ## _init(type_name* map); \ 36 | bool function_prefix ## _add(type_name* map, key_type key, value_type value); \ 37 | void function_prefix ## _set(type_name* map, key_type key, value_type value); \ 38 | value_type function_prefix ## _get(type_name* map, key_type key); \ 39 | bool function_prefix ## _try_get(type_name* map, key_type key, value_type* out_value); \ 40 | bool function_prefix ## _remove(type_name* map, key_type key); \ 41 | bool function_prefix ## _get_and_remove(type_name* map, key_type key, key_type* out_key, value_type* out_value); \ 42 | void function_prefix ## _clear(type_name* map, bool reset_capacity); \ 43 | 44 | 45 | // TODO: Add more safety in case the map fails to resize. 46 | 47 | #define MAP_DEFINE_C(type_name, function_prefix, key_type, value_type, hash_fn, compare_fn) \ 48 | type_name* function_prefix ## _create(void) { \ 49 | type_name* map = malloc(sizeof(type_name)); \ 50 | if(!map) \ 51 | return NULL; \ 52 | if(!function_prefix ## _init(map)) { \ 53 | free(map); \ 54 | return NULL; \ 55 | } \ 56 | return map; \ 57 | } \ 58 | \ 59 | bool function_prefix ## _init(type_name* map) { \ 60 | map->shift = 29; \ 61 | map->capacity = 8; \ 62 | map->count = 0; \ 63 | map->load_factor = 4; \ 64 | return (map->cells = calloc(8, sizeof(type_name ## Cell))) != NULL; \ 65 | } \ 66 | \ 67 | static void function_prefix ## _resize(type_name* map) { \ 68 | int capacity = map->load_factor = map->capacity; \ 69 | map->capacity = 1 << (32 - (--map->shift)); \ 70 | type_name ## Cell* old = map->cells; \ 71 | type_name ## Cell* new = calloc(map->capacity, sizeof(type_name ## Cell)); \ 72 | assert(new); \ 73 | \ 74 | for(int i = 0; i < capacity; i++) { \ 75 | if(old[i].active) { \ 76 | uint32_t cell = ___fib_hash(old[i].hash, map->shift); \ 77 | while(new[cell].active) { \ 78 | cell = (cell + 1) % map->capacity; \ 79 | } \ 80 | new[cell] = old[i]; \ 81 | } \ 82 | } \ 83 | free(old); \ 84 | map->cells = new; \ 85 | } \ 86 | \ 87 | bool function_prefix ## _add(type_name* map, key_type key, value_type value) { \ 88 | uint32_t hash, cell; \ 89 | \ 90 | if(map->count == map->load_factor) \ 91 | function_prefix ## _resize(map); \ 92 | \ 93 | hash = hash_fn(key); \ 94 | cell = ___fib_hash(hash, map->shift); \ 95 | \ 96 | while(true) { \ 97 | if(!map->cells[cell].active) { \ 98 | map->cells[cell].active = true; \ 99 | map->cells[cell].key = key; \ 100 | map->cells[cell].value = value; \ 101 | map->cells[cell].hash = hash; \ 102 | map->count++; \ 103 | return true; \ 104 | } else if(map->cells[cell].hash == hash && compare_fn(map->cells[cell].key, key) == 0) \ 105 | return false; \ 106 | if(++cell == map->capacity) \ 107 | cell = 0; \ 108 | } \ 109 | \ 110 | return false; \ 111 | } \ 112 | \ 113 | void function_prefix ## _set(type_name* map, key_type key, value_type value) { \ 114 | uint32_t hash, cell; \ 115 | \ 116 | if(map->count == map->load_factor) \ 117 | function_prefix ## _resize(map); \ 118 | \ 119 | hash = hash_fn(key); \ 120 | cell = ___fib_hash(hash, map->shift); \ 121 | \ 122 | while(true) { \ 123 | if(!map->cells[cell].active) { \ 124 | map->cells[cell].active = true; \ 125 | map->cells[cell].key = key; \ 126 | map->cells[cell].value = value; \ 127 | map->cells[cell].hash = hash; \ 128 | map->count++; \ 129 | break; \ 130 | } else if(map->cells[cell].hash == hash && compare_fn(map->cells[cell].key, key) == 0) { \ 131 | map->cells[cell].value = value; \ 132 | break; \ 133 | } \ 134 | if(++cell == map->capacity) \ 135 | cell = 0; \ 136 | } \ 137 | } \ 138 | \ 139 | static inline bool function_prefix ## _find_cell(type_name* map, key_type key, uint32_t* out_hash, uint32_t* out_cell) { \ 140 | uint32_t hash, cell; \ 141 | hash = hash_fn(key); \ 142 | cell = ___fib_hash(hash, map->shift); \ 143 | \ 144 | while(true) { \ 145 | if(!map->cells[cell].active) \ 146 | return false; \ 147 | \ 148 | if(map->cells[cell].hash == hash && compare_fn(map->cells[cell].key, key) == 0) { \ 149 | *out_hash = hash; \ 150 | *out_cell = cell; \ 151 | return true; \ 152 | } \ 153 | \ 154 | cell = (cell + 1) % map->capacity; \ 155 | } \ 156 | } \ 157 | \ 158 | value_type function_prefix ## _get(type_name* map, key_type key) { \ 159 | uint32_t cell, hash; \ 160 | if(function_prefix ## _find_cell(map, key, &hash, &cell)) \ 161 | return map->cells[cell].value; \ 162 | else \ 163 | return (value_type){0}; \ 164 | } \ 165 | \ 166 | bool function_prefix ## _try_get(type_name* map, key_type key, value_type* out_value) { \ 167 | uint32_t cell, hash; \ 168 | if(function_prefix ## _find_cell(map, key, &hash, &cell)) { \ 169 | if(out_value != NULL) \ 170 | *out_value = map->cells[cell].value; \ 171 | return true; \ 172 | } else { \ 173 | return false; \ 174 | } \ 175 | } \ 176 | \ 177 | static inline void function_prefix ## _replace_cell(type_name* map, uint32_t cell, uint32_t hash) { \ 178 | uint32_t start = cell; \ 179 | \ 180 | while(true) { \ 181 | cell = (cell + 1) % map->capacity; \ 182 | \ 183 | if(!map->cells[cell].active) \ 184 | break; \ 185 | \ 186 | uint32_t preferred_cell = ___fib_hash(map->cells[cell].hash, map->shift); \ 187 | if(preferred_cell <= start || preferred_cell > cell) { \ 188 | map->cells[start] = map->cells[cell]; \ 189 | start = cell; \ 190 | } \ 191 | } \ 192 | map->cells[start].active = false; \ 193 | } \ 194 | \ 195 | bool function_prefix ## _remove(type_name* map, key_type key) { \ 196 | uint32_t cell, hash; \ 197 | if(!function_prefix ## _find_cell(map, key, &hash, &cell)) \ 198 | return false; \ 199 | \ 200 | function_prefix ## _replace_cell(map, cell, hash); \ 201 | map->count--; \ 202 | return true; \ 203 | } \ 204 | \ 205 | bool function_prefix ## _get_and_remove(type_name* map, key_type key, key_type* out_key, value_type* out_value) { \ 206 | uint32_t cell, hash; \ 207 | if(!function_prefix ## _find_cell(map, key, &hash, &cell)) \ 208 | return false; \ 209 | \ 210 | if(out_key != NULL) \ 211 | *out_key = map->cells[cell].key; \ 212 | if(out_value != NULL) \ 213 | *out_value = map->cells[cell].value; \ 214 | \ 215 | function_prefix ## _replace_cell(map, cell, hash); \ 216 | map->count--; \ 217 | return true; \ 218 | } \ 219 | \ 220 | void function_prefix ## _clear(type_name* map, bool reset_capacity) { \ 221 | if(reset_capacity) { \ 222 | free(map->cells); \ 223 | function_prefix ## _init(map); \ 224 | } else { \ 225 | map->count = 0; \ 226 | for(uint32_t i = 0; i < map->capacity; i++) \ 227 | map->cells[i].active = false; \ 228 | } \ 229 | } \ 230 | 231 | 232 | #endif //GENERIC_MAP_GENERIC_MAP_H -------------------------------------------------------------------------------- /include/generic_option.h: -------------------------------------------------------------------------------- 1 | #ifndef GENERIC_DATA_STRUCTURES_GENERIC_OPTIONAL_H 2 | #define GENERIC_DATA_STRUCTURES_GENERIC_OPTIONAL_H 3 | 4 | #include 5 | #include 6 | 7 | #define OPTION_DEFINE_H(type_name, function_prefix, value_type) \ 8 | typedef struct type_name { \ 9 | value_type value; \ 10 | bool has_value; \ 11 | } type_name; \ 12 | \ 13 | static inline type_name function_prefix ## _make(value_type value) { return (type_name){ value, true }; } \ 14 | static inline type_name function_prefix ## _default(void) { return (type_name){ .has_value = false }; } \ 15 | static inline bool function_prefix ## _has_value(type_name optional) { return optional.has_value; } \ 16 | static inline value_type function_prefix ## _value(type_name optional) { assert(optional.has_value); return optional.value; } \ 17 | static inline value_type function_prefix ## _value_or_default(type_name optional) { return optional.value; } \ 18 | 19 | 20 | #define gds_option_make(type_name, value) ((type_name){ value, true }) 21 | #define gds_option_default(type_name) ((type_name){ .has_value = false }) 22 | #define gds_option_has_value(optional) ((optional).has_value) 23 | #define gds_option_value(optional) (assert((optional).has_value), (optional).value) 24 | #define gds_option_value_or_default(optional) ((optional).value) 25 | 26 | #endif -------------------------------------------------------------------------------- /include/generic_pool.h: -------------------------------------------------------------------------------- 1 | #ifndef GENERIC_DATA_STRUCTURES_GENERIC_POOL_H 2 | #define GENERIC_DATA_STRUCTURES_GENERIC_POOL_H 3 | 4 | /* 5 | * Defines a special type of allocator that creates objects 6 | * with the intent of reusing them in the future. 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | 13 | #define POOL_DEFINE_H(type_name, function_prefix, value_type) \ 14 | struct type_name ## Node { \ 15 | value_type* buffer; \ 16 | struct type_name ## Node* next; \ 17 | }; \ 18 | \ 19 | typedef struct type_name { \ 20 | struct type_name ## Node* node; \ 21 | value_type** open; \ 22 | unsigned int open_count; \ 23 | unsigned int open_capacity; \ 24 | unsigned int next; \ 25 | unsigned int node_capacity; \ 26 | unsigned int total; \ 27 | } type_name; \ 28 | \ 29 | type_name* function_prefix ## _create(void); \ 30 | bool function_prefix ## _init(type_name* pool); \ 31 | void function_prefix ## _free(type_name* pool); \ 32 | void function_prefix ## _free_resources(type_name* pool); \ 33 | \ 34 | value_type* function_prefix ## _get(type_name* pool); \ 35 | bool function_prefix ## _release(type_name* pool, value_type* value); \ 36 | 37 | #ifndef POOL_SKIP_RELEASE_ASSERT 38 | 39 | // This verifies that a released pointer is actually owned by the pool, 40 | // but is not actually a necessary step in the release process, 41 | // so it can optionally be optionally be defined away. 42 | 43 | #define ___POOL_RELEASE_ASSERT(node_type) \ 44 | long long buffer_size = pool->total; \ 45 | node_type node = pool->node; \ 46 | \ 47 | while(node != NULL) { \ 48 | ptrdiff_t offset = value - node->buffer; \ 49 | if(offset >= 0 && offset < buffer_size) \ 50 | break; \ 51 | \ 52 | node = node->next; \ 53 | buffer_size >>= 1; \ 54 | } \ 55 | \ 56 | if(!node) \ 57 | return false; 58 | 59 | #else 60 | 61 | #define ___POOL_RELEASE_ASSERT(node_type) 62 | 63 | #endif 64 | 65 | #define POOL_DEFINE_C(type_name, function_prefix, value_type, init_fn, free_resources_fn) \ 66 | type_name* function_prefix ## _create(void) { \ 67 | type_name* pool = malloc(sizeof(*pool)); \ 68 | if(!pool) \ 69 | return NULL; \ 70 | \ 71 | if(!function_prefix ## _init(pool)) { \ 72 | free(pool); \ 73 | return NULL; \ 74 | } \ 75 | \ 76 | return pool; \ 77 | } \ 78 | \ 79 | bool function_prefix ## _init(type_name* pool) { \ 80 | struct type_name ## Node* node = malloc(sizeof(*node)); \ 81 | if(!node) \ 82 | return false; \ 83 | node->buffer = malloc(16 * sizeof(*node->buffer)); \ 84 | if(!node->buffer) { \ 85 | free(node); \ 86 | return false; \ 87 | } \ 88 | node->next = NULL; \ 89 | pool->node = node; \ 90 | pool->open = NULL; \ 91 | pool->open_count = 0; \ 92 | pool->open_capacity = 0; \ 93 | pool->next = 0; \ 94 | pool->node_capacity = 16; \ 95 | pool->total = 16; \ 96 | return true; \ 97 | } \ 98 | \ 99 | void function_prefix ## _free(type_name* pool) { \ 100 | function_prefix ## _free_resources(pool); \ 101 | free(pool); \ 102 | } \ 103 | \ 104 | void function_prefix ## _free_resources(type_name* pool) { \ 105 | struct type_name ## Node* node = pool->node; \ 106 | \ 107 | while(node != NULL) { \ 108 | struct type_name ## Node* next = node->next; \ 109 | free(node->buffer); \ 110 | free(node); \ 111 | node = next; \ 112 | } \ 113 | \ 114 | free(pool->open); \ 115 | } \ 116 | \ 117 | value_type* function_prefix ## _get(type_name* pool) { \ 118 | value_type* result; \ 119 | if(pool->open_count == 0) { \ 120 | if(pool->next == pool->node_capacity) { \ 121 | struct type_name ## Node* node = malloc(sizeof(*node)); \ 122 | if(!node) \ 123 | return NULL; \ 124 | \ 125 | node->buffer = malloc(pool->total * sizeof(*node->buffer)); \ 126 | if(!node->buffer) { \ 127 | free(node); \ 128 | return NULL; \ 129 | } \ 130 | \ 131 | node->next = pool->node; \ 132 | \ 133 | pool->node_capacity = pool->total; \ 134 | pool->total *= 2; \ 135 | pool->node = node; \ 136 | pool->next = 0; \ 137 | } \ 138 | \ 139 | result = &pool->node->buffer[pool->next++]; \ 140 | } else { \ 141 | result = pool->open[--pool->open_count]; \ 142 | } \ 143 | \ 144 | init_fn(result); \ 145 | return result; \ 146 | } \ 147 | \ 148 | bool function_prefix ## _release(type_name* pool, value_type* value) { \ 149 | ___POOL_RELEASE_ASSERT(struct type_name ## Node*) \ 150 | \ 151 | if(pool->open_count == pool->open_capacity) { \ 152 | unsigned int capacity = pool->open_capacity; \ 153 | capacity = capacity == 0 ? 4 : capacity * 2; \ 154 | void* buffer = realloc(pool->open, capacity * sizeof(*pool->open)); \ 155 | if(!buffer) \ 156 | return false; \ 157 | \ 158 | pool->open_capacity = capacity; \ 159 | pool->open = buffer; \ 160 | } \ 161 | \ 162 | pool->open[pool->open_count++] = value; \ 163 | \ 164 | free_resources_fn(value); \ 165 | return true; \ 166 | } \ 167 | 168 | 169 | // This is a simpler implementation that allocates new objects 170 | // on the fly rather than batching them. 171 | // Needs testing to see if/when it's faster before switching implmentations. 172 | 173 | 174 | // #define POOL_DEFINE_H(type_name, function_prefix, value_type) \ 175 | // typedef struct type_name { \ 176 | // value_type** buffer; \ 177 | // unsigned int pool_count; \ 178 | // unsigned int pool_capacity; \ 179 | // } type_name; \ 180 | // 181 | // 182 | // #define POOL_DEFINE_C(type_name, function_prefix, value_type, init_fn, free_resources_fn) \ 183 | // value_type* function_prefix ## _get(type_name* pool) { \ 184 | // value_type* result; \ 185 | // if(pool->pool_count == 0) \ 186 | // result = malloc(sizeof(*result)); \ 187 | // else \ 188 | // result = buffer[--pool->pool_count]; \ 189 | // \ 190 | // init_fn(result); \ 191 | // return result; \ 192 | // } \ 193 | // \ 194 | // bool function_prefix ## _release(type_name* pool, value_type* value) { \ 195 | // if(pool->pool_count == pool->pool_capacity) { \ 196 | // unsigned int capacity = pool->capacity == 0 ? 4 : pool->capacity * 2; \ 197 | // void* buffer = realloc(pool->buffer, capacity); \ 198 | // if(!buffer) \ 199 | // return false; \ 200 | // \ 201 | // pool->buffer = buffer; \ 202 | // pool->capacity = capacity; \ 203 | // } \ 204 | // \ 205 | // pool->buffer[pool->pool_count++] = value; \ 206 | // return true; \ 207 | // } \ 208 | 209 | 210 | #endif -------------------------------------------------------------------------------- /include/generic_queue.h: -------------------------------------------------------------------------------- 1 | #ifndef GENERIC_DATA_STRUCTURES_QUEUE_H 2 | #define GENERIC_DATA_STRUCTURES_QUEUE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | // Macros to define a strongly typed queue data structure implemented using a circular buffer. 11 | 12 | #define QUEUE_DEFINE_H(type_name, function_prefix, value_type) \ 13 | typedef struct type_name { \ 14 | value_type* buffer; \ 15 | unsigned int count; \ 16 | unsigned int capacity; \ 17 | unsigned int start; \ 18 | unsigned int end; \ 19 | } type_name; \ 20 | \ 21 | type_name* function_prefix ## _create(void); \ 22 | type_name* function_prefix ## _create_capacity(unsigned int capacity); \ 23 | bool function_prefix ## _init(type_name* queue); \ 24 | bool function_prefix ## _init_capacity(type_name* queue, unsigned int capacity); \ 25 | void function_prefix ## _clear(type_name* queue); \ 26 | bool function_prefix ## _enqueue(type_name* queue, value_type value); \ 27 | value_type function_prefix ## _dequeue(type_name* queue); \ 28 | static inline value_type function_prefix ## _peek(type_name* queue) { \ 29 | assert(queue->count); \ 30 | return queue->buffer[queue->start]; \ 31 | } \ 32 | static inline unsigned int function_prefix ## _count(type_name* queue) { return queue->count; } \ 33 | static inline void function_prefix ## _free_resources(type_name* queue) { free(queue->buffer); } \ 34 | static inline void function_prefix ## _free(type_name* queue) { free(queue->buffer); free(queue); } 35 | 36 | #define QUEUE_DEFINE_C(type_name, function_prefix, value_type) \ 37 | /* todo: inline the create functions. */ \ 38 | type_name* function_prefix ## _create(void) { \ 39 | type_name* queue = malloc(sizeof(type_name)); \ 40 | if(!queue) \ 41 | return NULL; \ 42 | if(!function_prefix ## _init(queue)) { \ 43 | free(queue); \ 44 | return NULL; \ 45 | } \ 46 | return queue; \ 47 | } \ 48 | \ 49 | type_name* function_prefix ## _create_capacity(unsigned int capacity) { \ 50 | type_name* queue = malloc(sizeof(type_name)); \ 51 | if(!queue) \ 52 | return NULL; \ 53 | if(!function_prefix ## _init_capacity(queue, capacity)) { \ 54 | free(queue); \ 55 | return NULL; \ 56 | } \ 57 | return queue; \ 58 | } \ 59 | \ 60 | bool function_prefix ## _init(type_name* queue) { \ 61 | queue->start = 0; \ 62 | queue->end = 0; \ 63 | queue->count = 0; \ 64 | queue->capacity = 4; \ 65 | return (queue->buffer = malloc(queue->capacity * sizeof(value_type))) != NULL; \ 66 | } \ 67 | \ 68 | bool function_prefix ## _init_capacity(type_name* queue, unsigned int capacity) { \ 69 | queue->start = 0; \ 70 | queue->end = 0; \ 71 | queue->count = 0; \ 72 | queue->capacity = capacity == 0 ? 1 : capacity; \ 73 | return (queue->buffer = malloc(queue->capacity * sizeof(value_type))) != NULL; \ 74 | } \ 75 | \ 76 | void function_prefix ## _clear(type_name* queue) { \ 77 | queue->start = 0; \ 78 | queue->end = 0; \ 79 | queue->count = 0; \ 80 | } \ 81 | \ 82 | bool function_prefix ## _enqueue(type_name* queue, value_type value) { \ 83 | if(queue->end == queue->capacity) \ 84 | queue->end = 0; \ 85 | if(queue->count == queue->capacity) { \ 86 | unsigned int offset = queue->capacity - queue->start; \ 87 | queue->capacity *= 2; \ 88 | value_type* buffer = realloc(queue->buffer, queue->capacity * sizeof(value_type)); \ 89 | if(!buffer) { \ 90 | queue->capacity /= 2; \ 91 | return false; \ 92 | } \ 93 | queue->buffer = buffer; \ 94 | memmove(queue->buffer + queue->capacity - offset, queue->buffer + queue->start, offset * sizeof(value_type)); \ 95 | queue->start = queue->capacity - offset; \ 96 | } \ 97 | queue->buffer[queue->end++] = value; \ 98 | queue->count++; \ 99 | return true; \ 100 | } \ 101 | \ 102 | value_type function_prefix ## _dequeue(type_name* queue) { \ 103 | assert(queue->count); \ 104 | queue->count--; \ 105 | if(queue->start == queue->capacity - 1) { \ 106 | queue->start = 0; \ 107 | return queue->buffer[queue->capacity - 1]; \ 108 | } \ 109 | return queue->buffer[queue->start++]; \ 110 | } 111 | 112 | 113 | #endif -------------------------------------------------------------------------------- /include/generic_rbtree.h: -------------------------------------------------------------------------------- 1 | #ifndef GENERIC_DATA_STRUCTURES_RED_BLACK_TREE_H 2 | #define GENERIC_DATA_STRUCTURES_RED_BLACK_TREE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | // Macros to define a strongly typed rb-tree data structure. 10 | // TODO: Return error value if a new node fails to allocate. 11 | 12 | typedef enum RBColor { 13 | RB_BLACK, 14 | RB_RED 15 | } RBColor; 16 | 17 | #define RBTREE_DEFINE_H(type_name, function_prefix, key_type, value_type) \ 18 | typedef struct type_name ## Node type_name ## Node; \ 19 | struct type_name ## Node { \ 20 | type_name ## Node* left; \ 21 | type_name ## Node* right; \ 22 | type_name ## Node* parent; \ 23 | key_type key; \ 24 | value_type value; \ 25 | RBColor color; \ 26 | }; \ 27 | \ 28 | typedef struct type_name { \ 29 | type_name ## Node* root; \ 30 | unsigned int count; \ 31 | } type_name; \ 32 | \ 33 | static inline type_name* function_prefix ## _create(void); \ 34 | static inline void function_prefix ## _init(type_name* tree); \ 35 | static inline void function_prefix ## _free(type_name* tree, bool free_nodes); \ 36 | void function_prefix ## _free_resources(type_name* tree); \ 37 | static inline type_name ## Node* function_prefix ## _root(type_name* tree); \ 38 | static inline unsigned int function_prefix ## _count(type_name* tree); \ 39 | static inline type_name ## Node* function_prefix ## _add(type_name* tree, key_type key, value_type value); \ 40 | static inline bool function_prefix ## _get(type_name* tree, key_type key, value_type* out_value); \ 41 | static inline bool function_prefix ## _get_min(type_name* tree, value_type* out_value); \ 42 | static inline bool function_prefix ## _get_max(type_name* tree, value_type* out_value); \ 43 | static inline bool function_prefix ## _remove(type_name* tree, key_type key, value_type* out_value); \ 44 | static inline bool function_prefix ## _remove_min(type_name* tree, value_type* out_value); \ 45 | static inline bool function_prefix ## _remove_max(type_name* tree, value_type* out_value); \ 46 | void function_prefix ## _add_node(type_name* tree, type_name ## Node* node); \ 47 | type_name ## Node* function_prefix ## _get_node(type_name* tree, key_type key); \ 48 | static inline type_name ## Node* function_prefix ## _get_min_node(type_name* tree); \ 49 | static inline type_name ## Node* function_prefix ## _get_max_node(type_name* tree); \ 50 | type_name ## Node* function_prefix ## _remove_node(type_name* tree, type_name ## Node* node); \ 51 | static inline type_name ## Node* function_prefix ## _remove_min_node(type_name* tree); \ 52 | static inline type_name ## Node* function_prefix ## _remove_max_node(type_name* tree); \ 53 | \ 54 | static inline type_name* function_prefix ## _create(void) { \ 55 | type_name* tree = malloc(sizeof(type_name)); \ 56 | if(!tree) \ 57 | return NULL; \ 58 | tree->root = NULL; \ 59 | tree->count = 0; \ 60 | return tree; \ 61 | } \ 62 | \ 63 | static inline void function_prefix ## _init(type_name* tree) { \ 64 | tree->root = NULL; \ 65 | tree->count = 0; \ 66 | } \ 67 | \ 68 | static inline void function_prefix ## _free(type_name* tree, bool free_nodes) { \ 69 | if(free_nodes) \ 70 | function_prefix ## _free_resources(tree); \ 71 | free(tree); \ 72 | } \ 73 | \ 74 | static inline type_name ## Node* function_prefix ## _root(type_name* tree) { \ 75 | return tree->root; \ 76 | } \ 77 | \ 78 | static inline unsigned int function_prefix ## _count(type_name* tree) { \ 79 | return tree->count; \ 80 | } \ 81 | \ 82 | static inline type_name ## Node* function_prefix ## _add(type_name* tree, key_type key, value_type value) { \ 83 | type_name ## Node* node = malloc(sizeof(type_name ## Node)); \ 84 | if(!node) \ 85 | return NULL; \ 86 | node->key = key; \ 87 | node->value = value; \ 88 | function_prefix ## _add_node(tree, node); \ 89 | return node; \ 90 | } \ 91 | \ 92 | static inline bool function_prefix ## _get(type_name* tree, key_type key, value_type* out_value) { \ 93 | type_name ## Node* node = function_prefix ## _get_node(tree, key); \ 94 | if(!node) \ 95 | return false; \ 96 | \ 97 | if(out_value != NULL) *out_value = node->value; \ 98 | \ 99 | return true; \ 100 | } \ 101 | \ 102 | static inline bool function_prefix ## _get_min(type_name* tree, value_type* out_value) { \ 103 | type_name ## Node* node = function_prefix ## _get_min_node(tree); \ 104 | if(!node) \ 105 | return false; \ 106 | \ 107 | if(out_value != NULL) *out_value = node->value; \ 108 | \ 109 | return true; \ 110 | } \ 111 | \ 112 | static inline bool function_prefix ## _get_max(type_name* tree, value_type* out_value) { \ 113 | type_name ## Node* node = function_prefix ## _get_max_node(tree); \ 114 | if(!node) \ 115 | return false; \ 116 | \ 117 | if(out_value != NULL) *out_value = node->value; \ 118 | \ 119 | return true; \ 120 | } \ 121 | \ 122 | static inline bool function_prefix ## _remove(type_name* tree, key_type key, value_type* out_value) { \ 123 | type_name ## Node* node = function_prefix ## _get_node(tree, key); \ 124 | if(node == NULL) \ 125 | return false; \ 126 | \ 127 | if(out_value != NULL) *out_value = node->value; \ 128 | free(function_prefix ## _remove_node(tree, node)); \ 129 | return true; \ 130 | } \ 131 | \ 132 | static inline bool function_prefix ## _remove_min(type_name* tree, value_type* out_value) { \ 133 | type_name ## Node* node = function_prefix ## _get_min_node(tree); \ 134 | if(!node) \ 135 | return false; \ 136 | \ 137 | if(out_value != NULL) *out_value = node->value; \ 138 | free(function_prefix ## _remove_node(tree, node)); \ 139 | return true; \ 140 | } \ 141 | \ 142 | static inline bool function_prefix ## _remove_max(type_name* tree, value_type* out_value) { \ 143 | type_name ## Node* node = function_prefix ## _get_max_node(tree); \ 144 | if(!node) \ 145 | return false; \ 146 | \ 147 | if(out_value != NULL) *out_value = node->value; \ 148 | free(function_prefix ## _remove_node(tree, node)); \ 149 | return true; \ 150 | } \ 151 | \ 152 | static inline type_name ## Node* function_prefix ## _get_min_node(type_name* tree) { \ 153 | if(tree->root == NULL) \ 154 | return NULL; \ 155 | type_name ## Node* node = tree->root; \ 156 | while(node->left) \ 157 | node = node->left; \ 158 | return node; \ 159 | } \ 160 | \ 161 | static inline type_name ## Node* function_prefix ## _get_max_node(type_name* tree) { \ 162 | if(tree->root == NULL) \ 163 | return NULL; \ 164 | type_name ## Node* node = tree->root; \ 165 | while(node->right) \ 166 | node = node->right; \ 167 | return node; \ 168 | } \ 169 | \ 170 | static inline type_name ## Node* function_prefix ## _remove_min_node(type_name* tree) { \ 171 | type_name ## Node* node = function_prefix ## _get_min_node(tree); \ 172 | if(!node) \ 173 | return NULL; \ 174 | \ 175 | return function_prefix ## _remove_node(tree, node); \ 176 | } \ 177 | \ 178 | static inline type_name ## Node* function_prefix ## _remove_max_node(type_name* tree) { \ 179 | type_name ## Node* node = function_prefix ## _get_max_node(tree); \ 180 | if(!node) \ 181 | return NULL; \ 182 | \ 183 | return function_prefix ## _remove_node(tree, node); \ 184 | } \ 185 | 186 | 187 | #define RBTREE_DEFINE_C(type_name, function_prefix, key_type, value_type, compare_fn) \ 188 | static inline type_name ## Node* function_prefix ## _parent(type_name ## Node* node) { \ 189 | return node->parent; \ 190 | } \ 191 | \ 192 | static inline type_name ## Node* function_prefix ## _grandparent(type_name ## Node* node) { \ 193 | type_name ## Node* parent = function_prefix ## _parent(node); \ 194 | if(parent == NULL) \ 195 | return NULL; \ 196 | return function_prefix ## _parent(parent); \ 197 | } \ 198 | \ 199 | static inline type_name ## Node* function_prefix ## _sibling(type_name ## Node* node) { \ 200 | type_name ## Node* parent = function_prefix ## _parent(node);\ 201 | if(parent == NULL) \ 202 | return NULL; \ 203 | if(node == parent->left) \ 204 | return parent->right; \ 205 | else \ 206 | return parent->left; \ 207 | } \ 208 | \ 209 | static inline type_name ## Node* function_prefix ## _uncle(type_name ## Node* node) { \ 210 | type_name ## Node* parent = function_prefix ## _parent(node); \ 211 | type_name ## Node* grandparent = function_prefix ## _grandparent(node); \ 212 | if(grandparent == NULL) \ 213 | return NULL; \ 214 | return function_prefix ## _sibling(parent); \ 215 | } \ 216 | \ 217 | static inline RBColor function_prefix ## _color(type_name ## Node* node) { \ 218 | return node == NULL ? RB_BLACK : node->color; \ 219 | } \ 220 | \ 221 | type_name ## Node* function_prefix ## _get_node(type_name* tree, key_type key) { \ 222 | type_name ## Node* node = tree->root; \ 223 | while(node != NULL) { \ 224 | int result = compare_fn(key, node->key); \ 225 | if(result == 0) \ 226 | return node; \ 227 | else if(result < 0) \ 228 | node = node->left; \ 229 | else \ 230 | node = node->right; \ 231 | } \ 232 | return NULL; \ 233 | } \ 234 | \ 235 | static void function_prefix ## _insert_repair_tree(type_name* tree, type_name ## Node* node); \ 236 | \ 237 | static void function_prefix ## _replace_node(type_name* tree, type_name ## Node* old_node, type_name ## Node* new_node) { \ 238 | if(old_node->parent == NULL) { \ 239 | tree->root = new_node;\ 240 | } else {\ 241 | if(old_node == old_node->parent->left) \ 242 | old_node->parent->left = new_node; \ 243 | else \ 244 | old_node->parent->right = new_node; \ 245 | } \ 246 | if(new_node != NULL) \ 247 | new_node->parent = old_node->parent; \ 248 | } \ 249 | \ 250 | static void function_prefix ## _rotate_left(type_name* tree, type_name ## Node* node) { \ 251 | type_name ## Node* right = node->right; \ 252 | function_prefix ## _replace_node(tree, node, right); \ 253 | node->right = right->left; \ 254 | if(right->left != NULL) \ 255 | right->left->parent = node; \ 256 | right->left = node; \ 257 | node->parent = right; \ 258 | } \ 259 | \ 260 | static void function_prefix ## _rotate_right(type_name* tree, type_name ## Node* node) { \ 261 | type_name ## Node* left = node->left; \ 262 | function_prefix ## _replace_node(tree, node, left); \ 263 | node->left = left->right; \ 264 | if(left->right != NULL) \ 265 | left->right->parent = node; \ 266 | left->right = node; \ 267 | node->parent = left; \ 268 | } \ 269 | \ 270 | static inline void function_prefix ## _insert_case1(type_name ## Node* node) { \ 271 | if(function_prefix ## _parent(node) == NULL) \ 272 | node->color = RB_BLACK; \ 273 | } \ 274 | \ 275 | static inline void function_prefix ## _insert_case2(type_name ## Node* node) { \ 276 | return; \ 277 | } \ 278 | \ 279 | static inline void function_prefix ## _insert_case3(type_name* tree, type_name ## Node* node) { \ 280 | function_prefix ## _parent(node)->color = RB_BLACK; \ 281 | function_prefix ## _uncle(node)->color = RB_BLACK; \ 282 | type_name ## Node* grandparent = function_prefix ## _grandparent(node); \ 283 | grandparent->color = RB_RED; \ 284 | function_prefix ## _insert_repair_tree(tree, grandparent); \ 285 | } \ 286 | \ 287 | static void function_prefix ## _insert_case4(type_name* tree, type_name ## Node* node) { \ 288 | if(node == node->parent->right && node->parent == function_prefix ## _grandparent(node)->left) { \ 289 | function_prefix ## _rotate_left(tree, node->parent); \ 290 | node = node->left; \ 291 | } else if(node == node->parent->left && node->parent == function_prefix ## _grandparent(node)->right) { \ 292 | function_prefix ## _rotate_right(tree, node->parent); \ 293 | node = node->right; \ 294 | } \ 295 | \ 296 | node->parent->color = RB_BLACK; \ 297 | function_prefix ## _grandparent(node)->color = RB_RED; \ 298 | if(node == node->parent->left && node->parent == function_prefix ## _grandparent(node)->left) \ 299 | function_prefix ## _rotate_right(tree, function_prefix ## _grandparent(node)); \ 300 | else {\ 301 | function_prefix ## _rotate_left(tree, function_prefix ## _grandparent(node)); \ 302 | } \ 303 | } \ 304 | \ 305 | static void function_prefix ## _insert_repair_tree(type_name* tree, type_name ## Node* node) { \ 306 | if(function_prefix ## _parent(node) == NULL) \ 307 | function_prefix ## _insert_case1(node); \ 308 | else if(function_prefix ## _color(node->parent) == RB_BLACK) \ 309 | function_prefix ## _insert_case2(node); \ 310 | else if(function_prefix ## _color(function_prefix ## _uncle(node)) == RB_RED) \ 311 | function_prefix ## _insert_case3(tree, node); \ 312 | else \ 313 | function_prefix ## _insert_case4(tree, node); \ 314 | } \ 315 | \ 316 | void function_prefix ## _add_node(type_name* tree, type_name ## Node* node) { \ 317 | node->color = RB_RED; \ 318 | node->parent = NULL; \ 319 | node->left = NULL; \ 320 | node->right = NULL; \ 321 | if(tree->root == NULL) { \ 322 | tree->root = node; \ 323 | } else { \ 324 | type_name ## Node* parent = NULL; \ 325 | type_name ## Node* current = tree->root; \ 326 | while(current != NULL) { \ 327 | parent = current; \ 328 | \ 329 | if(compare_fn(node->key, current->key) < 0) \ 330 | current = current->left; \ 331 | else \ 332 | current = current->right; \ 333 | } \ 334 | \ 335 | node->parent = parent; \ 336 | \ 337 | if(compare_fn(node->key, parent->key) < 0) \ 338 | parent->left = node; \ 339 | else \ 340 | parent->right = node; \ 341 | } \ 342 | tree->count++; \ 343 | function_prefix ## _insert_repair_tree(tree, node); \ 344 | } \ 345 | \ 346 | static void function_prefix ## _delete_case1(type_name* tree, type_name ## Node* node); \ 347 | static void function_prefix ## _delete_case2(type_name* tree, type_name ## Node* node); \ 348 | static void function_prefix ## _delete_case3(type_name* tree, type_name ## Node* node); \ 349 | static void function_prefix ## _delete_case4(type_name* tree, type_name ## Node* node); \ 350 | static void function_prefix ## _delete_case5(type_name* tree, type_name ## Node* node); \ 351 | static void function_prefix ## _delete_case6(type_name* tree, type_name ## Node* node); \ 352 | \ 353 | static void function_prefix ## _delete_case1(type_name* tree, type_name ## Node* node) { \ 354 | if(node->parent == NULL) \ 355 | return; \ 356 | else \ 357 | function_prefix ## _delete_case2(tree, node); \ 358 | } \ 359 | \ 360 | static void function_prefix ## _delete_case2(type_name* tree, type_name ## Node* node) { \ 361 | if (function_prefix ## _color(function_prefix ## _sibling(node)) == RB_RED) { \ 362 | node->parent->color = RB_RED; \ 363 | function_prefix ## _sibling(node)->color = RB_BLACK; \ 364 | if(node == node->parent->left) \ 365 | function_prefix ## _rotate_left(tree, node->parent); \ 366 | else \ 367 | function_prefix ## _rotate_right(tree, node->parent); \ 368 | } \ 369 | function_prefix ## _delete_case3(tree, node); \ 370 | } \ 371 | \ 372 | static void function_prefix ## _delete_case3(type_name* tree, type_name ## Node* node) { \ 373 | if (function_prefix ## _color(node->parent) == RB_BLACK && \ 374 | function_prefix ## _color(function_prefix ## _sibling(node)) == RB_BLACK && \ 375 | function_prefix ## _color(function_prefix ## _sibling(node)->left) == RB_BLACK && \ 376 | function_prefix ## _color(function_prefix ## _sibling(node)->right) == RB_BLACK) \ 377 | { \ 378 | function_prefix ## _sibling(node)->color = RB_RED; \ 379 | function_prefix ## _delete_case1(tree, node->parent); \ 380 | } \ 381 | else \ 382 | function_prefix ## _delete_case4(tree, node); \ 383 | }\ 384 | \ 385 | static void function_prefix ## _delete_case4(type_name* tree, type_name ## Node* node) { \ 386 | if (function_prefix ## _color(node->parent) == RB_RED && \ 387 | function_prefix ## _color(function_prefix ## _sibling(node)) == RB_BLACK && \ 388 | function_prefix ## _color(function_prefix ## _sibling(node)->left) == RB_BLACK && \ 389 | function_prefix ## _color(function_prefix ## _sibling(node)->right) == RB_BLACK) \ 390 | { \ 391 | function_prefix ## _sibling(node)->color = RB_RED; \ 392 | node->parent->color = RB_BLACK; \ 393 | } \ 394 | else \ 395 | function_prefix ## _delete_case5(tree, node); \ 396 | } \ 397 | \ 398 | static void function_prefix ## _delete_case5(type_name* tree, type_name ## Node* node) {\ 399 | if (node == node->parent->left && \ 400 | function_prefix ## _color(function_prefix ## _sibling(node)) == RB_BLACK && \ 401 | function_prefix ## _color(function_prefix ## _sibling(node)->left) == RB_RED && \ 402 | function_prefix ## _color(function_prefix ## _sibling(node)->right) == RB_BLACK) \ 403 | { \ 404 | function_prefix ## _sibling(node)->color = RB_RED; \ 405 | function_prefix ## _sibling(node)->left->color = RB_BLACK; \ 406 | function_prefix ## _rotate_right(tree, function_prefix ## _sibling(node)); \ 407 | } \ 408 | else if(node == node->parent->right && \ 409 | function_prefix ## _color(function_prefix ## _sibling(node)) == RB_BLACK && \ 410 | function_prefix ## _color(function_prefix ## _sibling(node)->right) == RB_RED && \ 411 | function_prefix ## _color(function_prefix ## _sibling(node)->left) == RB_BLACK) \ 412 | { \ 413 | function_prefix ## _sibling(node)->color = RB_RED; \ 414 | function_prefix ## _sibling(node)->right->color = RB_BLACK; \ 415 | function_prefix ## _rotate_left(tree, function_prefix ## _sibling(node)); \ 416 | } \ 417 | function_prefix ## _delete_case6(tree, node); \ 418 | } \ 419 | \ 420 | static void function_prefix ## _delete_case6(type_name* tree, type_name ## Node* node) { \ 421 | function_prefix ## _sibling(node)->color = function_prefix ## _color(node->parent); \ 422 | node->parent->color = RB_BLACK; \ 423 | if(node == node->parent->left) { \ 424 | function_prefix ## _sibling(node)->right->color = RB_BLACK; \ 425 | function_prefix ## _rotate_left(tree, node->parent); \ 426 | } else { \ 427 | function_prefix ## _sibling(node)->left->color = RB_BLACK; \ 428 | function_prefix ## _rotate_right(tree, node->parent); \ 429 | } \ 430 | } \ 431 | \ 432 | type_name ## Node* function_prefix ## _remove_node(type_name* tree, type_name ## Node* node) { \ 433 | key_type temp_key = node->key; \ 434 | value_type temp_value = node->value; \ 435 | if(node->left != NULL && node->right != NULL) { \ 436 | type_name ## Node* pred = node->left; \ 437 | while(pred->right) \ 438 | pred = pred->right; \ 439 | node->key = pred->key; \ 440 | node->value = pred->value; \ 441 | node = pred; \ 442 | } \ 443 | \ 444 | type_name ## Node* child = node->right == NULL ? node->left : node->right; \ 445 | if(function_prefix ## _color(node) == RB_BLACK) { \ 446 | node->color = function_prefix ## _color(child); \ 447 | function_prefix ## _delete_case1(tree, node); \ 448 | } \ 449 | function_prefix ## _replace_node(tree, node, child); \ 450 | if(node->parent == NULL && child != NULL) \ 451 | child->color = RB_BLACK; \ 452 | \ 453 | tree->count--; \ 454 | node->key = temp_key; \ 455 | node->value = temp_value; \ 456 | return node; \ 457 | } \ 458 | \ 459 | void function_prefix ## _free_resources(type_name* tree) { \ 460 | if(tree->root == NULL) \ 461 | return; \ 462 | \ 463 | type_name ## Node* current = tree->root; \ 464 | type_name ## Node* temp; \ 465 | while(current != NULL) { \ 466 | if(current->left != NULL) \ 467 | current = current->left; \ 468 | else if(current->right != NULL) \ 469 | current = current->right; \ 470 | else { \ 471 | if(current->parent != NULL) { \ 472 | if(current == current->parent->left) \ 473 | current->parent->left = NULL; \ 474 | else \ 475 | current->parent->right = NULL; \ 476 | } \ 477 | tree->count--; \ 478 | temp = current->parent; \ 479 | free(current); \ 480 | current = temp; \ 481 | } \ 482 | } \ 483 | } 484 | 485 | #endif -------------------------------------------------------------------------------- /include/generic_set.h: -------------------------------------------------------------------------------- 1 | #ifndef GENERIC_DATA_STRUCTURES_SET_H 2 | #define GENERIC_DATA_STRUCTURES_SET_H 3 | 4 | /* 5 | Defines a generic set of unique values. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "generic_hash_utils.h" 13 | 14 | #define SET_DEFINE_H(type_name, function_prefix, value_type) \ 15 | typedef struct type_name ## Cell { \ 16 | value_type value; \ 17 | uint32_t hash; \ 18 | bool active; \ 19 | } type_name ## Cell; \ 20 | \ 21 | typedef struct type_name { \ 22 | type_name ## Cell* cells; \ 23 | uint32_t count; \ 24 | uint32_t capacity; \ 25 | uint32_t load_factor; \ 26 | int shift; \ 27 | } type_name; \ 28 | \ 29 | static inline uint32_t function_prefix ## _count(type_name* set) { return set->count; } \ 30 | static inline uint32_t function_prefix ## _capacity(type_name* set) { return set->load_factor; } \ 31 | static inline uint32_t function_prefix ## _allocated(type_name* set) { return set->capacity; } \ 32 | static inline void function_prefix ## _free(type_name* set) { free(set->cells); free(set); } \ 33 | static inline void function_prefix ## _free_resources(type_name* set) { free(set->cells); } \ 34 | \ 35 | type_name* function_prefix ## _create(void); \ 36 | bool function_prefix ## _init(type_name* set); \ 37 | bool function_prefix ## _add(type_name* set, value_type value); \ 38 | bool function_prefix ## _contains(type_name* set, value_type value); \ 39 | bool function_prefix ## _remove(type_name* set, value_type value); \ 40 | bool function_prefix ## _get(type_name* set, value_type value, value_type* out_value); \ 41 | bool function_prefix ## _get_and_remove(type_name* set, value_type value, value_type* out_value); \ 42 | void function_prefix ## _clear(type_name* set, bool reset_capacity); \ 43 | bool function_prefix ## _union(type_name* left, type_name* right, type_name* result); \ 44 | bool function_prefix ## _intersect(type_name* left, type_name* right, type_name* result); \ 45 | bool function_prefix ## _complement(type_name* left, type_name* right, type_name* result); \ 46 | bool function_prefix ## _is_superset(type_name* superset, type_name* subset); \ 47 | 48 | 49 | #define SET_DEFINE_C(type_name, function_prefix, value_type, hash_fn, compare_fn) \ 50 | type_name* function_prefix ## _create(void) { \ 51 | type_name* set = malloc(sizeof(type_name)); \ 52 | if(!set) \ 53 | return NULL; \ 54 | function_prefix ## _init(set); \ 55 | return set; \ 56 | } \ 57 | \ 58 | bool function_prefix ## _init(type_name* set) { \ 59 | set->shift = 29; \ 60 | set->capacity = 8; \ 61 | set->count = 0; \ 62 | set->load_factor = 4; \ 63 | return (set->cells = calloc(8, sizeof(type_name ## Cell))) != NULL; \ 64 | } \ 65 | \ 66 | static void function_prefix ## _resize(type_name* set) { \ 67 | int capacity = set->load_factor = set->capacity; \ 68 | set->capacity = 1u << (32 - (--set->shift)); \ 69 | type_name ## Cell* old = set->cells; \ 70 | type_name ## Cell* current = calloc(set->capacity, sizeof(type_name ## Cell)); \ 71 | assert(current); \ 72 | \ 73 | for(uint32_t i = 0; i < capacity; i++) { \ 74 | if(old[i].active) { \ 75 | uint32_t cell = ___fib_hash(old[i].hash, set->shift); \ 76 | while(current[cell].active) { \ 77 | if(++cell > set->capacity) \ 78 | cell = 0; \ 79 | } \ 80 | \ 81 | current[cell] = old[i]; \ 82 | } \ 83 | } \ 84 | free(old); \ 85 | set->cells = current; \ 86 | } \ 87 | \ 88 | bool function_prefix ## _add(type_name* set, value_type value) { \ 89 | uint32_t hash, cell; \ 90 | \ 91 | if(set->count == set->load_factor) \ 92 | function_prefix ## _resize(set); \ 93 | \ 94 | hash = hash_fn(value); \ 95 | cell = ___fib_hash(hash, set->shift); \ 96 | \ 97 | while(true) { \ 98 | if(!set->cells[cell].active) { \ 99 | set->cells[cell].active = true; \ 100 | set->cells[cell].value = value; \ 101 | set->cells[cell].hash = hash; \ 102 | set->count++; \ 103 | return true; \ 104 | } else if(set->cells[cell].hash == hash && compare_fn(set->cells[cell].value, value) == 0) \ 105 | return false; \ 106 | \ 107 | if(++cell == set->capacity) \ 108 | cell = 0; \ 109 | } \ 110 | \ 111 | return false; \ 112 | } \ 113 | \ 114 | static inline bool function_prefix ## _find_cell(type_name* set, value_type value, uint32_t* out_hash, uint32_t* out_cell) { \ 115 | uint32_t cell, hash; \ 116 | hash = hash_fn(value); \ 117 | cell = ___fib_hash(hash, set->shift); \ 118 | \ 119 | while(true) { \ 120 | if(!set->cells[cell].active) \ 121 | return false; \ 122 | \ 123 | if(set->cells[cell].hash == hash && compare_fn(set->cells[cell].value, value) == 0) { \ 124 | *out_hash = hash; \ 125 | *out_cell = cell; \ 126 | return true; \ 127 | } \ 128 | \ 129 | if(++cell == set->capacity) \ 130 | cell = 0; \ 131 | } \ 132 | } \ 133 | \ 134 | static inline void function_prefix ## _replace_cell(type_name* set, uint32_t cell, uint32_t hash) { \ 135 | uint32_t start = cell; \ 136 | uint32_t last = start; \ 137 | \ 138 | while(true) { \ 139 | if(++cell == set->capacity) \ 140 | cell = 0; \ 141 | \ 142 | if(!set->cells[cell].active) \ 143 | break; \ 144 | \ 145 | uint32_t preferred_cell = ___fib_hash(set->cells[cell].hash, set->shift); \ 146 | if(preferred_cell <= start || preferred_cell > cell) { \ 147 | set->cells[start] = set->cells[cell]; \ 148 | start = cell; \ 149 | } \ 150 | } \ 151 | set->cells[start].active = false; \ 152 | } \ 153 | \ 154 | bool function_prefix ## _contains(type_name* set, value_type value) { \ 155 | uint32_t cell, hash; \ 156 | return function_prefix ## _find_cell(set, value, &hash, &cell); \ 157 | } \ 158 | \ 159 | bool function_prefix ## _remove(type_name* set, value_type value) { \ 160 | uint32_t cell, hash; \ 161 | if(!function_prefix ## _find_cell(set, value, &hash, &cell)) \ 162 | return false; \ 163 | \ 164 | function_prefix ## _replace_cell(set, cell, hash); \ 165 | set->count--; \ 166 | return true; \ 167 | } \ 168 | \ 169 | bool function_prefix ## _get(type_name* set, value_type value, value_type* out_value) { \ 170 | uint32_t cell, hash; \ 171 | if(!function_prefix ## _find_cell(set, value, &hash, &cell)) \ 172 | return false; \ 173 | *out_value = set->cells[cell].value; \ 174 | return true; \ 175 | } \ 176 | \ 177 | bool function_prefix ## _get_and_remove(type_name* set, value_type value, value_type* out_value) { \ 178 | uint32_t cell, hash; \ 179 | if(!function_prefix ## _find_cell(set, value, &hash, &cell)) \ 180 | return false; \ 181 | *out_value = set->cells[cell].value; \ 182 | \ 183 | function_prefix ## _replace_cell(set, cell, hash); \ 184 | set->count--; \ 185 | return true; \ 186 | } \ 187 | \ 188 | void function_prefix ## _clear(type_name* set, bool reset_capacity) { \ 189 | if(reset_capacity) { \ 190 | free(set->cells); \ 191 | function_prefix ## _init(set); \ 192 | } else { \ 193 | for(uint32_t i = 0; i < set->capacity; i++) \ 194 | set->cells[i].active = false; \ 195 | } \ 196 | } \ 197 | \ 198 | bool function_prefix ## _union(type_name* left, type_name* right, type_name* result) { \ 199 | if(!left || !right || !result) \ 200 | return false; \ 201 | \ 202 | for(int i = 0; i < left->capacity; i++) { \ 203 | if(!left->cells[i].active) \ 204 | continue; \ 205 | function_prefix ## _add(result, left->cells[i].value); \ 206 | } \ 207 | \ 208 | for(int i = 0; i < right->capacity; i++) { \ 209 | if(!right->cells[i].active) \ 210 | continue; \ 211 | function_prefix ## _add(result, right->cells[i].value); \ 212 | } \ 213 | \ 214 | return true; \ 215 | } \ 216 | \ 217 | bool function_prefix ## _intersect(type_name* left, type_name* right, type_name* result) { \ 218 | if(!left || !right || !result) \ 219 | return false; \ 220 | \ 221 | for(int i = 0; i < left->capacity; i++) { \ 222 | if(!left->cells[i].active) \ 223 | continue; \ 224 | if(function_prefix ## _contains(right, left->cells[i].value)) \ 225 | function_prefix ## _add(result, left->cells[i].value); \ 226 | } \ 227 | \ 228 | return true; \ 229 | } \ 230 | \ 231 | bool function_prefix ## _complement(type_name* left, type_name* right, type_name* result) { \ 232 | if(!left || !right || !result) \ 233 | return false; \ 234 | \ 235 | for(int i = 0; i < left->capacity; i++) { \ 236 | if(!left->cells[i].active) \ 237 | continue; \ 238 | if(!function_prefix ## _contains(right, left->cells[i].value)) \ 239 | function_prefix ## _add(result, left->cells[i].value); \ 240 | } \ 241 | \ 242 | return true; \ 243 | } \ 244 | \ 245 | bool function_prefix ## _is_superset(type_name* superset, type_name* subset) { \ 246 | if(!superset || !subset) \ 247 | return false; \ 248 | \ 249 | for(int i = 0; i < subset->capacity; i++) { \ 250 | if(!subset->cells[i].active) \ 251 | continue; \ 252 | if(!function_prefix ## _contains(superset, subset->cells[i].value)) \ 253 | return false; \ 254 | } \ 255 | \ 256 | return true; \ 257 | } \ 258 | 259 | #endif -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project('GenericDataStructures', 'c', version: '0.0.2', license: 'MIT') 2 | 3 | c_comp = meson.get_compiler('c') 4 | 5 | check_location = get_option('check_location') 6 | 7 | include_files = ['include'] 8 | 9 | inc = include_directories(include_files) 10 | 11 | if check_location != '' 12 | test_inc = include_directories(include_files + [check_location + '/include']) 13 | endif 14 | 15 | if check_location != '' or c_comp.has_header('check.h') 16 | subdir('tests') 17 | endif 18 | 19 | GenericDataStructures_dep = declare_dependency(include_directories: inc) -------------------------------------------------------------------------------- /meson_options.txt: -------------------------------------------------------------------------------- 1 | option('check_location', type: 'string', description: 'The location of the unit testing library Check. Leave blank to exclude tests.', value: '') -------------------------------------------------------------------------------- /tests/deque_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../include/generic_deque.h" 5 | #include "../include/generic_iterators/deque_iterator.h" 6 | 7 | DEQUE_DEFINE_H(IntDeque, id, int) 8 | DEQUE_DEFINE_C(IntDeque, id, int) 9 | 10 | static IntDeque* deque; 11 | 12 | void deque_start(void) { 13 | deque = id_create(); 14 | } 15 | 16 | void deque_reset(void) { 17 | id_free(deque); 18 | } 19 | 20 | START_TEST(deque_allocate_and_deallocate) { 21 | IntDeque temp, *ptr; 22 | 23 | ck_assert(id_init(&temp)); 24 | id_free_resources(&temp); 25 | 26 | ck_assert(id_init_capacity(&temp, 8)); 27 | id_free_resources(&temp); 28 | 29 | ck_assert(ptr = id_create()); 30 | id_free(ptr); 31 | 32 | ck_assert(ptr = id_create_capacity(8)); 33 | id_free(ptr); 34 | } 35 | END_TEST 36 | 37 | START_TEST(deque_push_front_increments_count) { 38 | ck_assert(id_count(deque) == 0); 39 | for(int i = 1; i < 10; i++) { 40 | ck_assert(id_push_front(deque, i)); 41 | ck_assert(id_count(deque) == i); 42 | } 43 | } 44 | END_TEST 45 | 46 | START_TEST(deque_push_back_increments_count) { 47 | ck_assert(id_count(deque) == 0); 48 | for(int i = 1; i < 10; i++) { 49 | ck_assert(id_push_back(deque, i)); 50 | ck_assert(id_count(deque) == i); 51 | } 52 | } 53 | END_TEST 54 | 55 | START_TEST(deque_pop_front_gets_value) { 56 | ck_assert(id_push_front(deque, 2)); 57 | ck_assert(id_push_back(deque, 4)); 58 | ck_assert(id_pop_front(deque) == 2); 59 | ck_assert(id_pop_front(deque) == 4); 60 | } 61 | END_TEST 62 | 63 | START_TEST(deque_pop_back_gets_value) { 64 | ck_assert(id_push_back(deque, 4)); 65 | ck_assert(id_push_front(deque, 2)); 66 | ck_assert(id_pop_back(deque) == 4); 67 | ck_assert(id_pop_back(deque) == 2); 68 | } 69 | END_TEST 70 | 71 | START_TEST(deque_resizes_properly) { 72 | unsigned int capacity = id_capacity(deque); 73 | ck_assert(id_push_front(deque, 0)); 74 | 75 | for (int i = 1; i < capacity; i++) 76 | ck_assert(id_push_back(deque, i)); 77 | 78 | ck_assert(id_capacity(deque) == capacity); 79 | ck_assert(id_push_back(deque, capacity)); 80 | ck_assert(id_capacity(deque) != capacity); 81 | 82 | while(id_count(deque) > 0) 83 | ck_assert(id_pop_back(deque) == capacity--); 84 | } 85 | END_TEST 86 | 87 | #define ORDER_COUNT 100 88 | 89 | START_TEST(deque_orders_properly) { 90 | int values[ORDER_COUNT]; 91 | bool direction[ORDER_COUNT]; 92 | 93 | for(int i = 0; i < ORDER_COUNT; i++) { 94 | values[i] = rand(); 95 | if(rand() % 2) { 96 | direction[i] = true; 97 | id_push_front(deque, values[i]); 98 | } else { 99 | direction[i] = false; 100 | id_push_back(deque, values[i]); 101 | } 102 | } 103 | 104 | for(int i = ORDER_COUNT - 1; i >= 0; i--) { 105 | if(direction[i]) { 106 | ck_assert(values[i] == id_pop_front(deque)); 107 | } else { 108 | ck_assert(values[i] == id_pop_back(deque)); 109 | } 110 | } 111 | } 112 | END_TEST 113 | 114 | START_TEST(deque_peek_front_gets_value_without_removal) { 115 | ck_assert(id_push_back(deque, 4)); 116 | ck_assert(id_push_front(deque, 2)); 117 | ck_assert(id_peek_front(deque) == 2); 118 | ck_assert(id_pop_front(deque) == 2); 119 | ck_assert(id_peek_front(deque) == 4); 120 | } 121 | END_TEST 122 | 123 | START_TEST(deque_peek_back_gets_value_without_removal) { 124 | ck_assert(id_push_front(deque, 2)); 125 | ck_assert(id_push_back(deque, 4)); 126 | ck_assert(id_peek_back(deque) == 4); 127 | ck_assert(id_pop_back(deque) == 4); 128 | ck_assert(id_peek_back(deque) == 2); 129 | } 130 | END_TEST 131 | 132 | START_TEST(deque_clear_can_keep_capacity) { 133 | unsigned int capacity = id_capacity(deque); 134 | for(int i = 0; i <= capacity; i++) 135 | id_push_back(deque, i); 136 | ck_assert(id_capacity(deque) != capacity); 137 | capacity = id_capacity(deque); 138 | id_clear(deque, false); 139 | ck_assert(id_capacity(deque) == capacity); 140 | } 141 | END_TEST 142 | 143 | START_TEST(deque_clear_can_reset_capacity) { 144 | unsigned int capacity = id_capacity(deque); 145 | for(int i = 0; i <= capacity; i++) 146 | id_push_back(deque, i); 147 | ck_assert(id_capacity(deque) != capacity); 148 | capacity = id_capacity(deque); 149 | id_clear(deque, true); 150 | ck_assert(id_capacity(deque) != capacity); 151 | } 152 | END_TEST 153 | 154 | START_TEST(deque_iterates_in_order) { 155 | int values[ORDER_COUNT]; 156 | 157 | for(int i = 0; i < ORDER_COUNT; i++) { 158 | int offset = i / 2; 159 | int value = rand(); 160 | if(i % 2) { 161 | values[(ORDER_COUNT / 2 - 1) - offset] = value; 162 | id_push_front(deque, value); 163 | } else { 164 | values[ORDER_COUNT / 2 + offset] = value; 165 | id_push_back(deque, value); 166 | } 167 | } 168 | 169 | int pos = 0, out_value; 170 | deque_iter_start(deque, out_value) { 171 | ck_assert(values[pos++] == out_value); 172 | } 173 | deque_iter_end 174 | 175 | } 176 | END_TEST 177 | 178 | int main(void) { 179 | Suite* s = suite_create("Queue Tests"); 180 | TCase* tc = tcase_create("Queue Tests"); 181 | 182 | tcase_add_checked_fixture(tc, deque_start, deque_reset); 183 | tcase_add_test(tc, deque_allocate_and_deallocate); 184 | tcase_add_test(tc, deque_push_front_increments_count); 185 | tcase_add_test(tc, deque_push_back_increments_count); 186 | tcase_add_test(tc, deque_pop_front_gets_value); 187 | tcase_add_test(tc, deque_pop_back_gets_value); 188 | tcase_add_test(tc, deque_resizes_properly); 189 | tcase_add_test(tc, deque_orders_properly); 190 | tcase_add_test(tc, deque_peek_front_gets_value_without_removal); 191 | tcase_add_test(tc, deque_peek_back_gets_value_without_removal); 192 | tcase_add_test(tc, deque_clear_can_keep_capacity); 193 | tcase_add_test(tc, deque_clear_can_reset_capacity); 194 | tcase_add_test(tc, deque_iterates_in_order); 195 | 196 | 197 | suite_add_tcase(s, tc); 198 | 199 | SRunner* sr = srunner_create(s); 200 | srunner_run_all(sr, CK_NORMAL); 201 | int number_failed = srunner_ntests_failed(sr); 202 | srunner_free(sr); 203 | 204 | return number_failed == 0 ? EXIT_SUCCESS : EXIT_FAILURE; 205 | } -------------------------------------------------------------------------------- /tests/event_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define GENERIC_EVENT_IMPLEMENTATION 4 | 5 | #include "../include/generic_event.h" 6 | 7 | EVENT_DEFINE_0_H(Action, action) 8 | EVENT_DEFINE_C(Action, action) 9 | 10 | EVENT_DEFINE_2_H(Callback, callback, int, int) 11 | EVENT_DEFINE_C(Callback, callback) 12 | 13 | static Action* action; 14 | static Callback* callback; 15 | static GdsEvent* gds_event; 16 | 17 | void action_set(void* ctx) { 18 | *(int*)ctx = 5; 19 | } 20 | 21 | void callback_set(void* ctx, int left, int right) { 22 | *(int*)ctx = left - right; 23 | } 24 | 25 | void gds_event_set(void* ctx, int value) { 26 | *(int*)ctx = value; 27 | } 28 | 29 | void event_start(void) { 30 | action = action_create(); 31 | callback = callback_create(); 32 | gds_event = gds_event_create(); 33 | } 34 | 35 | void event_reset(void) { 36 | action_free(action); 37 | callback_free(callback); 38 | gds_event_free(gds_event); 39 | } 40 | 41 | START_TEST(action_allocate_and_deallocate) { 42 | Action value; 43 | action_init(&value); 44 | action_free_resources(&value); 45 | Action* ptr = action_create(); 46 | ck_assert(ptr); 47 | action_free(ptr); 48 | } 49 | END_TEST 50 | 51 | START_TEST(callback_allocate_and_deallocate) { 52 | Callback value; 53 | callback_init(&value); 54 | callback_free_resources(&value); 55 | Callback* ptr = callback_create(); 56 | ck_assert(ptr); 57 | callback_free(ptr); 58 | } 59 | END_TEST 60 | 61 | START_TEST(gds_event_allocate_and_deallocate) { 62 | GdsEvent value; 63 | gds_event_init(&value); 64 | gds_event_free_resources(&value); 65 | GdsEvent* ptr = gds_event_create(); 66 | ck_assert(ptr); 67 | gds_event_free(ptr); 68 | } 69 | END_TEST 70 | 71 | START_TEST(action_subscribe_true) { 72 | ck_assert(action_subscribe(action, NULL, action_set)); 73 | } 74 | END_TEST 75 | 76 | START_TEST(callback_subscribe_true) { 77 | ck_assert(callback_subscribe(callback, NULL, callback_set)); 78 | } 79 | END_TEST 80 | 81 | START_TEST(gds_event_subscribe_true) { 82 | ck_assert(gds_event_subscribe(gds_event, NULL, gds_event_set)); 83 | } 84 | END_TEST 85 | 86 | START_TEST(action_unsubscribe_true) { 87 | ck_assert(action_subscribe(action, NULL, action_set)); 88 | ck_assert(action_unsubscribe(action, NULL, action_set)); 89 | } 90 | END_TEST 91 | 92 | START_TEST(callback_unsubscribe_true) { 93 | ck_assert(callback_subscribe(callback, NULL, callback_set)); 94 | ck_assert(callback_unsubscribe(callback, NULL, callback_set)); 95 | } 96 | END_TEST 97 | 98 | START_TEST(gds_event_unsubscribe_true) { 99 | ck_assert(gds_event_subscribe(gds_event, NULL, gds_event_set)); 100 | ck_assert(gds_event_unsubscribe(gds_event, NULL, gds_event_set)); 101 | } 102 | END_TEST 103 | 104 | START_TEST(action_unsubscribe_different_context) { 105 | int ctx; 106 | ck_assert(action_subscribe(action, &ctx, action_set)); 107 | ck_assert(!action_unsubscribe(action, NULL, action_set)); 108 | } 109 | END_TEST 110 | 111 | START_TEST(callback_unsubscribe_different_context) { 112 | int ctx; 113 | ck_assert(callback_subscribe(callback, &ctx, callback_set)); 114 | ck_assert(!callback_unsubscribe(callback, NULL, callback_set)); 115 | } 116 | END_TEST 117 | 118 | START_TEST(gds_event_unsubscribe_different_context) { 119 | int ctx; 120 | ck_assert(gds_event_subscribe(gds_event, &ctx, gds_event_set)); 121 | ck_assert(!gds_event_unsubscribe(gds_event, NULL, gds_event_set)); 122 | } 123 | END_TEST 124 | 125 | START_TEST(action_unsubscribe_different_function) { 126 | int ctx; 127 | ck_assert(action_subscribe(action, &ctx, action_set)); 128 | ck_assert(!action_unsubscribe(action, &ctx, NULL)); 129 | } 130 | END_TEST 131 | 132 | START_TEST(callback_unsubscribe_different_function) { 133 | int ctx; 134 | ck_assert(callback_subscribe(callback, &ctx, callback_set)); 135 | ck_assert(!callback_unsubscribe(callback, &ctx, NULL)); 136 | } 137 | END_TEST 138 | 139 | START_TEST(gds_event_unsubscribe_different_function) { 140 | int ctx; 141 | ck_assert(gds_event_subscribe(gds_event, &ctx, gds_event_set)); 142 | ck_assert(!gds_event_unsubscribe(gds_event, &ctx, NULL)); 143 | } 144 | END_TEST 145 | 146 | START_TEST(action_trigger_single_sub) { 147 | int ctx; 148 | action_subscribe(action, &ctx, action_set); 149 | action_trigger(action); 150 | ck_assert(ctx == 5); 151 | } 152 | END_TEST 153 | 154 | START_TEST(callback_trigger_single_sub) { 155 | int ctx; 156 | callback_subscribe(callback, &ctx, callback_set); 157 | callback_trigger(callback, 20, 10); 158 | ck_assert(ctx == 10); 159 | } 160 | END_TEST 161 | 162 | START_TEST(gds_event_trigger_single_sub) { 163 | int ctx; 164 | gds_event_subscribe(gds_event, &ctx, gds_event_set); 165 | GDS_EVENT_TRIGGER(gds_event, GDS_EVENT_SIGNATURE(int), 13); 166 | ck_assert(ctx = 13); 167 | } 168 | END_TEST 169 | 170 | START_TEST(action_trigger_multiple_subs) { 171 | int ctx1, ctx2; 172 | action_subscribe(action, &ctx1, action_set); 173 | action_subscribe(action, &ctx2, action_set); 174 | action_trigger(action); 175 | ck_assert(ctx1 == 5); 176 | ck_assert(ctx2 == 5); 177 | } 178 | END_TEST 179 | 180 | START_TEST(callback_trigger_multiple_subs) { 181 | int ctx1, ctx2; 182 | callback_subscribe(callback, &ctx1, callback_set); 183 | callback_subscribe(callback, &ctx2, callback_set); 184 | callback_trigger(callback, 20, 10); 185 | ck_assert(ctx1 == 10); 186 | ck_assert(ctx2 == 10); 187 | } 188 | END_TEST 189 | 190 | START_TEST(gds_event_trigger_multiple_subs) { 191 | int ctx1, ctx2; 192 | gds_event_subscribe(gds_event, &ctx1, gds_event_set); 193 | gds_event_subscribe(gds_event, &ctx2, gds_event_set); 194 | GDS_EVENT_TRIGGER(gds_event, GDS_EVENT_SIGNATURE(int), 15); 195 | ck_assert(ctx1 = 15); 196 | ck_assert(ctx2 = 15); 197 | } 198 | END_TEST 199 | 200 | static int global_value = 0; 201 | static void incr_global_value(void* ctx) { 202 | global_value++; 203 | } 204 | 205 | START_TEST(gds_event_trigger_no_args) { 206 | int pre = global_value; 207 | ck_assert(gds_event_subscribe(gds_event, NULL, incr_global_value)); 208 | GDS_EVENT_TRIGGER(gds_event, GDS_EVENT_DEFAULT); 209 | ck_assert(global_value == pre + 1); 210 | } 211 | END_TEST 212 | 213 | int main(void) { 214 | Suite* s = suite_create("Event Tests"); 215 | TCase* tc = tcase_create("Event Tests"); 216 | 217 | tcase_add_checked_fixture(tc, event_start, event_reset); 218 | tcase_add_test(tc, action_allocate_and_deallocate); 219 | tcase_add_test(tc, callback_allocate_and_deallocate); 220 | tcase_add_test(tc, gds_event_allocate_and_deallocate); 221 | tcase_add_test(tc, action_subscribe_true); 222 | tcase_add_test(tc, callback_subscribe_true); 223 | tcase_add_test(tc, gds_event_subscribe_true); 224 | tcase_add_test(tc, action_unsubscribe_true); 225 | tcase_add_test(tc, callback_unsubscribe_true); 226 | tcase_add_test(tc, gds_event_unsubscribe_true); 227 | tcase_add_test(tc, action_unsubscribe_different_context); 228 | tcase_add_test(tc, callback_unsubscribe_different_context); 229 | tcase_add_test(tc, gds_event_unsubscribe_different_context); 230 | tcase_add_test(tc, action_unsubscribe_different_function); 231 | tcase_add_test(tc, callback_unsubscribe_different_function); 232 | tcase_add_test(tc, gds_event_unsubscribe_different_function); 233 | tcase_add_test(tc, action_trigger_single_sub); 234 | tcase_add_test(tc, callback_trigger_single_sub); 235 | tcase_add_test(tc, gds_event_trigger_single_sub); 236 | tcase_add_test(tc, action_trigger_multiple_subs); 237 | tcase_add_test(tc, callback_trigger_multiple_subs); 238 | tcase_add_test(tc, gds_event_trigger_multiple_subs); 239 | tcase_add_test(tc, gds_event_trigger_no_args); 240 | 241 | suite_add_tcase(s, tc); 242 | 243 | SRunner* sr = srunner_create(s); 244 | srunner_run_all(sr, CK_NORMAL); 245 | int number_failed = srunner_ntests_failed(sr); 246 | srunner_free(sr); 247 | 248 | return number_failed == 0 ? EXIT_SUCCESS : EXIT_FAILURE; 249 | } -------------------------------------------------------------------------------- /tests/grid_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../include/generic_grid.h" 4 | 5 | GRID_DEFINE_H(IntGrid, ig, int) 6 | 7 | GRID_DEFINE_C(IntGrid, ig, int) 8 | 9 | static IntGrid* grid; 10 | 11 | void grid_start(void) { 12 | grid = ig_create(5, 5); 13 | } 14 | 15 | void grid_reset(void) { 16 | ig_free(grid); 17 | } 18 | 19 | START_TEST(grid_allocate_and_deallocate) { 20 | IntGrid temp1; 21 | ig_init(&temp1, 2, 2); 22 | ck_assert(temp1.grid); 23 | ig_free_resources(&temp1); 24 | IntGrid* temp2 = ig_create(2, 2); 25 | ck_assert(temp2->grid); 26 | ig_free(temp2); 27 | } 28 | END_TEST 29 | 30 | START_TEST(grid_check_width) { 31 | ck_assert(ig_width(grid) == 5); 32 | } 33 | END_TEST 34 | 35 | START_TEST(grid_check_height) { 36 | ck_assert(ig_height(grid) == 5); 37 | } 38 | END_TEST 39 | 40 | START_TEST(grid_get_and_set) { 41 | for(int i = 0; i < 5; i++) { 42 | ig_set(grid, i, i, i); 43 | } 44 | 45 | for(int i = 0; i < 5; i++) { 46 | ck_assert(ig_get(grid, i, i) == i); 47 | } 48 | } 49 | END_TEST 50 | 51 | START_TEST(grid_clears_sets_all) { 52 | ig_clear(grid, 12); 53 | for(int h = 0; h < ig_height(grid); h++) { 54 | for(int w = 0; w < ig_width(grid); w++) { 55 | ck_assert(ig_get(grid, w, h) == 12); 56 | } 57 | } 58 | } 59 | END_TEST 60 | 61 | int main(void) { 62 | Suite* s = suite_create("Grid Tests"); 63 | TCase* tc = tcase_create("Grid Tests"); 64 | 65 | tcase_add_checked_fixture(tc, grid_start, grid_reset); 66 | tcase_add_test(tc, grid_check_width); 67 | tcase_add_test(tc, grid_check_height); 68 | tcase_add_test(tc, grid_get_and_set); 69 | tcase_add_test(tc, grid_clears_sets_all); 70 | 71 | suite_add_tcase(s, tc); 72 | 73 | SRunner* sr = srunner_create(s); 74 | srunner_run_all(sr, CK_NORMAL); 75 | int number_failed = srunner_ntests_failed(sr); 76 | srunner_free(sr); 77 | 78 | return number_failed == 0 ? EXIT_SUCCESS : EXIT_FAILURE; 79 | } -------------------------------------------------------------------------------- /tests/list_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../include/generic_list.h" 4 | #include "../include/generic_iterators/list_iterator.h" 5 | 6 | LIST_DEFINE_H(IntList, il, int) 7 | 8 | LIST_DEFINE_C(IntList, il, int) 9 | 10 | IntList* list; 11 | 12 | void list_start(void) { 13 | list = il_create(); 14 | } 15 | 16 | void list_reset(void) { 17 | il_free(list); 18 | } 19 | 20 | START_TEST(list_allocate_and_deallocate) { 21 | IntList temp1; 22 | ck_assert(il_init(&temp1)); 23 | il_free_resources(&temp1); 24 | ck_assert(il_init_capacity(&temp1, 8)); 25 | il_free_resources(&temp1); 26 | IntList* temp2 = il_create(); 27 | ck_assert(temp2); 28 | il_free(temp2); 29 | } 30 | END_TEST 31 | 32 | START_TEST(list_add_increments_count) { 33 | for(int i = 0; i < 10; i++) { 34 | il_add(list, i); 35 | ck_assert(il_count(list) == i + 1); 36 | } 37 | } 38 | END_TEST 39 | 40 | START_TEST(list_get_returns_value) { 41 | for(int i = 0; i < 10; i++) 42 | il_add(list, i); 43 | 44 | for(int i = 0; i < 10; i++) 45 | ck_assert(il_get(list, i) == i); 46 | } 47 | END_TEST 48 | 49 | START_TEST(list_set_existing_index_overwrites) { 50 | for(int i = 0; i < 4; i++) 51 | il_add(list, i); 52 | 53 | ck_assert(il_count(list) == 4); 54 | il_set(list, 2, 8); 55 | ck_assert(il_count(list) == 4); 56 | 57 | ck_assert(il_get(list, 2) == 8); 58 | } 59 | END_TEST 60 | 61 | START_TEST(list_set_at_list_count_adds) { 62 | for(int i = 0; i < 4; i++) 63 | il_add(list, i); 64 | 65 | il_set(list, 4, 4); 66 | ck_assert(il_count(list) == 5); 67 | ck_assert(il_get(list, 4) == 4); 68 | } 69 | END_TEST 70 | 71 | START_TEST(list_remove_middle_index_shifts_elements) { 72 | for(int i = 0; i < 6; i++) 73 | il_add(list, i); 74 | 75 | il_remove(list, 0); 76 | ck_assert(il_count(list) == 5); 77 | 78 | for(int i = 1; i < 6; i++) 79 | ck_assert(il_get(list, i - 1) == i); 80 | 81 | il_remove(list, 3); 82 | ck_assert(il_count(list) == 4); 83 | 84 | int values[] = { 1, 2, 3, 5 }; 85 | 86 | for(int i = 0; i < 4; i++) 87 | ck_assert(il_get(list, i) == values[i]); 88 | } 89 | END_TEST 90 | 91 | START_TEST(list_remove_end_keeps_order) { 92 | for(int i = 0; i < 6; i++) 93 | il_add(list, i); 94 | 95 | il_remove(list, 5); 96 | for(int i = 0; i < 5; i++) 97 | ck_assert(il_get(list, i) == i); 98 | } 99 | END_TEST 100 | 101 | START_TEST(list_peek_gets_last_value_without_removing) { 102 | il_add(list, 4); 103 | ck_assert(il_peek(list) == 4); 104 | ck_assert(il_count(list) == 1); 105 | il_add(list, 7); 106 | ck_assert(il_peek(list) == 7); 107 | ck_assert(il_count(list) == 2); 108 | } 109 | END_TEST 110 | 111 | START_TEST(list_pop_gets_last_value_and_removes) { 112 | il_add(list, 4); 113 | il_add(list, 7); 114 | ck_assert(il_pop(list) == 7); 115 | ck_assert(il_count(list) == 1); 116 | ck_assert(il_pop(list) == 4); 117 | ck_assert(il_count(list) == 0); 118 | } 119 | END_TEST 120 | 121 | START_TEST(list_insert_middle_shifts_values) { 122 | for(int i = 1; i < 6; i++) 123 | il_add(list, i); 124 | 125 | il_insert(list, 0, 0); 126 | for(int i = 0; i < 6; i++) 127 | ck_assert(il_get(list, i) == i); 128 | 129 | il_insert(list, 2, 22); 130 | 131 | int values[] = { 0, 1, 22, 2, 3, 4, 5 }; 132 | for(int i = 0; i < 7; i++) 133 | ck_assert(il_get(list, i) == values[i]); 134 | } 135 | END_TEST 136 | 137 | START_TEST(list_insert_end_adds_value) { 138 | for(int i = 0; i < 5; i++) 139 | il_add(list, i); 140 | 141 | il_insert(list, 5, 5); 142 | 143 | for(int i = 0; i < 6; i++) 144 | ck_assert(il_get(list, i) == i); 145 | } 146 | END_TEST 147 | 148 | START_TEST(list_iter_all) { 149 | for(int i = 0; i < 5; i++) 150 | il_add(list, i); 151 | 152 | int value; 153 | int current = 0; 154 | list_iter_start(list, value) { 155 | ck_assert(current == value); 156 | current++; 157 | } 158 | list_iter_end 159 | ck_assert(current == 5); 160 | } 161 | END_TEST 162 | 163 | START_TEST(list_iter_some) { 164 | for(int i = 0; i < 5; i++) 165 | il_add(list, i); 166 | 167 | int value; 168 | int current = 0; 169 | list_iter_start(list, value) { 170 | ck_assert(current == value); 171 | current++; 172 | if(current == 3) 173 | break; 174 | } 175 | list_iter_end 176 | ck_assert(current == 3); 177 | } 178 | END_TEST 179 | 180 | int main(void) { 181 | Suite* s = suite_create("List Tests"); 182 | TCase* tc = tcase_create("List Tests"); 183 | 184 | tcase_add_checked_fixture(tc, list_start, list_reset); 185 | tcase_add_test(tc, list_allocate_and_deallocate); 186 | tcase_add_test(tc, list_add_increments_count); 187 | tcase_add_test(tc, list_get_returns_value); 188 | tcase_add_test(tc, list_set_existing_index_overwrites); 189 | tcase_add_test(tc, list_set_at_list_count_adds); 190 | tcase_add_test(tc, list_remove_middle_index_shifts_elements); 191 | tcase_add_test(tc, list_remove_end_keeps_order); 192 | tcase_add_test(tc, list_peek_gets_last_value_without_removing); 193 | tcase_add_test(tc, list_pop_gets_last_value_and_removes); 194 | tcase_add_test(tc, list_insert_middle_shifts_values); 195 | tcase_add_test(tc, list_insert_end_adds_value); 196 | tcase_add_test(tc, list_iter_all); 197 | tcase_add_test(tc, list_iter_some); 198 | 199 | suite_add_tcase(s, tc); 200 | 201 | SRunner* sr = srunner_create(s); 202 | srunner_run_all(sr, CK_NORMAL); 203 | int number_failed = srunner_ntests_failed(sr); 204 | srunner_free(sr); 205 | 206 | return number_failed == 0 ? EXIT_SUCCESS : EXIT_FAILURE; 207 | } -------------------------------------------------------------------------------- /tests/map_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "../include/generic_map.h" 7 | #include "../include/generic_iterators/map_iterator.h" 8 | 9 | MAP_DEFINE_H(StringMap, string_map, char*, char*) 10 | 11 | MAP_DEFINE_C(StringMap, string_map, char*, char*, gds_fnv32, strcmp) 12 | 13 | static StringMap* map; 14 | 15 | static char* ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 16 | 17 | void map_start(void) { 18 | map = string_map_create(); 19 | } 20 | 21 | void map_reset(void) { 22 | string_map_free(map); 23 | } 24 | 25 | START_TEST(map_allocate_and_deallocate) { 26 | StringMap temp; 27 | ck_assert(string_map_init(&temp)); 28 | string_map_free_resources(&temp); 29 | } 30 | END_TEST 31 | 32 | START_TEST(map_add_new_key_adds) { 33 | ck_assert(string_map_add(map, "hello", "world")); 34 | ck_assert(string_map_count(map) == 1); 35 | } 36 | END_TEST 37 | 38 | START_TEST(map_add_duplicate_key_doesnt_add) { 39 | ck_assert(string_map_add(map, "hello", "world")); 40 | ck_assert(!string_map_add(map, "hello", "new world")); 41 | } 42 | END_TEST 43 | 44 | START_TEST(map_get_existing_key_returns_value) { 45 | string_map_add(map, "hello", "world"); 46 | ck_assert(strcmp(string_map_get(map, "hello"), "world") == 0); 47 | } 48 | END_TEST 49 | 50 | START_TEST(map_get_missing_key_returns_default) { 51 | ck_assert(string_map_get(map, "hello") == NULL); 52 | } 53 | END_TEST 54 | 55 | START_TEST(map_set_new_key_add) { 56 | ck_assert(string_map_count(map) == 0); 57 | string_map_set(map, "Alexander", "Hamilton"); 58 | ck_assert(string_map_count(map) == 1); 59 | ck_assert(strcmp(string_map_get(map, "Alexander"), "Hamilton") == 0); 60 | } 61 | END_TEST 62 | 63 | START_TEST(map_set_existing_key_replaces) { 64 | string_map_add(map, "hello", "world"); 65 | ck_assert(strcmp(string_map_get(map, "hello"), "world") == 0); 66 | string_map_set(map, "hello", "new world"); 67 | ck_assert(strcmp(string_map_get(map, "hello"), "new world") == 0); 68 | } 69 | END_TEST 70 | 71 | START_TEST(map_remove_existing_key_removes) { 72 | string_map_add(map, "hello", "world"); 73 | ck_assert(string_map_count(map) == 1); 74 | ck_assert(string_map_remove(map, "hello")); 75 | ck_assert(string_map_count(map) == 0); 76 | } 77 | END_TEST 78 | 79 | START_TEST(map_remove_missing_key_returns_false) { 80 | ck_assert(!string_map_remove(map, "hello")); 81 | } 82 | END_TEST 83 | 84 | START_TEST(map_resizes_when_load_factor_is_hit) { 85 | uint32_t capacity = map->capacity; 86 | uint32_t load_factor = map->load_factor; 87 | for(int i = 0; i <= load_factor; i++) 88 | string_map_add(map, ALPHABET + i, ALPHABET + i); 89 | ck_assert(map->capacity != capacity); 90 | } 91 | END_TEST 92 | 93 | START_TEST(map_clear_can_keeps_capacity) { 94 | uint32_t load_factor = map->load_factor; 95 | 96 | for(int i = 0; i <= load_factor; i++) 97 | string_map_add(map, ALPHABET + i, ALPHABET + i); 98 | 99 | uint32_t capacity = map->capacity; 100 | string_map_clear(map, false); 101 | ck_assert(map->capacity == capacity); 102 | ck_assert(map->count == 0); 103 | } 104 | END_TEST 105 | 106 | START_TEST(map_clear_can_reset_capacity) { 107 | uint32_t load_factor = map->load_factor; 108 | 109 | for(int i = 0; i <= load_factor; i++) 110 | string_map_add(map, ALPHABET + i, ALPHABET + i); 111 | 112 | string_map_clear(map, true); 113 | ck_assert(map->capacity == 0); 114 | ck_assert(map->count == 0); 115 | } 116 | END_TEST 117 | 118 | START_TEST(map_iter_all) { 119 | StringMap forward; 120 | StringMap reverse; 121 | string_map_init(&forward); 122 | string_map_init(&reverse); 123 | for(int i = 0; i < 26; i++) { 124 | char* mem; 125 | mem = calloc(8, sizeof(char)); 126 | mem[2] = 'a' + i; 127 | mem[0] = 'z' - i; 128 | mem[4] = 'z' - i; 129 | mem[6] = 'a' + i; 130 | string_map_add(&forward, mem + 2, mem + 0); 131 | string_map_add(&reverse, mem + 4, mem + 6); 132 | } 133 | char* key; 134 | char* value; 135 | int count = 0; 136 | map_iter_start(&forward, key, value) 137 | { 138 | ck_assert(strcmp(string_map_get(&reverse, key), value) == 0); 139 | ck_assert(strcmp(string_map_get(&reverse, value), key) == 0); 140 | count++; 141 | } 142 | map_iter_end 143 | 144 | ck_assert(count == 26); 145 | for(int i = 0; i < 26; i++) { 146 | char temp[2] = { 'a' + i, 0 }; 147 | free(string_map_get(&forward, temp)); 148 | } 149 | string_map_free_resources(&forward); 150 | string_map_free_resources(&reverse); 151 | } 152 | END_TEST 153 | 154 | START_TEST(map_iter_some) { 155 | StringMap forward; 156 | StringMap reverse; 157 | string_map_init(&forward); 158 | string_map_init(&reverse); 159 | for(int i = 0; i < 26; i++) { 160 | char* mem; 161 | mem = calloc(8, sizeof(char)); 162 | mem[2] = 'a' + i; 163 | mem[0] = 'z' - i; 164 | mem[4] = 'z' - i; 165 | mem[6] = 'a' + i; 166 | string_map_add(&forward, mem + 2, mem + 0); 167 | string_map_add(&reverse, mem + 4, mem + 6); 168 | } 169 | char* key; 170 | char* value; 171 | int count = 0; 172 | map_iter_start(&forward, key, value) 173 | { 174 | ck_assert(strcmp(string_map_get(&reverse, key), value) == 0); 175 | ck_assert(strcmp(string_map_get(&reverse, value), key) == 0); 176 | count++; 177 | 178 | if(count == 13) 179 | break; 180 | } 181 | map_iter_end 182 | 183 | ck_assert(count == 13); 184 | for(int i = 0; i < 26; i++) { 185 | char temp[2] = { 'a' + i, 0 }; 186 | free(string_map_get(&forward, temp)); 187 | } 188 | string_map_free_resources(&forward); 189 | string_map_free_resources(&reverse); 190 | } 191 | END_TEST 192 | 193 | START_TEST(map_iter_keys) { 194 | StringMap forward; 195 | StringMap reverse; 196 | string_map_init(&forward); 197 | string_map_init(&reverse); 198 | for(int i = 0; i < 26; i++) { 199 | char* mem; 200 | mem = calloc(8, sizeof(char)); 201 | mem[2] = 'a' + i; 202 | mem[0] = 'z' - i; 203 | mem[4] = 'z' - i; 204 | mem[6] = 'a' + i; 205 | string_map_add(&forward, mem + 2, mem + 0); 206 | string_map_add(&reverse, mem + 4, mem + 6); 207 | } 208 | char* key; 209 | int count = 0; 210 | map_iter_key_start(&forward, key) 211 | { 212 | char temp[2] = { 'a' + ('z' - key[0]), 0 }; 213 | ck_assert(strcmp(string_map_get(&reverse, key), temp) == 0); 214 | count++; 215 | } 216 | map_iter_end 217 | 218 | ck_assert(count == 26); 219 | for(int i = 0; i < 26; i++) { 220 | char temp[2] = { 'a' + i, 0 }; 221 | free(string_map_get(&forward, temp)); 222 | } 223 | string_map_free_resources(&forward); 224 | string_map_free_resources(&reverse); 225 | } 226 | END_TEST 227 | 228 | START_TEST(map_iter_values) { 229 | StringMap forward; 230 | StringMap reverse; 231 | string_map_init(&forward); 232 | string_map_init(&reverse); 233 | for(int i = 0; i < 26; i++) { 234 | char* mem; 235 | mem = calloc(8, sizeof(char)); 236 | mem[2] = 'a' + i; 237 | mem[0] = 'z' - i; 238 | mem[4] = 'z' - i; 239 | mem[6] = 'a' + i; 240 | string_map_add(&forward, mem + 2, mem + 0); 241 | string_map_add(&reverse, mem + 4, mem + 6); 242 | } 243 | char* value; 244 | int count = 0; 245 | map_iter_key_start(&forward, value) 246 | { 247 | char temp[2] = { 'a' + ('z' - value[0]), 0 }; 248 | ck_assert(strcmp(string_map_get(&reverse, value), temp) == 0); 249 | count++; 250 | } 251 | map_iter_end 252 | 253 | ck_assert(count == 26); 254 | for(int i = 0; i < 26; i++) { 255 | char temp[2] = { 'a' + i, 0 }; 256 | free(string_map_get(&forward, temp)); 257 | } 258 | string_map_free_resources(&forward); 259 | string_map_free_resources(&reverse); 260 | } 261 | END_TEST 262 | 263 | int main(void) { 264 | Suite* s = suite_create("Map Tests"); 265 | TCase* tc = tcase_create("Map Tests"); 266 | 267 | tcase_add_checked_fixture(tc, map_start, map_reset); 268 | tcase_add_test(tc, map_allocate_and_deallocate); 269 | tcase_add_test(tc, map_add_new_key_adds); 270 | tcase_add_test(tc, map_add_duplicate_key_doesnt_add); 271 | tcase_add_test(tc, map_get_existing_key_returns_value); 272 | tcase_add_test(tc, map_get_missing_key_returns_default); 273 | tcase_add_test(tc, map_set_new_key_add); 274 | tcase_add_test(tc, map_set_existing_key_replaces); 275 | tcase_add_test(tc, map_remove_existing_key_removes); 276 | tcase_add_test(tc, map_remove_missing_key_returns_false); 277 | tcase_add_test(tc, map_resizes_when_load_factor_is_hit); 278 | tcase_add_test(tc, map_iter_all); 279 | tcase_add_test(tc, map_iter_some); 280 | tcase_add_test(tc, map_iter_keys); 281 | tcase_add_test(tc, map_iter_values); 282 | 283 | suite_add_tcase(s, tc); 284 | 285 | SRunner* sr = srunner_create(s); 286 | srunner_run_all(sr, CK_NORMAL); 287 | int number_failed = srunner_ntests_failed(sr); 288 | srunner_free(sr); 289 | 290 | return number_failed == 0 ? EXIT_SUCCESS : EXIT_FAILURE; 291 | } -------------------------------------------------------------------------------- /tests/meson.build: -------------------------------------------------------------------------------- 1 | if check_location != '' 2 | check_lib = check_location + '/lib' 3 | 4 | compat = c_comp.find_library( 5 | 'compat', 6 | required: true, 7 | dirs: check_lib) 8 | 9 | check = c_comp.find_library( 10 | 'check', 11 | required: true, 12 | dirs: check_lib) 13 | 14 | deps = [compat, check] 15 | else 16 | check = c_comp.find_library('check', required: true) 17 | test_inc = inc 18 | deps = [check] 19 | endif 20 | 21 | link_args = [] 22 | 23 | if c_comp.get_id() == 'msvc' and get_option('buildtype') == 'release' 24 | link_args += '/NODEFAULTLIB:MSVCRTD' 25 | endif 26 | 27 | rb_tree_test = executable( 28 | 'rb_tree_test', 29 | 'rb_tree_test.c', 30 | link_args: link_args, 31 | include_directories: test_inc, 32 | dependencies: deps 33 | ) 34 | 35 | map_test = executable( 36 | 'map_test', 37 | 'map_test.c', 38 | link_args: link_args, 39 | include_directories: test_inc, 40 | dependencies: deps 41 | ) 42 | 43 | set_test = executable( 44 | 'set_test', 45 | 'set_test.c', 46 | link_args: link_args, 47 | include_directories: test_inc, 48 | dependencies: deps 49 | ) 50 | 51 | queue_test = executable( 52 | 'queue_test', 53 | 'queue_test.c', 54 | link_args: link_args, 55 | include_directories: test_inc, 56 | dependencies: deps 57 | ) 58 | 59 | deque_test = executable( 60 | 'deque_test', 61 | 'deque_test.c', 62 | link_args: link_args, 63 | include_directories: test_inc, 64 | dependencies: deps 65 | ) 66 | 67 | list_test = executable( 68 | 'list_test', 69 | 'list_test.c', 70 | link_args: link_args, 71 | include_directories: test_inc, 72 | dependencies: deps 73 | ) 74 | 75 | grid_test = executable( 76 | 'grid_test', 77 | 'grid_test.c', 78 | link_args: link_args, 79 | include_directories: test_inc, 80 | dependencies: deps 81 | ) 82 | 83 | pool_test = executable( 84 | 'pool_test', 85 | 'pool_test.c', 86 | link_args: link_args, 87 | include_directories: test_inc, 88 | dependencies: deps 89 | ) 90 | 91 | event_test = executable( 92 | 'event_test', 93 | 'event_test.c', 94 | link_args: link_args, 95 | include_directories: test_inc, 96 | dependencies: deps 97 | ) 98 | 99 | trie_test = executable( 100 | 'trie_test', 101 | 'trie_test.c', 102 | link_args: link_args, 103 | include_directories: test_inc, 104 | dependencies: deps 105 | ) 106 | 107 | option_test = executable( 108 | 'option_test', 109 | 'option_test.c', 110 | link_args: link_args, 111 | include_directories: test_inc, 112 | dependencies: deps 113 | ) 114 | 115 | test('RB Tree Test', rb_tree_test) 116 | test('Map Test', map_test) 117 | test('Set Test', set_test) 118 | test('Queue Test', queue_test) 119 | test('Deque Test', deque_test) 120 | test('List Test', list_test) 121 | test('Grid Test', grid_test) 122 | test('Pool Test', pool_test) 123 | test('Event Test', event_test) 124 | test('Trie Test', trie_test) 125 | test('Option Test', option_test) -------------------------------------------------------------------------------- /tests/option_test.c: -------------------------------------------------------------------------------- 1 | #include "../include/generic_option.h" 2 | #include 3 | 4 | #include 5 | 6 | OPTION_DEFINE_H(OptionalInt, opt_int, int) 7 | 8 | START_TEST(option_make_function) { 9 | OptionalInt option = opt_int_make(2); 10 | ck_assert(option.value == 2); 11 | ck_assert(option.has_value); 12 | } 13 | END_TEST 14 | 15 | START_TEST(option_make_macro) { 16 | OptionalInt option = gds_option_make(OptionalInt, 3); 17 | ck_assert(option.value == 3); 18 | ck_assert(option.has_value); 19 | } 20 | END_TEST 21 | 22 | START_TEST(option_default_function) { 23 | OptionalInt option = opt_int_default(); 24 | ck_assert(!option.has_value); 25 | } 26 | END_TEST 27 | 28 | START_TEST(option_default_macro) { 29 | OptionalInt option = gds_option_default(OptionalInt); 30 | ck_assert(!option.has_value); 31 | } 32 | END_TEST 33 | 34 | START_TEST(option_has_value_function) { 35 | OptionalInt option = opt_int_make(4); 36 | ck_assert(opt_int_has_value(option)); 37 | option = opt_int_default(); 38 | ck_assert(!opt_int_has_value(option)); 39 | } 40 | END_TEST 41 | 42 | START_TEST(option_has_value_macro) { 43 | OptionalInt option = opt_int_make(5); 44 | ck_assert(gds_option_has_value(option)); 45 | option = opt_int_default(); 46 | ck_assert(!gds_option_has_value(option)); 47 | } 48 | END_TEST 49 | 50 | START_TEST(option_value_function) { 51 | OptionalInt option = opt_int_make(6); 52 | ck_assert(opt_int_value(option) == 6); 53 | } 54 | END_TEST 55 | 56 | START_TEST(option_value_macro) { 57 | OptionalInt option = opt_int_make(7); 58 | ck_assert(gds_option_value(option)); 59 | } 60 | END_TEST 61 | 62 | START_TEST(option_value_or_default_function) { 63 | OptionalInt option = opt_int_make(8); 64 | ck_assert(opt_int_value_or_default(option) == 8); 65 | option = opt_int_default(); 66 | ck_assert(opt_int_value_or_default(option) == 0); 67 | } 68 | END_TEST 69 | 70 | START_TEST(option_value_or_default_macro) { 71 | OptionalInt option = opt_int_make(9); 72 | ck_assert(gds_option_value_or_default(option) == 9); 73 | option = opt_int_default(); 74 | ck_assert(gds_option_value_or_default(option) == 0); 75 | } 76 | END_TEST 77 | 78 | int main(void) { 79 | Suite* s = suite_create("Optional Value Tests"); 80 | TCase* tc = tcase_create("Optional Value Tests"); 81 | 82 | tcase_add_test(tc, option_make_function); 83 | tcase_add_test(tc, option_make_macro); 84 | tcase_add_test(tc, option_default_function); 85 | tcase_add_test(tc, option_default_macro); 86 | tcase_add_test(tc, option_has_value_function); 87 | tcase_add_test(tc, option_has_value_macro); 88 | tcase_add_test(tc, option_value_function); 89 | tcase_add_test(tc, option_value_macro); 90 | tcase_add_test(tc, option_value_or_default_function); 91 | tcase_add_test(tc, option_value_or_default_macro); 92 | 93 | 94 | suite_add_tcase(s, tc); 95 | 96 | SRunner* sr = srunner_create(s); 97 | srunner_run_all(sr, CK_NORMAL); 98 | int number_failed = srunner_ntests_failed(sr); 99 | srunner_free(sr); 100 | 101 | return number_failed == 0 ? EXIT_SUCCESS : EXIT_FAILURE; 102 | } -------------------------------------------------------------------------------- /tests/pool_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../include/generic_pool.h" 4 | 5 | #define POOL_INITIAL_VALUE 5 6 | 7 | void int_init(int* i) { *i = POOL_INITIAL_VALUE; } 8 | void int_free_resources(int* i) { } 9 | 10 | POOL_DEFINE_H(IntPool, int_pool, int) 11 | POOL_DEFINE_C(IntPool, int_pool, int, int_init, int_free_resources) 12 | 13 | IntPool* pool; 14 | 15 | void pool_start(void) { 16 | pool = int_pool_create(); 17 | } 18 | 19 | void pool_reset(void) { 20 | int_pool_free(pool); 21 | } 22 | 23 | START_TEST(pool_allocate_and_deallocate) { 24 | IntPool value; 25 | ck_assert(int_pool_init(&value)); 26 | int_pool_free_resources(&value); 27 | 28 | IntPool* ptr = int_pool_create(); 29 | ck_assert(ptr); 30 | int_pool_free(ptr); 31 | } 32 | END_TEST 33 | 34 | START_TEST(pool_get_value) { 35 | int* i = int_pool_get(pool); 36 | ck_assert(*i == POOL_INITIAL_VALUE); 37 | } 38 | END_TEST 39 | 40 | START_TEST(pool_release_value) { 41 | int* i = int_pool_get(pool); 42 | ck_assert(*i == POOL_INITIAL_VALUE); 43 | ck_assert(int_pool_release(pool, i)); 44 | } 45 | END_TEST 46 | 47 | START_TEST(pool_get_released_value_reuses_memory) { 48 | int* i = int_pool_get(pool); 49 | int* j = int_pool_get(pool); 50 | int* copy = i; 51 | ck_assert(int_pool_release(pool, i)); 52 | i = int_pool_get(pool); 53 | ck_assert(i == copy); 54 | } 55 | END_TEST 56 | 57 | #define POOL_SIZE 1000 58 | 59 | START_TEST(pool_stress_test) { 60 | int** buffer = malloc(POOL_SIZE * sizeof(*buffer)); 61 | 62 | for(int reps = 0; reps < 2; reps++) { 63 | for(int i = 0; i < POOL_SIZE; i++) { 64 | buffer[i] = int_pool_get(pool); 65 | ck_assert(*buffer[i] == POOL_INITIAL_VALUE); 66 | } 67 | 68 | for(int i = 0; i < POOL_SIZE; i++) 69 | ck_assert(int_pool_release(pool, buffer[i])); 70 | } 71 | 72 | free(buffer); 73 | } 74 | END_TEST 75 | 76 | int main(void) { 77 | Suite* s = suite_create("Pool Tests"); 78 | TCase* tc = tcase_create("Pool Tests"); 79 | 80 | tcase_add_checked_fixture(tc, pool_start, pool_reset); 81 | tcase_add_test(tc, pool_allocate_and_deallocate); 82 | tcase_add_test(tc, pool_get_value); 83 | tcase_add_test(tc, pool_release_value); 84 | tcase_add_test(tc, pool_get_released_value_reuses_memory); 85 | tcase_add_test(tc, pool_stress_test); 86 | 87 | 88 | suite_add_tcase(s, tc); 89 | 90 | SRunner* sr = srunner_create(s); 91 | srunner_run_all(sr, CK_NORMAL); 92 | int number_failed = srunner_ntests_failed(sr); 93 | srunner_free(sr); 94 | 95 | return number_failed == 0 ? EXIT_SUCCESS : EXIT_FAILURE; 96 | } -------------------------------------------------------------------------------- /tests/queue_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../include/generic_queue.h" 4 | 5 | QUEUE_DEFINE_H(IntQueue, iq, int) 6 | 7 | QUEUE_DEFINE_C(IntQueue, iq, int) 8 | 9 | 10 | static IntQueue* queue; 11 | 12 | void queue_start(void) { 13 | queue = iq_create(); 14 | } 15 | 16 | void queue_reset(void) { 17 | iq_free(queue); 18 | } 19 | 20 | START_TEST(queue_allocate_and_deallocate) { 21 | IntQueue temp; 22 | ck_assert(iq_init(&temp)); 23 | iq_free_resources(&temp); 24 | 25 | ck_assert(iq_init_capacity(&temp, 8)); 26 | iq_free_resources(&temp); 27 | } 28 | END_TEST 29 | 30 | START_TEST(queue_enqueue_increments_count) { 31 | ck_assert(iq_count(queue) == 0); 32 | for(int i = 0; i < 10; i++) { 33 | iq_enqueue(queue, i); 34 | ck_assert(iq_count(queue) == i + 1); 35 | } 36 | } 37 | END_TEST 38 | 39 | START_TEST(queue_dequeue_gets_value) { 40 | for(int i = 0; i < 4; i++) { 41 | iq_enqueue(queue, i); 42 | } 43 | for(int i = 0; i < 4; i++) { 44 | ck_assert(iq_dequeue(queue) == i); 45 | ck_assert(iq_count(queue) == 3 - i); 46 | } 47 | } 48 | END_TEST 49 | 50 | START_TEST(queue_enqueue_then_dequeue_works_properly) { 51 | for(int i = 0; i < 4; i++) 52 | iq_enqueue(queue, i); 53 | 54 | ck_assert(iq_dequeue(queue) == 0); 55 | iq_enqueue(queue, 4); 56 | ck_assert(queue->capacity == 4); 57 | iq_enqueue(queue, 5); 58 | ck_assert(queue->capacity == 8); 59 | ck_assert(iq_dequeue(queue) == 1); 60 | } 61 | END_TEST 62 | 63 | START_TEST(queue_peek_gets_value_without_removing) { 64 | for(int i = 0; i < 4; i++) 65 | iq_enqueue(queue, i); 66 | 67 | ck_assert(iq_peek(queue) == 0); 68 | ck_assert(iq_count(queue) == 4); 69 | iq_dequeue(queue); 70 | ck_assert(iq_peek(queue) == 1); 71 | } 72 | END_TEST 73 | 74 | START_TEST(queue_clear_clears) { 75 | for(int i = 0; i < 4; i++) 76 | iq_enqueue(queue, i); 77 | 78 | ck_assert(queue->capacity == 4); 79 | ck_assert(queue->count == 4); 80 | iq_clear(queue); 81 | ck_assert(queue->capacity == 4); 82 | ck_assert(queue->count == 0); 83 | 84 | for(int i = 0; i < 4; i++) 85 | iq_enqueue(queue, i); 86 | 87 | ck_assert(queue->capacity == 4); 88 | ck_assert(queue->count == 4); 89 | } 90 | END_TEST 91 | 92 | int main(void) { 93 | Suite* s = suite_create("Queue Tests"); 94 | TCase* tc = tcase_create("Queue Tests"); 95 | 96 | tcase_add_checked_fixture(tc, queue_start, queue_reset); 97 | tcase_add_test(tc, queue_allocate_and_deallocate); 98 | tcase_add_test(tc, queue_enqueue_increments_count); 99 | tcase_add_test(tc, queue_dequeue_gets_value); 100 | tcase_add_test(tc, queue_enqueue_then_dequeue_works_properly); 101 | tcase_add_test(tc, queue_peek_gets_value_without_removing); 102 | tcase_add_test(tc, queue_clear_clears); 103 | 104 | suite_add_tcase(s, tc); 105 | 106 | SRunner* sr = srunner_create(s); 107 | srunner_run_all(sr, CK_NORMAL); 108 | int number_failed = srunner_ntests_failed(sr); 109 | srunner_free(sr); 110 | 111 | return number_failed == 0 ? EXIT_SUCCESS : EXIT_FAILURE; 112 | } -------------------------------------------------------------------------------- /tests/rb_tree_test.c: -------------------------------------------------------------------------------- 1 | #include "../include/generic_rbtree.h" 2 | #include "../include/generic_iterators/rbtree_iterator.h" 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | static inline int int_cmp(int left, int right) { 9 | return left < right ? -1 : (left == right ? 0 : 1); 10 | } 11 | 12 | RBTREE_DEFINE_H(IITree, iitree, int, int) 13 | 14 | RBTREE_DEFINE_C(IITree, iitree, int, int, int_cmp) 15 | 16 | static IITree* tree; 17 | static int test_num = 0; 18 | 19 | void tree_start(void) { 20 | tree = iitree_create(); 21 | } 22 | 23 | void tree_reset(void) { 24 | iitree_free(tree, true); 25 | } 26 | 27 | START_TEST(tree_allocates_and_deallocates_no_elements) { 28 | IITree temp; 29 | iitree_init(&temp); 30 | iitree_free_resources(&temp); 31 | 32 | IITree* tree_ptr = iitree_create(); 33 | iitree_free(tree_ptr, true); 34 | } 35 | END_TEST 36 | 37 | START_TEST(tree_allocates_and_deallocates_some_elements) { 38 | IITree temp; 39 | iitree_init(&temp); 40 | 41 | iitree_add(&temp, 0, 0); 42 | iitree_add(&temp, 1, 1); 43 | 44 | ck_assert(iitree_count(&temp) == 2); 45 | 46 | iitree_free_resources(&temp); 47 | 48 | ck_assert(iitree_count(&temp) == 0); 49 | 50 | IITree* tree_ptr = iitree_create(); 51 | 52 | iitree_add(tree_ptr, 0, 0); 53 | iitree_add(tree_ptr, 1, 1); 54 | 55 | ck_assert(iitree_count(tree_ptr) == 2); 56 | 57 | iitree_free(tree_ptr, true); 58 | } 59 | END_TEST 60 | 61 | START_TEST(tree_adds_items_in_order_simple) { 62 | for(int i = 0; i < 6; i++) { 63 | iitree_add(tree, i, i); 64 | } 65 | 66 | ck_assert(iitree_count(tree) == 6); 67 | 68 | int value = 0; 69 | int index = 0; 70 | IITreeNode** stack = malloc(sizeof(IITreeNode*) * 6); 71 | IITreeNode* node = iitree_root(tree); 72 | while(node != NULL) { 73 | while(node->left != NULL) { 74 | stack[index++] = node; 75 | node = node->left; 76 | } 77 | ck_assert(value == node->value); 78 | value++; 79 | while(node->right == NULL && index > 0) { 80 | node = stack[--index]; 81 | ck_assert(value == node->value); 82 | value++; 83 | } 84 | node = node->right; 85 | } 86 | free(stack); 87 | } 88 | END_TEST 89 | 90 | START_TEST(tree_adds_items_in_order_complex) { 91 | iitree_add(tree, 0, 0); 92 | iitree_add(tree, 5, 5); 93 | iitree_add(tree, 2, 2); 94 | iitree_add(tree, 1, 1); 95 | iitree_add(tree, 4, 4); 96 | iitree_add(tree, 3, 3); 97 | 98 | ck_assert(iitree_count(tree) == 6); 99 | 100 | int value = 0; 101 | int index = 0; 102 | IITreeNode** stack = malloc(sizeof(IITreeNode*) * 6); 103 | IITreeNode* node = iitree_root(tree); 104 | while(node != NULL) { 105 | while(node->left != NULL) { 106 | stack[index++] = node; 107 | node = node->left; 108 | } 109 | ck_assert(value == node->value); 110 | value++; 111 | while(node->right == NULL && index > 0) { 112 | node = stack[--index]; 113 | ck_assert(value == node->value); 114 | value++; 115 | } 116 | node = node->right; 117 | 118 | } 119 | free(stack); 120 | } 121 | END_TEST 122 | 123 | START_TEST(tree_remove_root) { 124 | ck_assert(iitree_root(tree) == NULL); 125 | 126 | iitree_add(tree, 1, 1); 127 | 128 | ck_assert(iitree_root(tree) != NULL); 129 | ck_assert(iitree_count(tree) == 1); 130 | 131 | ck_assert(iitree_remove(tree, 1, NULL)); 132 | 133 | ck_assert(iitree_root(tree) == NULL); 134 | ck_assert(iitree_count(tree) == 0); 135 | } 136 | END_TEST 137 | 138 | START_TEST(tree_remove_preserves_order) { 139 | int values[] = { 0, 1, 2, 4, 5 }; 140 | 141 | for(int i = 0; i < 6; i++) { 142 | iitree_add(tree, i, i); 143 | } 144 | 145 | iitree_remove(tree, 3, NULL); 146 | 147 | int value = 0; 148 | int index = 0; 149 | IITreeNode** stack = malloc(sizeof(IITreeNode*) * iitree_count(tree)); 150 | IITreeNode* node = iitree_root(tree); 151 | while(node != NULL) { 152 | while(node->left != NULL) { 153 | stack[index++] = node; 154 | node = node->left; 155 | } 156 | ck_assert(values[value] == node->value); 157 | value++; 158 | while(node->right == NULL && index > 0) { 159 | node = stack[--index]; 160 | ck_assert(values[value] == node->value); 161 | value++; 162 | } 163 | node = node->right; 164 | } 165 | 166 | free(stack); 167 | } 168 | END_TEST 169 | 170 | START_TEST(tree_remove_min_removes_min) { 171 | for(int i = 0; i < 6; i++) 172 | iitree_add(tree, i, i); 173 | 174 | for(int i = 0; i < 6; i++) { 175 | int value; 176 | iitree_remove_min(tree, &value); 177 | ck_assert(value == i); 178 | } 179 | } 180 | END_TEST 181 | 182 | START_TEST(tree_remove_max_removes_max) { 183 | for(int i = 0; i < 6; i++) 184 | iitree_add(tree, i, i); 185 | 186 | for(int i = 5; i >= 0; i--) { 187 | int value; 188 | iitree_remove_max(tree, &value); 189 | ck_assert(value == i); 190 | } 191 | } 192 | END_TEST 193 | 194 | START_TEST(tree_get_invalid_key_returns_false) { 195 | for(int i = 0; i < 6; i++) 196 | iitree_add(tree, i, i); 197 | 198 | int value; 199 | ck_assert(!iitree_get(tree, 10, &value)); 200 | } 201 | END_TEST 202 | 203 | START_TEST(tree_get_valid_key_returns_true) { 204 | for(int i = 0; i < 6; i++) 205 | iitree_add(tree, i, i); 206 | 207 | for(int i = 0; i < 6; i++) { 208 | int value; 209 | ck_assert(iitree_get(tree, i, &value)); 210 | ck_assert(value == i); 211 | } 212 | } 213 | END_TEST 214 | 215 | START_TEST(tree_get_min_returns_min) { 216 | for(int i = 0; i < 6; i++) 217 | iitree_add(tree, i, i); 218 | 219 | int value; 220 | iitree_get_min(tree, &value); 221 | 222 | ck_assert(value == 0); 223 | } 224 | END_TEST 225 | 226 | START_TEST(tree_get_max_returns_max) { 227 | for(int i = 0; i < 6; i++) 228 | iitree_add(tree, i, i); 229 | 230 | int value; 231 | iitree_get_max(tree, &value); 232 | 233 | ck_assert(value == 5); 234 | } 235 | END_TEST 236 | 237 | START_TEST(tree_iter_all) { 238 | for(int i = 0; i <= 6; i++) 239 | iitree_add(tree, i, 6-i); 240 | 241 | int key, value; 242 | int count = 0; 243 | rbtree_iter_start(IITree, tree, key, value) { 244 | ck_assert(count == key); 245 | ck_assert(value == 6-key); 246 | count++; 247 | } 248 | rbtree_iter_end 249 | ck_assert(count == 7); 250 | } 251 | END_TEST 252 | 253 | START_TEST(tree_iter_some) { 254 | for(int i = 0; i < 6; i++) 255 | iitree_add(tree, i, i); 256 | 257 | int key, value; 258 | int count = 0; 259 | rbtree_iter_start(IITree, tree, key, value) { 260 | ck_assert(count == key); 261 | count++; 262 | if(count == 3) 263 | break; 264 | } 265 | rbtree_iter_end 266 | ck_assert(count == 3); 267 | } 268 | END_TEST 269 | 270 | START_TEST(tree_iter_keys) { 271 | for(int i = 0; i <= 6; i++) 272 | iitree_add(tree, i, 6-i); 273 | 274 | int key; 275 | int count = 0; 276 | rbtree_iter_keys_start(IITree, tree, key) { 277 | ck_assert(count == key); 278 | count++; 279 | } 280 | rbtree_iter_end 281 | ck_assert(count == 7); 282 | } 283 | END_TEST 284 | 285 | START_TEST(tree_iter_values) { 286 | for(int i = 0; i <= 6; i++) 287 | iitree_add(tree, i, 6-i); 288 | 289 | int value; 290 | int count = 0; 291 | rbtree_iter_values_start(IITree, tree, value) { 292 | ck_assert(value == 6-count); 293 | count++; 294 | } 295 | rbtree_iter_end 296 | ck_assert(count == 7); 297 | } 298 | END_TEST 299 | 300 | int main(void) { 301 | int number_failed; 302 | 303 | Suite* s = suite_create("RB Tree"); 304 | TCase* tc = tcase_create("RB Tree"); 305 | 306 | tcase_add_checked_fixture(tc, tree_start, tree_reset); 307 | tcase_add_test(tc, tree_allocates_and_deallocates_no_elements); 308 | tcase_add_test(tc, tree_allocates_and_deallocates_some_elements); 309 | tcase_add_test(tc, tree_adds_items_in_order_simple); 310 | tcase_add_test(tc, tree_adds_items_in_order_complex); 311 | tcase_add_test(tc, tree_remove_root); 312 | tcase_add_test(tc, tree_remove_preserves_order); 313 | tcase_add_test(tc, tree_remove_min_removes_min); 314 | tcase_add_test(tc, tree_remove_max_removes_max); 315 | tcase_add_test(tc, tree_get_invalid_key_returns_false); 316 | tcase_add_test(tc, tree_get_valid_key_returns_true); 317 | tcase_add_test(tc, tree_get_min_returns_min); 318 | tcase_add_test(tc, tree_get_max_returns_max); 319 | tcase_add_test(tc, tree_iter_all); 320 | tcase_add_test(tc, tree_iter_some); 321 | tcase_add_test(tc, tree_iter_keys); 322 | tcase_add_test(tc, tree_iter_values); 323 | 324 | suite_add_tcase(s, tc); 325 | 326 | SRunner* sr = srunner_create(s); 327 | 328 | srunner_run_all(sr, CK_NORMAL); 329 | number_failed = srunner_ntests_failed(sr); 330 | srunner_free(sr); 331 | 332 | return number_failed == 0 ? EXIT_SUCCESS : EXIT_FAILURE; 333 | } -------------------------------------------------------------------------------- /tests/set_test.c: -------------------------------------------------------------------------------- 1 | #include "../include/generic_set.h" 2 | #include "../include/generic_iterators/set_iterator.h" 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | SET_DEFINE_H(StringSet, str_set, char*) 9 | SET_DEFINE_C(StringSet, str_set, char*, gds_fnv32, strcmp) 10 | 11 | static StringSet* set; 12 | 13 | static char* ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 14 | 15 | void set_start(void) { 16 | set = str_set_create(); 17 | } 18 | 19 | void set_reset(void) { 20 | str_set_free(set); 21 | } 22 | 23 | START_TEST(set_allocate_and_deallocate) { 24 | // Mostly just a fake test to make sure these don't crash the program. 25 | StringSet temp; 26 | ck_assert(str_set_init(&temp)); 27 | str_set_free_resources(&temp); 28 | 29 | // Run it twice just to be extra sure. 30 | ck_assert(str_set_init(&temp)); 31 | str_set_free_resources(&temp); 32 | } 33 | END_TEST 34 | 35 | START_TEST(set_add_new_value_adds) { 36 | ck_assert(str_set_add(set, "owl")); 37 | ck_assert(str_set_count(set) == 1); 38 | ck_assert(str_set_add(set, "pig")); 39 | ck_assert(str_set_count(set) == 2); 40 | } 41 | END_TEST 42 | 43 | START_TEST(set_add_duplicate_value_doesnt_add) { 44 | ck_assert(str_set_add(set, "owl")); 45 | ck_assert(!str_set_add(set, "owl")); 46 | } 47 | END_TEST 48 | 49 | START_TEST(set_contains_existing_key) { 50 | str_set_add(set, "owl"); 51 | str_set_add(set, "cow"); 52 | ck_assert(str_set_contains(set, "owl")); 53 | ck_assert(str_set_contains(set, "cow")); 54 | } 55 | END_TEST 56 | 57 | START_TEST(set_doesnt_contain_missing_key) { 58 | str_set_add(set, "owl"); 59 | ck_assert(!str_set_contains(set, "cow")); 60 | ck_assert(!str_set_contains(set, "raven")); 61 | } 62 | END_TEST 63 | 64 | START_TEST(set_remove_existing_key_removes) { 65 | str_set_add(set, "owl"); 66 | ck_assert(str_set_contains(set, "owl")); 67 | ck_assert(str_set_remove(set, "owl")); 68 | ck_assert(!str_set_contains(set, "owl")); 69 | } 70 | END_TEST 71 | 72 | START_TEST(set_remove_missing_key_returns_false) { 73 | ck_assert(!str_set_remove(set, "owl")); 74 | ck_assert(!str_set_remove(set, "raven")); 75 | } 76 | END_TEST 77 | 78 | START_TEST(set_clear_can_keep_capacity) { 79 | uint32_t load_factor = set->load_factor; 80 | 81 | for(int i = 0; i <= load_factor; i++) 82 | str_set_add(set, ALPHABET + i); 83 | 84 | uint32_t capacity = set->capacity; 85 | str_set_clear(set, false); 86 | ck_assert(set->capacity == capacity); 87 | ck_assert(set->count == 0); 88 | } 89 | END_TEST 90 | 91 | START_TEST(set_clear_can_reset_capacity) { 92 | uint32_t load_factor = set->load_factor; 93 | 94 | for(int i = 0; i <= load_factor; i++) 95 | str_set_add(set, ALPHABET + i); 96 | 97 | str_set_clear(set, true); 98 | ck_assert(set->capacity == 0); 99 | ck_assert(set->count == 0); 100 | } 101 | END_TEST 102 | 103 | START_TEST(set_union_contains_left_and_right) { 104 | StringSet* left = str_set_create(); 105 | StringSet* right = str_set_create(); 106 | StringSet* result = str_set_create(); 107 | 108 | str_set_add(left, "cow"); 109 | str_set_add(right, "pig"); 110 | 111 | ck_assert(str_set_union(left, right, result)); 112 | ck_assert(str_set_count(result) == 2); 113 | ck_assert(str_set_contains(result, "cow")); 114 | ck_assert(str_set_contains(result, "pig")); 115 | ck_assert(!str_set_contains(result, "raven")); 116 | 117 | str_set_free(left); 118 | str_set_free(right); 119 | str_set_free(result); 120 | } 121 | END_TEST 122 | 123 | START_TEST(set_intersect_contains_left_and_right_shared) { 124 | StringSet* left = str_set_create(); 125 | StringSet* right = str_set_create(); 126 | StringSet* result = str_set_create(); 127 | 128 | str_set_add(left, "cow"); 129 | str_set_add(left, "raven"); 130 | str_set_add(right, "pig"); 131 | str_set_add(right, "raven"); 132 | 133 | ck_assert(str_set_intersect(left, right, result)); 134 | ck_assert(str_set_count(result) == 1); 135 | ck_assert(!str_set_contains(result, "cow")); 136 | ck_assert(str_set_contains(result, "raven")); 137 | ck_assert(!str_set_contains(result, "pig")); 138 | 139 | str_set_free(left); 140 | str_set_free(right); 141 | str_set_free(result); 142 | } 143 | END_TEST 144 | 145 | START_TEST(set_complement_contains_left_only) { 146 | StringSet* left = str_set_create(); 147 | StringSet* right = str_set_create(); 148 | StringSet* result = str_set_create(); 149 | 150 | str_set_add(left, "cow"); 151 | str_set_add(left, "raven"); 152 | str_set_add(right, "pig"); 153 | str_set_add(right, "cow"); 154 | 155 | ck_assert(str_set_complement(left, right, result)); 156 | ck_assert(str_set_count(result) == 1); 157 | ck_assert(!str_set_contains(result, "cow")); 158 | ck_assert(str_set_contains(result, "raven")); 159 | ck_assert(!str_set_contains(result, "pig")); 160 | 161 | str_set_free(left); 162 | str_set_free(right); 163 | str_set_free(result); 164 | } 165 | END_TEST 166 | 167 | START_TEST(set_is_superset_left_is_superset) { 168 | StringSet* left = str_set_create(); 169 | StringSet* right = str_set_create(); 170 | 171 | str_set_add(left, "cow"); 172 | str_set_add(left, "raven"); 173 | str_set_add(left, "pig"); 174 | str_set_add(right, "pig"); 175 | str_set_add(right, "cow"); 176 | 177 | ck_assert(str_set_is_superset(left, right)); 178 | ck_assert(!str_set_is_superset(right, left)); 179 | 180 | str_set_free(left); 181 | str_set_free(right); 182 | } 183 | END_TEST 184 | 185 | START_TEST(set_resizes_when_load_factor_is_reached) { 186 | ck_assert(set->load_factor < strlen(ALPHABET)); 187 | 188 | uint32_t load_factor = set->load_factor; 189 | int i = 0; 190 | while(load_factor == set->load_factor) 191 | str_set_add(set, ALPHABET + i++); 192 | 193 | ck_assert(set->load_factor == load_factor * 2); 194 | } 195 | END_TEST 196 | 197 | #define ARRAY_SIZE(array) (sizeof((array)) / sizeof(*(array))) 198 | 199 | START_TEST(set_iter_all) { 200 | char* animals[] = { "owl", "cow", "raven" }; 201 | for(int i = 0; i < ARRAY_SIZE(animals); i++) 202 | str_set_add(set, animals[i]); 203 | 204 | int count = 0; 205 | char* value; 206 | bool found; 207 | set_iter_start(set, value) { 208 | found = false; 209 | for(int i = 0; i < ARRAY_SIZE(animals); i++) { 210 | if(strcmp(value, animals[i]) == 0) { 211 | found = true; 212 | break; 213 | } 214 | } 215 | ck_assert(found); 216 | count++; 217 | } 218 | set_iter_end 219 | 220 | ck_assert(count == 3); 221 | } 222 | END_TEST 223 | 224 | START_TEST(set_iter_some) { 225 | str_set_add(set, "owl"); 226 | str_set_add(set, "cow"); 227 | str_set_add(set, "raven"); 228 | 229 | char* dummy; 230 | int count = 0; 231 | set_iter_start(set, dummy) { 232 | if(++count == 2) 233 | break; 234 | } 235 | set_iter_end 236 | 237 | ck_assert(count == 2); 238 | } 239 | END_TEST 240 | 241 | START_TEST(set_iter_skip) { 242 | str_set_add(set, "owl"); 243 | str_set_add(set, "cow"); 244 | str_set_add(set, "raven"); 245 | 246 | char* dummy; 247 | int count = 0; 248 | int count2 = 0; 249 | set_iter_start(set, dummy) { 250 | if(++count == 2) 251 | continue; 252 | count2++; 253 | } 254 | set_iter_end 255 | 256 | ck_assert(count == 3); 257 | ck_assert(count2 == 2); 258 | } 259 | END_TEST 260 | 261 | int main(void) { 262 | Suite* s = suite_create("Set Tests"); 263 | TCase* tc = tcase_create("Set Tests"); 264 | 265 | tcase_add_checked_fixture(tc, set_start, set_reset); 266 | tcase_add_test(tc, set_allocate_and_deallocate); 267 | tcase_add_test(tc, set_add_new_value_adds); 268 | tcase_add_test(tc, set_add_duplicate_value_doesnt_add); 269 | tcase_add_test(tc, set_contains_existing_key); 270 | tcase_add_test(tc, set_doesnt_contain_missing_key); 271 | tcase_add_test(tc, set_remove_existing_key_removes); 272 | tcase_add_test(tc, set_remove_missing_key_returns_false); 273 | tcase_add_test(tc, set_union_contains_left_and_right); 274 | tcase_add_test(tc, set_intersect_contains_left_and_right_shared); 275 | tcase_add_test(tc, set_complement_contains_left_only); 276 | tcase_add_test(tc, set_is_superset_left_is_superset); 277 | tcase_add_test(tc, set_resizes_when_load_factor_is_reached); 278 | tcase_add_test(tc, set_iter_all); 279 | tcase_add_test(tc, set_iter_some); 280 | tcase_add_test(tc, set_iter_skip); 281 | tcase_add_test(tc, set_allocate_and_deallocate); 282 | tcase_add_test(tc, set_allocate_and_deallocate); 283 | tcase_add_test(tc, set_allocate_and_deallocate); 284 | 285 | suite_add_tcase(s, tc); 286 | 287 | SRunner* sr = srunner_create(s); 288 | srunner_run_all(sr, CK_NORMAL); 289 | int number_failed = srunner_ntests_failed(sr); 290 | srunner_free(sr); 291 | 292 | return number_failed == 0 ? EXIT_SUCCESS : EXIT_FAILURE; 293 | } -------------------------------------------------------------------------------- /tests/trie_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../include/generic_trie.h" 5 | #include "../include/generic_iterators/trie_iterator.h" 6 | 7 | TRIE_SET_DEFINE_H(StringTrie, str_trie, char) 8 | 9 | TRIE_SET_DEFINE_C(StringTrie, str_trie, char) 10 | 11 | TRIE_MAP_DEFINE_H(SITrie, si_trie, char, int) 12 | 13 | TRIE_MAP_DEFINE_C(SITrie, si_trie, char, int) 14 | 15 | static char* simple_words[] = { 16 | "hello", 17 | "world", 18 | "owl", 19 | "fox", 20 | "raven", 21 | "cat", 22 | "cow", 23 | "moo", 24 | "meow", 25 | "vs", 26 | "nyan" 27 | }; 28 | 29 | // This can't share any words with simple_words either. 30 | 31 | static char* complex_words[] = { 32 | "This", 33 | "is", 34 | "a", 35 | "rather", 36 | "complex", 37 | "sentence", 38 | "that", 39 | "contains", 40 | "no", 41 | "duplicate", 42 | "words", 43 | "in", 44 | "order", 45 | "to", 46 | "make", 47 | "sure", 48 | "the", 49 | "trie_set", 50 | "has", 51 | "an", 52 | "opportunity", 53 | "resize", 54 | "when", 55 | "number", 56 | "twenty", 57 | "reached", 58 | "," 59 | "but", 60 | "too", 61 | "little", 62 | "letters", 63 | "left", 64 | "after", 65 | "all", 66 | "uh", 67 | "oh", 68 | "spaghettio", 69 | "Generic", 70 | "Data", 71 | "Structures", 72 | "set", 73 | "of", 74 | "C", 75 | "header", 76 | "files", 77 | "contain", 78 | "macros", 79 | "which", 80 | "generate", 81 | "strongly", 82 | "typed", 83 | "data", 84 | "structures", 85 | "fashion", 86 | "similar", 87 | "c++", 88 | "templates", 89 | "Each", 90 | "two", 91 | "type", 92 | "corresponds", 93 | "name", 94 | "first", 95 | "macro", 96 | "can", 97 | "go", 98 | "file", 99 | "functions", 100 | "are", 101 | "used", 102 | "across", 103 | "multiple", 104 | "compilation", 105 | "units" 106 | }; 107 | 108 | #define ARRAY_SIZE(array) (sizeof(array) / sizeof(*array)) 109 | 110 | static StringTrie* trie_set; 111 | static SITrie* trie_map; 112 | 113 | void trie_set_start(void) { 114 | trie_set = str_trie_create(); 115 | } 116 | 117 | void trie_set_reset(void) { 118 | str_trie_free(trie_set); 119 | } 120 | 121 | void trie_map_start(void) { 122 | trie_map = si_trie_create(); 123 | } 124 | 125 | void trie_map_reset(void) { 126 | si_trie_free(trie_map); 127 | } 128 | 129 | START_TEST(trie_set_allocate_and_deallocate) { 130 | StringTrie temp, *ptr; 131 | ck_assert(str_trie_init(&temp)); 132 | str_trie_free_resources(&temp); 133 | ptr = str_trie_create(); 134 | ck_assert(ptr); 135 | str_trie_free(ptr); 136 | } 137 | END_TEST 138 | 139 | START_TEST(trie_set_simple_add_new_value_succeeds) { 140 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) { 141 | ck_assert(str_trie_count(trie_set) == i); 142 | ck_assert(str_trie_add(trie_set, simple_words[i])); 143 | ck_assert(str_trie_count(trie_set) == i + 1); 144 | } 145 | } 146 | END_TEST 147 | 148 | START_TEST(trie_set_simple_add_repeat_value_fails) { 149 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) { 150 | ck_assert(str_trie_count(trie_set) == i); 151 | ck_assert(str_trie_add(trie_set, simple_words[i])); 152 | ck_assert(str_trie_count(trie_set) == i + 1); 153 | } 154 | 155 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) { 156 | ck_assert(!str_trie_add(trie_set, simple_words[i])); 157 | } 158 | } 159 | END_TEST 160 | 161 | START_TEST(trie_set_complex_add_new_value_succeeds) { 162 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) { 163 | ck_assert(str_trie_count(trie_set) == i); 164 | ck_assert(str_trie_add(trie_set, complex_words[i])); 165 | ck_assert(str_trie_count(trie_set) == i + 1); 166 | } 167 | } 168 | END_TEST 169 | 170 | START_TEST(trie_set_complex_add_repeat_value_fails) { 171 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) { 172 | ck_assert(str_trie_count(trie_set) == i); 173 | ck_assert(str_trie_add(trie_set, complex_words[i])); 174 | ck_assert(str_trie_count(trie_set) == i + 1); 175 | } 176 | 177 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) { 178 | ck_assert(!str_trie_add(trie_set, complex_words[i])); 179 | } 180 | } 181 | END_TEST 182 | 183 | START_TEST(trie_set_simple_contains_added_value_succeeds) { 184 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) 185 | ck_assert(str_trie_add(trie_set, simple_words[i])); 186 | 187 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) 188 | ck_assert(str_trie_contains(trie_set, simple_words[i])); 189 | } 190 | END_TEST 191 | 192 | START_TEST(trie_set_simple_contains_missing_value_fails) { 193 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) 194 | ck_assert(str_trie_add(trie_set, simple_words[i])); 195 | 196 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) 197 | ck_assert(!str_trie_contains(trie_set, complex_words[i])); 198 | } 199 | END_TEST 200 | 201 | START_TEST(trie_set_complex_contains_added_value_succeeds) { 202 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) 203 | ck_assert(str_trie_add(trie_set, complex_words[i])); 204 | 205 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) 206 | ck_assert(str_trie_contains(trie_set, complex_words[i])); 207 | } 208 | END_TEST 209 | 210 | START_TEST(trie_set_complex_contains_missing_value_fails) { 211 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) 212 | ck_assert(str_trie_add(trie_set, complex_words[i])); 213 | 214 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) 215 | ck_assert(!str_trie_contains(trie_set, simple_words[i])); 216 | } 217 | END_TEST 218 | 219 | START_TEST(trie_set_simple_remove_added_value_succeeds) { 220 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) 221 | ck_assert(str_trie_add(trie_set, simple_words[i])); 222 | 223 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) { 224 | unsigned int count = str_trie_count(trie_set); 225 | ck_assert(str_trie_remove(trie_set, simple_words[i])); 226 | ck_assert(str_trie_count(trie_set) == count - 1); 227 | } 228 | } 229 | END_TEST 230 | 231 | START_TEST(trie_set_simple_remove_missing_value_fails) { 232 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) 233 | ck_assert(str_trie_add(trie_set, simple_words[i])); 234 | 235 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) 236 | ck_assert(!str_trie_remove(trie_set, complex_words[i])); 237 | } 238 | END_TEST 239 | 240 | START_TEST(trie_set_complex_remove_added_value_succeeds) { 241 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) 242 | ck_assert(str_trie_add(trie_set, complex_words[i])); 243 | 244 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) { 245 | unsigned int count = str_trie_count(trie_set); 246 | ck_assert(str_trie_remove(trie_set, complex_words[i])); 247 | ck_assert(str_trie_count(trie_set) == count - 1); 248 | } 249 | } 250 | END_TEST 251 | 252 | START_TEST(trie_set_complex_remove_missing_value_fails) { 253 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) 254 | ck_assert(str_trie_add(trie_set, complex_words[i])); 255 | 256 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) 257 | ck_assert(!str_trie_remove(trie_set, simple_words[i])); 258 | } 259 | END_TEST 260 | 261 | START_TEST(trie_set_simple_add_and_remove) { 262 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) 263 | ck_assert(str_trie_add(trie_set, simple_words[i])); 264 | 265 | for(int i = 0; i < ARRAY_SIZE(simple_words); i += 2) 266 | ck_assert(str_trie_remove(trie_set, simple_words[i])); 267 | 268 | for(int i = 1; i < ARRAY_SIZE(simple_words); i += 2) 269 | ck_assert(str_trie_contains(trie_set, simple_words[i])); 270 | 271 | for(int i = 0; i < ARRAY_SIZE(simple_words); i += 2) 272 | ck_assert(!str_trie_contains(trie_set, simple_words[i])); 273 | } 274 | END_TEST 275 | 276 | START_TEST(trie_set_complex_add_and_remove) { 277 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) 278 | ck_assert(str_trie_add(trie_set, complex_words[i])); 279 | 280 | for(int i = 0; i < ARRAY_SIZE(complex_words); i += 2) 281 | ck_assert(str_trie_remove(trie_set, complex_words[i])); 282 | 283 | for(int i = 1; i < ARRAY_SIZE(complex_words); i += 2) 284 | ck_assert(str_trie_contains(trie_set, complex_words[i])); 285 | 286 | for(int i = 0; i < ARRAY_SIZE(complex_words); i += 2) 287 | ck_assert(!str_trie_contains(trie_set, complex_words[i])); 288 | } 289 | END_TEST 290 | 291 | START_TEST(trie_set_simple_children_count) { 292 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) 293 | ck_assert(str_trie_add(trie_set, simple_words[i])); 294 | 295 | int starts_with = 0; 296 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) { 297 | if(simple_words[i][0] == 'c') 298 | starts_with++; 299 | } 300 | 301 | unsigned int count = str_trie_children_count(trie_set, "c", 20); 302 | ck_assert(count == starts_with); 303 | } 304 | END_TEST 305 | 306 | START_TEST(trie_set_complex_children_count) { 307 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) 308 | ck_assert(str_trie_add(trie_set, complex_words[i])); 309 | 310 | int starts_with = 0; 311 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) { 312 | if(complex_words[i][0] == 'c') 313 | starts_with++; 314 | } 315 | 316 | unsigned int count = str_trie_children_count(trie_set, "c", 20); 317 | ck_assert(count == starts_with); 318 | } 319 | END_TEST 320 | 321 | START_TEST(trie_set_large_children_count) { 322 | char words[271][4]; 323 | words[0][0] = 'a'; 324 | words[0][1] = 0; 325 | int index = 1; 326 | for(int i = 0; i < 10; i++) { 327 | words[index][0] = 'a'; 328 | words[index][1] = 'a' + i; 329 | words[index][2] = 0; 330 | index++; 331 | for(int j = 0; j < 26; j++, index++) { 332 | words[index][0] = 'a'; 333 | words[index][1] = 'a' + i; 334 | words[index][2] = 'a' + j; 335 | words[index][3] = 0; 336 | } 337 | } 338 | 339 | for(int i = 0; i < 271; i++) 340 | str_trie_add(trie_set, words[i]); 341 | 342 | unsigned int count = str_trie_children_count(trie_set, "a", 5); 343 | ck_assert(count == 270); 344 | count = str_trie_children_count(trie_set, "aa", 4); 345 | ck_assert(count == 26); 346 | } 347 | END_TEST 348 | 349 | START_TEST(trie_set_simple_children_all_alloc) { 350 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) 351 | ck_assert(str_trie_add(trie_set, simple_words[i])); 352 | 353 | trie_map = si_trie_create(); 354 | 355 | int starts_with = 0; 356 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) { 357 | if(simple_words[i][0] == 'c') { 358 | si_trie_add(trie_map, simple_words[i], starts_with); 359 | starts_with++; 360 | } 361 | } 362 | 363 | 364 | char** values = calloc(starts_with, sizeof(*values)); 365 | int* word_count = calloc(starts_with, sizeof(*word_count)); 366 | 367 | unsigned int count = str_trie_children(trie_set, "c", values, starts_with, 10, true); 368 | ck_assert(count == starts_with); 369 | 370 | for(int i = 0; i < count; i++) { 371 | int index; 372 | ck_assert(si_trie_try_get(trie_map, values[i], &index)); 373 | word_count[index]++; 374 | } 375 | 376 | for(int i = 0; i < count; i++) { 377 | free(values[i]); 378 | ck_assert(word_count[i] == 1); 379 | } 380 | 381 | free(values); 382 | free(word_count); 383 | si_trie_free(trie_map); 384 | } 385 | END_TEST 386 | 387 | START_TEST(trie_set_simple_children_all_no_alloc) { 388 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) 389 | ck_assert(str_trie_add(trie_set, simple_words[i])); 390 | 391 | trie_map = si_trie_create(); 392 | 393 | int starts_with = 0; 394 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) { 395 | if(simple_words[i][0] == 'c') { 396 | si_trie_add(trie_map, simple_words[i], starts_with); 397 | starts_with++; 398 | } 399 | } 400 | 401 | const int max_length = 10; 402 | 403 | char** values = calloc(starts_with, sizeof(*values)); 404 | for(int i = 0; i < starts_with; i++) 405 | values[i] = calloc(max_length, sizeof(**values)); 406 | 407 | int* word_count = calloc(starts_with, sizeof(*word_count)); 408 | 409 | unsigned int count = str_trie_children(trie_set, "c", values, starts_with, max_length, true); 410 | ck_assert(count == starts_with); 411 | 412 | for(int i = 0; i < count; i++) { 413 | int index; 414 | ck_assert(si_trie_try_get(trie_map, values[i], &index)); 415 | word_count[index]++; 416 | } 417 | 418 | for(int i = 0; i < count; i++) { 419 | free(values[i]); 420 | ck_assert(word_count[i] == 1); 421 | } 422 | 423 | free(values); 424 | free(word_count); 425 | si_trie_free(trie_map); 426 | } 427 | END_TEST 428 | 429 | START_TEST(trie_set_simple_children_partial) { 430 | str_trie_add(trie_set, "read"); 431 | str_trie_add(trie_set, "reads"); 432 | char buffer[10] = {0}; 433 | char* values[2] = { buffer }; 434 | 435 | const int max_length = 4; 436 | 437 | ck_assert(str_trie_children_count(trie_set, "r", max_length) == 1); 438 | unsigned int count = str_trie_children(trie_set, "r", values, 1, max_length, false); 439 | ck_assert(count == 1); 440 | ck_assert(strcmp(buffer, "read") == 0); 441 | } 442 | END_TEST 443 | 444 | START_TEST(trie_set_complex_children_all_alloc) { 445 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) 446 | ck_assert(str_trie_add(trie_set, complex_words[i])); 447 | 448 | trie_map = si_trie_create(); 449 | 450 | int starts_with = 0; 451 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) { 452 | if(complex_words[i][0] == 'c') { 453 | si_trie_add(trie_map, complex_words[i], starts_with); 454 | starts_with++; 455 | } 456 | } 457 | 458 | const int max_length = 20; 459 | 460 | char** values = calloc(starts_with, sizeof(*values)); 461 | for(int i = 0; i < starts_with; i++) 462 | values[i] = calloc(max_length, sizeof(**values)); 463 | int* word_count = calloc(starts_with, sizeof(*word_count)); 464 | 465 | unsigned int count = str_trie_children(trie_set, "c", values, starts_with, max_length, true); 466 | ck_assert(count == starts_with); 467 | 468 | for(int i = 0; i < count; i++) { 469 | int index; 470 | ck_assert(si_trie_try_get(trie_map, values[i], &index)); 471 | word_count[index]++; 472 | } 473 | 474 | for(int i = 0; i < count; i++) { 475 | free(values[i]); 476 | ck_assert(word_count[i] == 1); 477 | } 478 | 479 | free(values); 480 | free(word_count); 481 | si_trie_free(trie_map); 482 | } 483 | END_TEST 484 | 485 | START_TEST(trie_set_complex_children_all_no_alloc) { 486 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) 487 | ck_assert(str_trie_add(trie_set, complex_words[i])); 488 | 489 | trie_map = si_trie_create(); 490 | 491 | int starts_with = 0; 492 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) { 493 | if(complex_words[i][0] == 'c') { 494 | si_trie_add(trie_map, complex_words[i], starts_with); 495 | starts_with++; 496 | } 497 | } 498 | 499 | 500 | char** values = calloc(starts_with, sizeof(*values)); 501 | int* word_count = calloc(starts_with, sizeof(*word_count)); 502 | 503 | unsigned int count = str_trie_children(trie_set, "c", values, starts_with, 20, true); 504 | ck_assert(count == starts_with); 505 | 506 | for(int i = 0; i < count; i++) { 507 | int index; 508 | ck_assert(si_trie_try_get(trie_map, values[i], &index)); 509 | word_count[index]++; 510 | } 511 | 512 | for(int i = 0; i < count; i++) { 513 | free(values[i]); 514 | ck_assert(word_count[i] == 1); 515 | } 516 | 517 | free(values); 518 | free(word_count); 519 | si_trie_free(trie_map); 520 | } 521 | END_TEST 522 | 523 | START_TEST(trie_set_children_null_out_values_returns_children_count) { 524 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) 525 | ck_assert(str_trie_add(trie_set, simple_words[i])); 526 | 527 | int starts_with = 0; 528 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) { 529 | if(simple_words[i][0] == 'c') { 530 | starts_with++; 531 | } 532 | } 533 | 534 | unsigned int count = str_trie_children(trie_set, "c", NULL, 0, 20, false); 535 | ck_assert(count == starts_with); 536 | } 537 | END_TEST 538 | 539 | START_TEST(trie_set_simple_iter) { 540 | int word_count[ARRAY_SIZE(simple_words)] = { 0 }; 541 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) 542 | ck_assert(str_trie_add(trie_set, simple_words[i])); 543 | 544 | char* value; 545 | trie_set_iter_start(StringTrie, trie_set, value) { 546 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) { 547 | if(strcmp(value, simple_words[i]) == 0) { 548 | ck_assert(word_count[i] == 0); 549 | word_count[i] += 1; 550 | } 551 | } 552 | } 553 | trie_set_iter_end 554 | 555 | for(int i = 0; i < ARRAY_SIZE(word_count); i++) { 556 | ck_assert(word_count[i] == 1); 557 | } 558 | } 559 | END_TEST 560 | 561 | START_TEST(trie_set_complex_iter) { 562 | int word_count[ARRAY_SIZE(complex_words)] = { 0 }; 563 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) 564 | ck_assert(str_trie_add(trie_set, complex_words[i])); 565 | 566 | char* value; 567 | trie_set_iter_start(StringTrie, trie_set, value) { 568 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) { 569 | if(strcmp(value, complex_words[i]) == 0) { 570 | ck_assert(word_count[i] == 0); 571 | word_count[i] += 1; 572 | } 573 | } 574 | } 575 | trie_set_iter_end 576 | 577 | for(int i = 0; i < ARRAY_SIZE(word_count); i++) { 578 | ck_assert(word_count[i] == 1); 579 | } 580 | } 581 | END_TEST 582 | 583 | START_TEST(trie_map_allocate_and_deallocate) { 584 | SITrie temp, *ptr; 585 | ck_assert(si_trie_init(&temp)); 586 | si_trie_free_resources(&temp); 587 | ptr = si_trie_create(); 588 | ck_assert(ptr); 589 | si_trie_free(ptr); 590 | } 591 | END_TEST 592 | 593 | START_TEST(trie_map_simple_add_new_value_succeeds) { 594 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) { 595 | ck_assert(si_trie_count(trie_map) == i); 596 | ck_assert(si_trie_add(trie_map, simple_words[i], i)); 597 | ck_assert(si_trie_count(trie_map) == i + 1); 598 | ck_assert(si_trie_get(trie_map, simple_words[i]) == i); 599 | } 600 | } 601 | END_TEST 602 | 603 | START_TEST(trie_map_simple_add_repeat_value_fails) { 604 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) { 605 | ck_assert(si_trie_count(trie_map) == i); 606 | ck_assert(si_trie_add(trie_map, simple_words[i], i)); 607 | ck_assert(si_trie_count(trie_map) == i + 1); 608 | } 609 | 610 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) { 611 | ck_assert(!si_trie_add(trie_map, simple_words[i], i)); 612 | } 613 | } 614 | END_TEST 615 | 616 | START_TEST(trie_map_complex_add_new_value_succeeds) { 617 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) { 618 | ck_assert(si_trie_count(trie_map) == i); 619 | ck_assert(si_trie_add(trie_map, complex_words[i], i)); 620 | ck_assert(si_trie_count(trie_map) == i + 1); 621 | ck_assert(si_trie_get(trie_map, complex_words[i]) == i); 622 | } 623 | } 624 | END_TEST 625 | 626 | START_TEST(trie_map_complex_add_repeat_value_fails) { 627 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) { 628 | ck_assert(si_trie_count(trie_map) == i); 629 | ck_assert(si_trie_add(trie_map, complex_words[i], i)); 630 | ck_assert(si_trie_count(trie_map) == i + 1); 631 | } 632 | 633 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) { 634 | ck_assert(!si_trie_add(trie_map, complex_words[i], i)); 635 | } 636 | } 637 | END_TEST 638 | 639 | START_TEST(trie_map_simple_set_new_value_succeeds) { 640 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) { 641 | ck_assert(si_trie_count(trie_map) == i); 642 | ck_assert(si_trie_set(trie_map, simple_words[i], i)); 643 | ck_assert(si_trie_count(trie_map) == i + 1); 644 | ck_assert(si_trie_get(trie_map, simple_words[i]) == i); 645 | } 646 | } 647 | END_TEST 648 | 649 | START_TEST(trie_map_simple_set_repeat_value_succeeds) { 650 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) { 651 | ck_assert(si_trie_count(trie_map) == i); 652 | ck_assert(si_trie_set(trie_map, simple_words[i], i)); 653 | ck_assert(si_trie_count(trie_map) == i + 1); 654 | ck_assert(si_trie_get(trie_map, simple_words[i]) == i); 655 | } 656 | 657 | unsigned int count = si_trie_count(trie_map); 658 | 659 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) { 660 | ck_assert(si_trie_set(trie_map, simple_words[i], i + 1)); 661 | ck_assert(si_trie_get(trie_map, simple_words[i]) == i + 1); 662 | ck_assert(si_trie_count(trie_map) == count); 663 | } 664 | } 665 | END_TEST 666 | 667 | START_TEST(trie_map_complex_set_new_value_succeeds) { 668 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) { 669 | ck_assert(si_trie_count(trie_map) == i); 670 | ck_assert(si_trie_set(trie_map, complex_words[i], i)); 671 | ck_assert(si_trie_count(trie_map) == i + 1); 672 | ck_assert(si_trie_get(trie_map, complex_words[i]) == i); 673 | } 674 | } 675 | END_TEST 676 | 677 | START_TEST(trie_map_complex_set_repeat_value_succeeds) { 678 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) { 679 | ck_assert(si_trie_count(trie_map) == i); 680 | ck_assert(si_trie_set(trie_map, complex_words[i], i)); 681 | ck_assert(si_trie_count(trie_map) == i + 1); 682 | ck_assert(si_trie_get(trie_map, complex_words[i]) == i); 683 | } 684 | 685 | unsigned int count = si_trie_count(trie_map); 686 | 687 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) { 688 | ck_assert(si_trie_set(trie_map, complex_words[i], i + 1)); 689 | ck_assert(si_trie_get(trie_map, complex_words[i]) == i + 1); 690 | ck_assert(si_trie_count(trie_map) == count); 691 | } 692 | } 693 | END_TEST 694 | 695 | START_TEST(trie_map_get_missing_value_returns_default) { 696 | ck_assert(si_trie_get(trie_map, "moo") == 0); 697 | } 698 | END_TEST 699 | 700 | START_TEST(trie_map_simple_try_get_added_value_succeeds) { 701 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) 702 | ck_assert(si_trie_set(trie_map, simple_words[i], i)); 703 | 704 | int value; 705 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) { 706 | ck_assert(si_trie_try_get(trie_map, simple_words[i], &value)); 707 | ck_assert(value == i); 708 | } 709 | } 710 | END_TEST 711 | 712 | START_TEST(trie_map_simple_try_get_missing_value_fails) { 713 | int value = 4; 714 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) { 715 | ck_assert(!si_trie_try_get(trie_map, simple_words[i], &value)); 716 | ck_assert(value == 4); 717 | } 718 | } 719 | END_TEST 720 | 721 | START_TEST(trie_map_complex_try_get_added_value_succeeds) { 722 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) 723 | ck_assert(si_trie_set(trie_map, complex_words[i], i)); 724 | 725 | int value; 726 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) { 727 | ck_assert(si_trie_try_get(trie_map, complex_words[i], &value)); 728 | ck_assert(value == i); 729 | } 730 | } 731 | END_TEST 732 | 733 | START_TEST(trie_map_complex_try_get_missing_value_fails) { 734 | int value = 6; 735 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) { 736 | ck_assert(!si_trie_try_get(trie_map, complex_words[i], &value)); 737 | ck_assert(value == 6); 738 | } 739 | } 740 | END_TEST 741 | 742 | START_TEST(trie_map_simple_remove_added_succeeds) { 743 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) 744 | ck_assert(si_trie_set(trie_map, simple_words[i], i)); 745 | 746 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) 747 | ck_assert(si_trie_remove(trie_map, simple_words[i])); 748 | 749 | ck_assert(si_trie_count(trie_map) == 0); 750 | } 751 | END_TEST 752 | 753 | START_TEST(trie_map_simple_remove_missing_fails) { 754 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) 755 | ck_assert(!si_trie_remove(trie_map, simple_words[i])); 756 | } 757 | END_TEST 758 | 759 | START_TEST(trie_map_simple_remove_some_succeeds) { 760 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) 761 | ck_assert(si_trie_set(trie_map, simple_words[i], i)); 762 | 763 | for(int i = 0; i < ARRAY_SIZE(simple_words); i += 2) 764 | ck_assert(si_trie_remove(trie_map, simple_words[i])); 765 | 766 | for(int i = 0; i < ARRAY_SIZE(simple_words); i += 2) { 767 | if(i % 2) 768 | ck_assert(si_trie_try_get(trie_map, simple_words[i], NULL)); 769 | else 770 | ck_assert(!si_trie_try_get(trie_map, simple_words[i], NULL)); 771 | } 772 | } 773 | END_TEST 774 | 775 | START_TEST(trie_map_complex_remove_added_succeeds) { 776 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) 777 | ck_assert(si_trie_set(trie_map, complex_words[i], i)); 778 | 779 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) 780 | ck_assert(si_trie_remove(trie_map, complex_words[i])); 781 | 782 | ck_assert(si_trie_count(trie_map) == 0); 783 | } 784 | END_TEST 785 | 786 | START_TEST(trie_map_complex_remove_missing_fails) { 787 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) 788 | ck_assert(!si_trie_remove(trie_map, complex_words[i])); 789 | } 790 | END_TEST 791 | 792 | START_TEST(trie_map_complex_remove_some_succeeds) { 793 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) 794 | ck_assert(si_trie_set(trie_map, complex_words[i], i)); 795 | 796 | for(int i = 0; i < ARRAY_SIZE(complex_words); i += 2) 797 | ck_assert(si_trie_remove(trie_map, complex_words[i])); 798 | 799 | for(int i = 0; i < ARRAY_SIZE(complex_words); i += 2) { 800 | if(i % 2) 801 | ck_assert(si_trie_try_get(trie_map, complex_words[i], NULL)); 802 | else 803 | ck_assert(!si_trie_try_get(trie_map, complex_words[i], NULL)); 804 | } 805 | } 806 | END_TEST 807 | 808 | START_TEST(trie_map_simple_get_and_remove_added_value_succeeds) { 809 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) 810 | ck_assert(si_trie_set(trie_map, simple_words[i], i)); 811 | 812 | int value; 813 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) { 814 | ck_assert(si_trie_get_and_remove(trie_map, simple_words[i], &value)); 815 | ck_assert(value == i); 816 | } 817 | 818 | ck_assert(si_trie_count(trie_map) == 0); 819 | } 820 | END_TEST 821 | 822 | START_TEST(trie_map_simple_get_and_remove_missing_value_fails) { 823 | int value = 5; 824 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) { 825 | ck_assert(!si_trie_get_and_remove(trie_map, simple_words[i], &value)); 826 | ck_assert(value == 5); 827 | } 828 | } 829 | END_TEST 830 | 831 | START_TEST(trie_map_simple_get_and_remove_some_succeeds) { 832 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) 833 | ck_assert(si_trie_set(trie_map, simple_words[i], i)); 834 | 835 | int value; 836 | for(int i = 0; i < ARRAY_SIZE(simple_words); i += 2) { 837 | ck_assert(si_trie_get_and_remove(trie_map, simple_words[i], &value)); 838 | ck_assert(value == i); 839 | } 840 | 841 | for(int i = 0; i < ARRAY_SIZE(simple_words); i += 2) { 842 | if(i % 2) 843 | ck_assert(si_trie_try_get(trie_map, simple_words[i], NULL)); 844 | else 845 | ck_assert(!si_trie_try_get(trie_map, simple_words[i], NULL)); 846 | } 847 | } 848 | END_TEST 849 | 850 | START_TEST(trie_map_complex_get_and_remove_added_value_succeeds) { 851 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) 852 | ck_assert(si_trie_set(trie_map, complex_words[i], i)); 853 | 854 | int value; 855 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) { 856 | ck_assert(si_trie_get_and_remove(trie_map, complex_words[i], &value)); 857 | ck_assert(value == i); 858 | } 859 | 860 | ck_assert(si_trie_count(trie_map) == 0); 861 | } 862 | END_TEST 863 | 864 | START_TEST(trie_map_complex_get_and_remove_missing_value_fails) { 865 | int value = 5; 866 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) { 867 | ck_assert(!si_trie_get_and_remove(trie_map, complex_words[i], &value)); 868 | ck_assert(value == 5); 869 | } 870 | } 871 | END_TEST 872 | 873 | START_TEST(trie_map_complex_get_and_remove_some_succeeds) { 874 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) 875 | ck_assert(si_trie_set(trie_map, complex_words[i], i)); 876 | 877 | int value; 878 | for(int i = 0; i < ARRAY_SIZE(complex_words); i += 2) { 879 | ck_assert(si_trie_get_and_remove(trie_map, complex_words[i], &value)); 880 | ck_assert(value == i); 881 | } 882 | 883 | for(int i = 0; i < ARRAY_SIZE(complex_words); i += 2) { 884 | if(i % 2) 885 | ck_assert(si_trie_try_get(trie_map, complex_words[i], NULL)); 886 | else 887 | ck_assert(!si_trie_try_get(trie_map, complex_words[i], NULL)); 888 | } 889 | } 890 | END_TEST 891 | 892 | START_TEST(trie_map_simple_clear_succeeds) { 893 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) 894 | ck_assert(si_trie_set(trie_map, simple_words[i], i)); 895 | 896 | ck_assert(si_trie_clear(trie_map)); 897 | ck_assert(si_trie_count(trie_map) == 0); 898 | } 899 | END_TEST 900 | 901 | START_TEST(trie_map_complex_clear_succeeds) { 902 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) 903 | ck_assert(si_trie_set(trie_map, complex_words[i], i)); 904 | 905 | ck_assert(si_trie_clear(trie_map)); 906 | ck_assert(si_trie_count(trie_map) == 0); 907 | } 908 | END_TEST 909 | 910 | START_TEST(trie_map_simple_iter_both) { 911 | int word_count[ARRAY_SIZE(simple_words)] = { 0 }; 912 | 913 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) 914 | ck_assert(si_trie_set(trie_map, simple_words[i], i)); 915 | 916 | char* key; 917 | int value; 918 | trie_map_iter_start(SITrie, trie_map, key, value) { 919 | ck_assert(strcmp(key, simple_words[value]) == 0); 920 | word_count[value] += 1; 921 | } 922 | trie_map_iter_end 923 | 924 | for(int i = 0; i < ARRAY_SIZE(word_count); i++) { 925 | ck_assert(word_count[i] == 1); 926 | } 927 | } 928 | END_TEST 929 | 930 | START_TEST(trie_map_simple_iter_key) { 931 | int word_count[ARRAY_SIZE(simple_words)] = { 0 }; 932 | 933 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) 934 | ck_assert(si_trie_set(trie_map, simple_words[i], i)); 935 | 936 | char* key; 937 | trie_map_iter_key_start(SITrie, trie_map, key) { 938 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) { 939 | if(strcmp(key, simple_words[i]) == 0) { 940 | word_count[i] += 1; 941 | } 942 | } 943 | } 944 | trie_map_iter_end 945 | 946 | for(int i = 0; i < ARRAY_SIZE(word_count); i++) { 947 | ck_assert(word_count[i] == 1); 948 | } 949 | } 950 | END_TEST 951 | 952 | START_TEST(trie_map_simple_iter_value) { 953 | int word_count[ARRAY_SIZE(simple_words)] = { 0 }; 954 | 955 | for(int i = 0; i < ARRAY_SIZE(simple_words); i++) 956 | ck_assert(si_trie_set(trie_map, simple_words[i], i)); 957 | 958 | int value; 959 | trie_map_iter_value_start(SITrie, trie_map, value) { 960 | word_count[value] += 1; 961 | } 962 | trie_map_iter_end 963 | 964 | for(int i = 0; i < ARRAY_SIZE(word_count); i++) { 965 | ck_assert(word_count[i] == 1); 966 | } 967 | } 968 | END_TEST 969 | 970 | START_TEST(trie_map_complex_iter_both) { 971 | int word_count[ARRAY_SIZE(complex_words)] = { 0 }; 972 | 973 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) 974 | ck_assert(si_trie_set(trie_map, complex_words[i], i)); 975 | 976 | char* key; 977 | int value; 978 | trie_map_iter_start(SITrie, trie_map, key, value) { 979 | ck_assert(strcmp(key, complex_words[value]) == 0); 980 | word_count[value] += 1; 981 | } 982 | trie_map_iter_end 983 | 984 | for(int i = 0; i < ARRAY_SIZE(word_count); i++) { 985 | ck_assert(word_count[i] == 1); 986 | } 987 | } 988 | END_TEST 989 | 990 | START_TEST(trie_map_complex_iter_key) { 991 | int word_count[ARRAY_SIZE(complex_words)] = { 0 }; 992 | 993 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) 994 | ck_assert(si_trie_set(trie_map, complex_words[i], i)); 995 | 996 | char* key; 997 | trie_map_iter_key_start(SITrie, trie_map, key) { 998 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) { 999 | if(strcmp(key, complex_words[i]) == 0) { 1000 | word_count[i] += 1; 1001 | } 1002 | } 1003 | } 1004 | trie_map_iter_end 1005 | 1006 | for(int i = 0; i < ARRAY_SIZE(word_count); i++) { 1007 | ck_assert(word_count[i] == 1); 1008 | } 1009 | } 1010 | END_TEST 1011 | 1012 | START_TEST(trie_map_complex_iter_value) { 1013 | int word_count[ARRAY_SIZE(complex_words)] = { 0 }; 1014 | 1015 | for(int i = 0; i < ARRAY_SIZE(complex_words); i++) 1016 | ck_assert(si_trie_set(trie_map, complex_words[i], i)); 1017 | 1018 | int value; 1019 | trie_map_iter_value_start(SITrie, trie_map, value) { 1020 | word_count[value] += 1; 1021 | } 1022 | trie_map_iter_end 1023 | 1024 | for(int i = 0; i < ARRAY_SIZE(word_count); i++) { 1025 | ck_assert(word_count[i] == 1); 1026 | } 1027 | } 1028 | END_TEST 1029 | 1030 | int main(void) { 1031 | Suite* s = suite_create("Trie Tests"); 1032 | TCase* tc_set = tcase_create("Trie Set Tests"); 1033 | TCase* tc_map = tcase_create("Trie Map Tests"); 1034 | 1035 | tcase_add_checked_fixture(tc_set, trie_set_start, trie_set_reset); 1036 | tcase_add_test(tc_set, trie_set_allocate_and_deallocate); 1037 | tcase_add_test(tc_set, trie_set_simple_add_new_value_succeeds); 1038 | tcase_add_test(tc_set, trie_set_simple_add_repeat_value_fails); 1039 | tcase_add_test(tc_set, trie_set_complex_add_new_value_succeeds); 1040 | tcase_add_test(tc_set, trie_set_complex_add_repeat_value_fails); 1041 | tcase_add_test(tc_set, trie_set_simple_contains_added_value_succeeds); 1042 | tcase_add_test(tc_set, trie_set_simple_contains_missing_value_fails); 1043 | tcase_add_test(tc_set, trie_set_complex_contains_added_value_succeeds); 1044 | tcase_add_test(tc_set, trie_set_complex_contains_missing_value_fails); 1045 | tcase_add_test(tc_set, trie_set_simple_remove_added_value_succeeds); 1046 | tcase_add_test(tc_set, trie_set_simple_remove_missing_value_fails); 1047 | tcase_add_test(tc_set, trie_set_complex_remove_added_value_succeeds); 1048 | tcase_add_test(tc_set, trie_set_complex_remove_missing_value_fails); 1049 | tcase_add_test(tc_set, trie_set_simple_add_and_remove); 1050 | tcase_add_test(tc_set, trie_set_complex_add_and_remove); 1051 | tcase_add_test(tc_set, trie_set_simple_children_count); 1052 | tcase_add_test(tc_set, trie_set_complex_children_count); 1053 | tcase_add_test(tc_set, trie_set_large_children_count); 1054 | tcase_add_test(tc_set, trie_set_simple_children_all_alloc); 1055 | tcase_add_test(tc_set, trie_set_simple_children_all_no_alloc); 1056 | tcase_add_test(tc_set, trie_set_simple_children_partial); 1057 | tcase_add_test(tc_set, trie_set_complex_children_all_alloc); 1058 | tcase_add_test(tc_set, trie_set_complex_children_all_no_alloc); 1059 | tcase_add_test(tc_set, trie_set_children_null_out_values_returns_children_count); 1060 | tcase_add_test(tc_set, trie_set_simple_iter); 1061 | tcase_add_test(tc_set, trie_set_complex_iter); 1062 | 1063 | tcase_add_checked_fixture(tc_map, trie_map_start, trie_map_reset); 1064 | tcase_add_test(tc_map, trie_map_allocate_and_deallocate); 1065 | tcase_add_test(tc_map, trie_map_simple_add_new_value_succeeds); 1066 | tcase_add_test(tc_map, trie_map_simple_add_repeat_value_fails); 1067 | tcase_add_test(tc_map, trie_map_complex_add_new_value_succeeds); 1068 | tcase_add_test(tc_map, trie_map_complex_add_repeat_value_fails); 1069 | tcase_add_test(tc_map, trie_map_simple_set_new_value_succeeds); 1070 | tcase_add_test(tc_map, trie_map_simple_set_repeat_value_succeeds); 1071 | tcase_add_test(tc_map, trie_map_complex_set_new_value_succeeds); 1072 | tcase_add_test(tc_map, trie_map_complex_set_repeat_value_succeeds); 1073 | tcase_add_test(tc_map, trie_map_get_missing_value_returns_default); 1074 | tcase_add_test(tc_map, trie_map_simple_try_get_added_value_succeeds); 1075 | tcase_add_test(tc_map, trie_map_simple_try_get_missing_value_fails); 1076 | tcase_add_test(tc_map, trie_map_complex_try_get_added_value_succeeds); 1077 | tcase_add_test(tc_map, trie_map_complex_try_get_missing_value_fails); 1078 | tcase_add_test(tc_map, trie_map_simple_remove_added_succeeds); 1079 | tcase_add_test(tc_map, trie_map_simple_remove_missing_fails); 1080 | tcase_add_test(tc_map, trie_map_simple_remove_some_succeeds); 1081 | tcase_add_test(tc_map, trie_map_complex_remove_added_succeeds); 1082 | tcase_add_test(tc_map, trie_map_complex_remove_missing_fails); 1083 | tcase_add_test(tc_map, trie_map_complex_remove_some_succeeds); 1084 | tcase_add_test(tc_map, trie_map_simple_get_and_remove_added_value_succeeds); 1085 | tcase_add_test(tc_map, trie_map_simple_get_and_remove_missing_value_fails); 1086 | tcase_add_test(tc_map, trie_map_simple_get_and_remove_some_succeeds); 1087 | tcase_add_test(tc_map, trie_map_complex_get_and_remove_added_value_succeeds); 1088 | tcase_add_test(tc_map, trie_map_complex_get_and_remove_missing_value_fails); 1089 | tcase_add_test(tc_map, trie_map_complex_get_and_remove_some_succeeds); 1090 | tcase_add_test(tc_map, trie_map_simple_clear_succeeds); 1091 | tcase_add_test(tc_map, trie_map_complex_clear_succeeds); 1092 | tcase_add_test(tc_map, trie_map_simple_iter_both); 1093 | tcase_add_test(tc_map, trie_map_simple_iter_key); 1094 | tcase_add_test(tc_map, trie_map_simple_iter_value); 1095 | tcase_add_test(tc_map, trie_map_complex_iter_both); 1096 | tcase_add_test(tc_map, trie_map_complex_iter_key); 1097 | tcase_add_test(tc_map, trie_map_complex_iter_value); 1098 | 1099 | suite_add_tcase(s, tc_set); 1100 | suite_add_tcase(s, tc_map); 1101 | 1102 | SRunner* sr = srunner_create(s); 1103 | srunner_run_all(sr, CK_NORMAL); 1104 | int number_failed = srunner_ntests_failed(sr); 1105 | srunner_free(sr); 1106 | 1107 | return number_failed == 0 ? EXIT_SUCCESS : EXIT_FAILURE; 1108 | } -------------------------------------------------------------------------------- /todolist.txt: -------------------------------------------------------------------------------- 1 | Additional Data Structure: 2 | ☐ Sorted Set @low 3 | ☐ Binary Heap @high 4 | ☐ Fibonacci Heap @low 5 | ☐ Trie @low 6 | ☐ Linked List @critical 7 | ☐ Pair @low 8 | 9 | Extra Utilities: 10 | ☐ [generic_map.h] map (create and init)_capacity functions 11 | 12 | Bugs: 13 | ☐ [generic_iterators/trie_iterator.h] Trie iterator tries to return the same value twice in a row sometimes. Currently works with bandaid. 14 | 15 | ___________________ 16 | Archive: 17 | ✔ Deque @high @done (20-01-07 14:13) @project(Additional Data Structure) 18 | ✔ create and destroy functions - These will allocate and free the actual data structures themselves, not just the fields. @high @done (19-09-08 19:36) @project(Extra Utilities) 19 | ✔ map - get_and_remove function - A function that gets both the key and value from the map, then removes the associated cell. The user can then free or otherwise manipulate the left over key and value data. @high @done (19-09-08 19:35) @project(Extra Utilities) 20 | ✔ Grid @low @done (19-09-05 13:44) @project(Additional Data Structure) 21 | ✔ Collection Iterators @high @done (19-09-05 13:44) @project(Additional Data Structure) 22 | ✔ Set @critical @done (19-09-05 13:43) @project(Additional Data Structure) 23 | --------------------------------------------------------------------------------