Loading...
Searching...
No Matches
Go to the documentation of this file. 1#ifndef KEST_DYNAMIC_ARRAY_H_
2#define KEST_DYNAMIC_ARRAY_H_
4#define DECLARE_LIST(X) \
5typedef struct X##_list { \
9 kest_allocator alloc; \
12int X##_list_init(X##_list *list); \
13int X##_list_init_with_allocator(X##_list *list, const kest_allocator *alloc); \
14int X##_list_init_reserved(X##_list *list, size_t n); \
15int X##_list_init_reserved_with_allocator(X##_list *list, size_t n, const kest_allocator *alloc); \
16int X##_list_reserve(X##_list *list, size_t n); \
17int X##_list_append(X##_list *list, X x); \
18int X##_list_append_ref(X##_list *list, const X *x); \
19int X##_list_destroy(X##_list *list); \
20int X##_list_destroy_all(X##_list *list, void (*destructor)(X *x)); \
21int X##_list_contains(X##_list *list, X x, int (*cmp)(const X*, const X*)); \
22int X##_list_contains_ref(X##_list *list, const X *x, int (*cmp)(const X*, const X*)); \
23int X##_list_index_of(X##_list *list, X x, int (*cmp)(const X*, const X*)); \
24int X##_list_index_of_ref(X##_list *list, const X *x, int (*cmp)(const X*, const X*));\
25X *X##_list_head(X##_list *list);\
26X *X##_list_tail(X##_list *list);\
27int X##_list_pop_tail(X##_list *list);\
28int X##_list_pop_destroy_tail(X##_list *list, void (*destructor)(X *x));\
29int X##_list_append_list(X##_list *list, X##_list *a);\
30int X##_list_drain_destroy(X##_list *list, void (*destructor)(X *x));\
31int X##_list_drain(X##_list *list);
33#define IMPLEMENT_LIST(X) \
35int X##_list_init(X##_list *list) \
37 return X##_list_init_with_allocator(list, NULL); \
40int X##_list_init_with_allocator(X##_list *list, const kest_allocator *alloc) \
42 if (!list) return ERR_NULL_PTR; \
44 list->entries = NULL; \
47 list->alloc = alloc ? *alloc : (kest_allocator){0}; \
52int X##_list_init_reserved(X##_list *list, size_t n) \
54 return X##_list_init_reserved_with_allocator(list, n, NULL); \
57int X##_list_init_reserved_with_allocator(X##_list *list, size_t n, const kest_allocator *alloc) \
59 int r = X##_list_init_with_allocator(list, alloc); \
60 if (r != NO_ERROR) return r; \
62 if (n == 0) return NO_ERROR; \
64 list->entries = kest_allocator_alloc(&list->alloc, sizeof(X) * n); \
65 if (!list->entries) return ERR_ALLOC_FAIL; \
67 memset(list->entries, 0, sizeof(X) * n); \
73int X##_list_reserve(X##_list *list, size_t n) \
75 if (!list) return ERR_NULL_PTR; \
76 if (!n) return NO_ERROR; \
78 if (list->count + n <= list->capacity) \
81 size_t cap_needed = list->count + n - 1; \
82 cap_needed |= cap_needed >> 1; \
83 cap_needed |= cap_needed >> 2; \
84 cap_needed |= cap_needed >> 4; \
85 cap_needed |= cap_needed >> 8; \
86 cap_needed |= cap_needed >> 16; \
87 if (sizeof(size_t) > 4) cap_needed |= cap_needed >> 32; \
92 list->entries = kest_allocator_alloc(&list->alloc, sizeof(X) * cap_needed); \
97 return ERR_ALLOC_FAIL; \
99 memset(list->entries, 0, sizeof(X) * cap_needed); \
103 X *new_array = kest_allocator_realloc(&list->alloc, list->entries, sizeof(X) * cap_needed); \
104 if (!new_array) return ERR_ALLOC_FAIL; \
106 list->entries = new_array; \
107 memset(&list->entries[list->count], 0, sizeof(X) * (cap_needed - list->count)); \
110 list->capacity = cap_needed; \
114int X##_list_append(X##_list *list, X x) \
116 return X##_list_append_ref(list, &x); \
119int X##_list_append_ref(X##_list *list, const X *x) \
121 if (!list) return ERR_NULL_PTR; \
122 if (!x) return ERR_BAD_ARGS; \
124 int r = X##_list_reserve(list, 1); \
125 if (r != NO_ERROR) return r; \
127 memcpy(&list->entries[list->count], x, sizeof(X)); \
133int X##_list_destroy(X##_list *list) \
135 if (!list) return ERR_NULL_PTR; \
138 kest_allocator_free(&list->alloc, list->entries); \
140 list->entries = NULL; \
142 list->capacity = 0; \
147int X##_list_destroy_all(X##_list *list, void (*destructor)(X *x)) \
149 if (!list) return ERR_NULL_PTR; \
151 if (!list->entries) \
154 list->capacity = 0; \
160 for (int i = 0; i < list->count; i++) \
161 destructor(&list->entries[i]); \
164 kest_allocator_free(&list->alloc, list->entries); \
166 list->entries = NULL; \
168 list->capacity = 0; \
173int X##_list_contains(X##_list *list, X x, int (*cmp)(const X*, const X*)) \
175 return X##_list_contains_ref(list, &x, cmp); \
178int X##_list_contains_ref(X##_list *list, const X *x, int (*cmp)(const X*, const X*)) \
180 if (!list || !list->entries) return 0; \
182 for (int i = 0; i < list->count && i < list->capacity; i++) \
186 if (cmp(&list->entries[i], x) == 0) return 1; \
190 if (memcmp(&list->entries[i], x, sizeof(X)) == 0) return 1; \
196int X##_list_index_of(X##_list *list, X x, int (*cmp)(const X*, const X*)) \
198 return X##_list_index_of_ref(list, &x, cmp); \
201int X##_list_index_of_ref(X##_list *list, const X *x, int (*cmp)(const X*, const X*)) \
203 if (!list || !list->entries) return -1; \
205 for (int i = 0; i < list->count && i < list->capacity; i++) \
209 if (cmp(&list->entries[i], x) == 0) return i; \
213 if (memcmp(&list->entries[i], x, sizeof(X)) == 0) return i; \
219X *X##_list_head(X##_list *list)\
227 if (list->count < 1) return NULL;\
229 return &list->entries[0];\
231X *X##_list_tail(X##_list *list)\
239 if (list->count < 1 || list->capacity < list->count) return NULL;\
241 return &list->entries[list->count - 1];\
244int X##_list_pop_destroy_tail(X##_list *list, void (*destructor)(X *x))\
247 return ERR_NULL_PTR;\
249 if (list->count > 0)\
252 destructor(&list->entries[list->count]);\
258int X##_list_pop_tail(X##_list *list)\
261 return ERR_NULL_PTR;\
263 if (list->count > 0)\
269int X##_list_append_list(X##_list *list, X##_list *a)\
272 return ERR_NULL_PTR;\
278 return ERR_BAD_ARGS;\
280 X##_list_reserve(list, a->count);\
282 memcpy(&list->entries[list->count], a->entries, sizeof(X) * a->count);\
284 list->count += a->count;\
289int X##_list_drain_destroy(X##_list *list, void (*destructor)(X *x))\
292 return ERR_NULL_PTR;\
295 for (int i = 0; i < list->count; i++)\
298 destructor(&list->entries[i]);\
305int X##_list_drain(X##_list *list)\
308 return ERR_NULL_PTR;\
315#define DECLARE_PTR_LIST(X) \
316typedef struct X##_ptr_list { \
320 kest_allocator alloc; \
323int X##_ptr_list_init(X##_ptr_list *list); \
324int X##_ptr_list_init_with_allocator(X##_ptr_list *list, const kest_allocator *alloc); \
325int X##_ptr_list_reserve(X##_ptr_list *list, size_t n); \
326int X##_ptr_list_append(X##_ptr_list *list, X *x); \
327int X##_ptr_list_destroy(X##_ptr_list *list); \
328int X##_ptr_list_destroy_all(X##_ptr_list *list, void (*destructor)(X *x)); \
329int X##_ptr_list_contains(X##_ptr_list *list, X *x); \
330int X##_ptr_list_index_of(X##_ptr_list *list, X *x); \
331X **X##_ptr_list_head(X##_ptr_list *list);\
332X **X##_ptr_list_tail(X##_ptr_list *list);\
333int X##_ptr_list_pop_tail(X##_ptr_list *list);\
334int X##_ptr_list_append_list(X##_ptr_list *list, X##_ptr_list *a);\
335int X##_ptr_list_drain_destroy(X##_ptr_list *list, void (*destructor)(X *x));\
336int X##_ptr_list_drain(X##_ptr_list *list);
339#define IMPLEMENT_PTR_LIST(X) \
341int X##_ptr_list_init(X##_ptr_list *list) \
343 return X##_ptr_list_init_with_allocator(list, NULL); \
346int X##_ptr_list_init_with_allocator(X##_ptr_list *list, const kest_allocator *alloc) \
348 if (!list) return ERR_NULL_PTR; \
350 list->entries = NULL; \
352 list->capacity = 0; \
353 list->alloc = alloc ? *alloc : (kest_allocator){0}; \
358int X##_ptr_list_reserve(X##_ptr_list *list, size_t n) \
360 if (!list) return ERR_NULL_PTR; \
361 if (!n) return NO_ERROR; \
363 if (list->count + n <= list->capacity) \
366 size_t cap_needed = list->count + n - 1; \
367 cap_needed |= cap_needed >> 1; \
368 cap_needed |= cap_needed >> 2; \
369 cap_needed |= cap_needed >> 4; \
370 cap_needed |= cap_needed >> 8; \
371 cap_needed |= cap_needed >> 16; \
372 if (sizeof(size_t) > 4) cap_needed |= cap_needed >> 32; \
375 if (!list->entries) \
377 list->entries = kest_allocator_alloc(&list->alloc, sizeof(X*) * cap_needed); \
378 if (!list->entries) return ERR_ALLOC_FAIL; \
379 memset(list->entries, 0, sizeof(X*) * cap_needed); \
383 X **new_array = kest_allocator_realloc(&list->alloc, list->entries, sizeof(X*) * cap_needed); \
384 if (!new_array) return ERR_ALLOC_FAIL; \
386 list->entries = new_array; \
387 memset(&list->entries[list->count], 0, sizeof(X*) * (cap_needed - list->count)); \
390 list->capacity = cap_needed; \
394int X##_ptr_list_append(X##_ptr_list *list, X *x) \
396 if (!list) return ERR_NULL_PTR; \
398 int r = X##_ptr_list_reserve(list, 1); \
399 if (r != NO_ERROR) return r; \
401 list->entries[list->count++] = x; \
405int X##_ptr_list_destroy(X##_ptr_list *list) \
407 if (!list) return ERR_NULL_PTR; \
410 kest_allocator_free(&list->alloc, list->entries); \
412 list->entries = NULL; \
414 list->capacity = 0; \
419int X##_ptr_list_destroy_all(X##_ptr_list *list, void (*destructor)(X *x)) \
421 if (!list) return ERR_NULL_PTR; \
423 if (!list->entries) \
426 list->capacity = 0; \
432 for (int i = 0; i < list->count; i++) \
433 if (list->entries[i]) destructor(list->entries[i]); \
437 for (int i = 0; i < list->count; i++) \
438 if (list->entries[i]) kest_allocator_free(&list->alloc, list->entries[i]); \
441 kest_allocator_free(&list->alloc, list->entries); \
443 list->entries = NULL; \
445 list->capacity = 0; \
450int X##_ptr_list_contains(X##_ptr_list *list, X *x) \
452 if (!list || !list->entries) return 0; \
454 for (int i = 0; i < list->count; i++) \
455 if (list->entries[i] == x) return 1; \
460int X##_ptr_list_index_of(X##_ptr_list *list, X *x) \
462 if (!list || !list->entries) return -1; \
464 for (int i = 0; i < list->count; i++) \
465 if (list->entries[i] == x) return i; \
469X **X##_ptr_list_head(X##_ptr_list *list)\
477 if (list->count < 1) return NULL;\
479 return &list->entries[0];\
481X **X##_ptr_list_tail(X##_ptr_list *list)\
489 if (list->count < 1 || list->capacity < list->count) return NULL;\
491 return &list->entries[list->count - 1];\
494int X##_ptr_list_pop_destroy_tail(X##_ptr_list *list, void (*destructor)(X *x))\
497 return ERR_NULL_PTR;\
499 if (list->count > 0)\
502 destructor(list->entries[list->count]);\
508int X##_ptr_list_pop_tail(X##_ptr_list *list)\
511 return ERR_NULL_PTR;\
513 if (list->count > 0)\
519int X##_ptr_list_append_list(X##_ptr_list *list, X##_ptr_list *a)\
522 return ERR_NULL_PTR;\
529 return ERR_BAD_ARGS;\
531 X##_ptr_list_reserve(list, a->count);\
533 memcpy(&list->entries[list->count], a->entries, sizeof(X*) * a->count);\
535 list->count += a->count;\
540int X##_ptr_list_drain_destroy(X##_ptr_list *list, void (*destructor)(X *x))\
543 return ERR_NULL_PTR;\
546 for (int i = 0; i < list->count; i++)\
548 if (destructor && list->entries[i])\
549 destructor(list->entries[i]);\
556int X##_ptr_list_drain(X##_ptr_list *list)\
559 return ERR_NULL_PTR;\