diff --git a/src/cmc/bidimap.h b/src/cmc/bidimap.h index 464bf7c..6c984ca 100644 --- a/src/cmc/bidimap.h +++ b/src/cmc/bidimap.h @@ -798,9 +798,11 @@ struct cmc_callbacks_bidimap struct SNAME *PFX##_copy_of(struct SNAME *_map_, K (*key_copy_func)(K), \ V (*value_copy_func)(V)) \ { \ - struct SNAME *result = PFX##_new(PFX##_capacity(_map_), PFX##_load(_map_), \ - _map_->key_cmp, _map_->key_hash, \ - _map_->val_cmp, _map_->val_hash); \ + /* TODO this function can be optimized */ \ + struct SNAME *result = PFX##_new_custom(PFX##_capacity(_map_), PFX##_load(_map_), \ + _map_->key_cmp, _map_->key_hash, \ + _map_->val_cmp, _map_->val_hash, \ + _map_->alloc, _map_->callbacks); \ \ for (size_t i = 0; i < _map_->capacity; i++) \ { \ @@ -870,14 +872,13 @@ struct cmc_callbacks_bidimap { \ struct cmc_string str; \ struct SNAME *m_ = _map_; \ - const char *name = #SNAME; \ \ int n = snprintf(str.s, cmc_string_len, cmc_string_fmt_bidimap, \ - name, #K, #V, m_, m_->key_buffer, m_->val_buffer, m_->capacity, \ + #SNAME, #K, #V, m_, m_->key_buffer, m_->val_buffer, m_->capacity, \ m_->count, m_->load, m_->key_cmp, m_->val_cmp, m_->key_hash, \ m_->val_hash, m_->alloc, m_->callbacks); \ \ - if (n < 0 || n == cmc_string_len) \ + if (n < 0 || n == (int)cmc_string_len) \ return (struct cmc_string){0}; \ \ str.s[n] = '\0'; \ diff --git a/src/cmc/deque.h b/src/cmc/deque.h index 49085b9..71b0e89 100644 --- a/src/cmc/deque.h +++ b/src/cmc/deque.h @@ -535,13 +535,12 @@ struct cmc_callbacks_deque { \ struct cmc_string str; \ struct SNAME *d_ = _deque_; \ - const char *name = #SNAME; \ \ int n = snprintf(str.s, cmc_string_len, cmc_string_fmt_deque, \ - name, #V, d_, d_->buffer, d_->capacity, d_->count, \ + #SNAME, #V, d_, d_->buffer, d_->capacity, d_->count, \ d_->front, d_->back, d_->alloc, d_->callbacks); \ \ - if (n < 0 || n == cmc_string_len) \ + if (n < 0 || n == (int)cmc_string_len) \ return (struct cmc_string){0}; \ \ str.s[n] = '\0'; \ diff --git a/src/cmc/hashmap.h b/src/cmc/hashmap.h index 4625a25..c5fa4a2 100644 --- a/src/cmc/hashmap.h +++ b/src/cmc/hashmap.h @@ -12,8 +12,8 @@ * HashMap * * A HashMap is an implementation of a Map with unique keys, where every key is - * mapped to a value. The keys are not sorted. It is implemented as a hashtable - * with robin hood hashing. + * mapped to a value. The keys are not sorted. It is implemented as a flat + * hashtable with linear probing and robin hood hashing. */ #ifndef CMC_HASHMAP_H @@ -100,7 +100,7 @@ static const char *cmc_string_fmt_hashmap = "struct %s<%s, %s> " "count:%" PRIuMAX ", " "load:%lf, " "cmp:%p, " - "hash:%p " + "hash:%p, " "alloc:%p, " "callbacks:%p }"; @@ -758,13 +758,12 @@ struct cmc_callbacks_hashmap { \ struct cmc_string str; \ struct SNAME *m_ = _map_; \ - const char *name = #SNAME; \ \ int n = snprintf(str.s, cmc_string_len, cmc_string_fmt_hashmap, \ - name, #K, #V, m_, m_->buffer, m_->capacity, m_->count, \ + #SNAME, #K, #V, m_, m_->buffer, m_->capacity, m_->count, \ m_->load, m_->cmp, m_->hash, m_->alloc, m_->callbacks); \ \ - if (n < 0 || n == cmc_string_len) \ + if (n < 0 || n == (int)cmc_string_len) \ return (struct cmc_string){0}; \ \ str.s[n] = '\0'; \ diff --git a/src/cmc/hashset.h b/src/cmc/hashset.h index 2cf088c..3485bbd 100644 --- a/src/cmc/hashset.h +++ b/src/cmc/hashset.h @@ -12,7 +12,8 @@ * HashSet * * A HashSet is an implementation of a Set with unique keys. The keys are not - * sorted. It is implemented as a hashtable with robin hood hashing. + * sorted. It is implemented as a flat hashtable with linear probing and robin + * hood hashing. */ #ifndef CMC_HASHSET_H @@ -99,7 +100,7 @@ static const char *cmc_string_fmt_hashset = "struct %s<%s> " "count:%" PRIuMAX ", " "load:%lf, " "cmp:%p, " - "hash:%p " + "hash:%p, " "alloc:%p, " "callbacks: %p }"; @@ -398,8 +399,8 @@ struct cmc_callbacks_hashset } \ } \ \ - free(_set_->buffer); \ - free(_set_); \ + _set_->alloc->free(_set_->buffer); \ + _set_->alloc->free(_set_); \ } \ \ void PFX##_customize(struct SNAME *_set_, struct cmc_alloc_node *alloc, \ @@ -611,7 +612,8 @@ struct cmc_callbacks_hashset \ struct SNAME *PFX##_copy_of(struct SNAME *_set_, V (*copy_func)(V)) \ { \ - struct SNAME *result = PFX##_new(_set_->capacity, _set_->load, _set_->cmp, _set_->hash); \ + struct SNAME *result = PFX##_new_custom(_set_->capacity, _set_->load, _set_->cmp, \ + _set_->hash, _set_->alloc, _set_->callbacks); \ \ if (!result) \ return NULL; \ @@ -670,13 +672,12 @@ struct cmc_callbacks_hashset { \ struct cmc_string str; \ struct SNAME *s_ = _set_; \ - const char *name = #SNAME; \ \ int n = snprintf(str.s, cmc_string_len, cmc_string_fmt_hashset, \ - name, #V, s_, s_->buffer, s_->capacity, s_->count, \ + #SNAME, #V, s_, s_->buffer, s_->capacity, s_->count, \ s_->load, s_->cmp, s_->hash, s_->alloc, s_->callbacks); \ \ - if (n < 0 || n == cmc_string_len) \ + if (n < 0 || n == (int)cmc_string_len) \ return (struct cmc_string){0}; \ \ str.s[n] = '\0'; \ @@ -894,7 +895,7 @@ struct cmc_callbacks_hashset \ struct SNAME##_iter *PFX##_iter_new(struct SNAME *target) \ { \ - struct SNAME##_iter *iter = malloc(sizeof(struct SNAME##_iter)); \ + struct SNAME##_iter *iter = target->alloc->malloc(sizeof(struct SNAME##_iter)); \ \ if (!iter) \ return NULL; \ @@ -906,7 +907,7 @@ struct cmc_callbacks_hashset \ void PFX##_iter_free(struct SNAME##_iter *iter) \ { \ - free(iter); \ + iter->target->alloc->free(iter); \ } \ \ void PFX##_iter_init(struct SNAME##_iter *iter, struct SNAME *target) \ diff --git a/src/cmc/heap.h b/src/cmc/heap.h index 65ec1bc..7893a2e 100644 --- a/src/cmc/heap.h +++ b/src/cmc/heap.h @@ -93,7 +93,7 @@ static const char *cmc_string_fmt_heap = "struct %s<%s> " "capacity:%" PRIuMAX ", " "count:%" PRIuMAX ", " "type:%s, " - "cmp:%p " + "cmp:%p, " "alloc:%p, " "callbacks: %p}"; @@ -336,8 +336,8 @@ struct cmc_callbacks_heap } \ } \ \ - free(_heap_->buffer); \ - free(_heap_); \ + _heap_->alloc->free(_heap_->buffer); \ + _heap_->alloc->free(_heap_); \ } \ \ void PFX##_customize(struct SNAME *_heap_, struct cmc_alloc_node *alloc, \ @@ -436,7 +436,7 @@ struct cmc_callbacks_heap if (capacity < PFX##_count(_heap_)) \ return false; \ \ - V *new_buffer = realloc(_heap_->buffer, sizeof(V) * capacity); \ + V *new_buffer = _heap_->alloc->realloc(_heap_->buffer, sizeof(V) * capacity); \ \ if (!new_buffer) \ return false; \ @@ -449,7 +449,8 @@ struct cmc_callbacks_heap \ struct SNAME *PFX##_copy_of(struct SNAME *_heap_, V (*copy_func)(V)) \ { \ - struct SNAME *result = PFX##_new(_heap_->capacity, _heap_->HO, _heap_->cmp); \ + struct SNAME *result = PFX##_new_custom(_heap_->capacity, _heap_->HO, _heap_->cmp, \ + _heap_->alloc, _heap_->callbacks); \ \ if (!result) \ return NULL; \ @@ -485,18 +486,23 @@ struct cmc_callbacks_heap { \ struct cmc_string str; \ struct SNAME *h_ = _heap_; \ - const char *name = #SNAME; \ const char *t = h_->HO == 1 ? "MaxHeap" : "MinHeap"; \ \ - snprintf(str.s, cmc_string_len, cmc_string_fmt_heap, \ - name, h_, h_->buffer, h_->capacity, h_->count, t, h_->cmp); \ + int n = snprintf(str.s, cmc_string_len, cmc_string_fmt_heap, \ + #SNAME, #V, h_, h_->buffer, h_->capacity, h_->count, \ + t, h_->cmp, h_->alloc, h_->callbacks); \ + \ + if (n < 0 || n == (int)cmc_string_len) \ + return (struct cmc_string){0}; \ + \ + str.s[n] = '\0'; \ \ return str; \ } \ \ struct SNAME##_iter *PFX##_iter_new(struct SNAME *target) \ { \ - struct SNAME##_iter *iter = malloc(sizeof(struct SNAME##_iter)); \ + struct SNAME##_iter *iter = target->alloc->malloc(sizeof(struct SNAME##_iter)); \ \ if (!iter) \ return NULL; \ @@ -508,7 +514,7 @@ struct cmc_callbacks_heap \ void PFX##_iter_free(struct SNAME##_iter *iter) \ { \ - free(iter); \ + iter->target->alloc->free(iter); \ } \ \ void PFX##_iter_init(struct SNAME##_iter *iter, struct SNAME *target) \ diff --git a/src/cmc/intervalheap.h b/src/cmc/intervalheap.h index 36ebfa4..3616cb1 100644 --- a/src/cmc/intervalheap.h +++ b/src/cmc/intervalheap.h @@ -26,10 +26,68 @@ #include #include #include -#include "../utl/cmc_string.h" +/* ------------------------------------------------------------------------------------------------- + * Core functionalities of the C Macro Collections Library + ------------------------------------------------------------------------------------------------ */ +#ifndef CMC_CORE_H +#define CMC_CORE_H + +/** + * struct cmc_string + * + * Used by all collections when calling the to_string function. + */ +struct cmc_string +{ + char s[400]; +}; + +static const size_t cmc_string_len = 400; + +/** + * struct cmc_alloc_node + * + * Custom allocation node. Allows collections to use custom allocation functions. + */ +struct cmc_alloc_node +{ + void *(*malloc)(size_t); + void *(*calloc)(size_t, size_t); + void *(*realloc)(void *, size_t); + void (*free)(void *); +} cmc_alloc_node_default = {malloc, calloc, realloc, free}; + +#endif /* CMC_CORE_H */ + +/* ------------------------------------------------------------------------------------------------- + * IntervalHeap specific + ------------------------------------------------------------------------------------------------ */ /* to_string format */ -static const char *cmc_string_fmt_intervalheap = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", size:%" PRIuMAX ", count:%" PRIuMAX ", cmp:%p }"; +static const char *cmc_string_fmt_intervalheap = "struct %s<%s> " + "at %p { " + "buffer:%p, " + "capacity:%" PRIuMAX ", " + "size:%" PRIuMAX ", " + "count:%" PRIuMAX ", " + "cmp:%p, " + "alloc:%p, " + "callbacks:%p }"; + +/** + * Custom IntervalHeap callbacks. + * + * There are two types of callbacks, 'before' and 'after': + * _ + */ +struct cmc_callbacks_intervalheap +{ + void (*before_clear)(void *); + void (*after_clear)(void *); + void (*before_free)(void *); + void (*after_free)(void *); + // TODO implement all callbacks +}; #define CMC_GENERATE_INTERVALHEAP(PFX, SNAME, V) \ CMC_GENERATE_INTERVALHEAP_HEADER(PFX, SNAME, V) \ @@ -41,907 +99,989 @@ static const char *cmc_string_fmt_intervalheap = "%s at %p { buffer:%p, capacity #define CMC_WRAPGEN_INTERVALHEAP_SOURCE(PFX, SNAME, K, V) \ CMC_GENERATE_INTERVALHEAP_SOURCE(PFX, SNAME, V) -/* HEADER ********************************************************************/ -#define CMC_GENERATE_INTERVALHEAP_HEADER(PFX, SNAME, V) \ - \ - /* Heap Structure */ \ - struct SNAME \ - { \ - /* Dynamic array of nodes */ \ - struct SNAME##_node *buffer; \ - \ - /* Current array capacity (how many nodes can be stored) */ \ - size_t capacity; \ - \ - /* Current amount of nodes in the dynamic array */ \ - size_t size; \ - \ - /* Current amount of elements in the heap */ \ - size_t count; \ - \ - /* Element comparison function */ \ - int (*cmp)(V, V); \ - \ - /* Function that returns an iterator to the start of the heap */ \ - struct SNAME##_iter (*it_start)(struct SNAME *); \ - \ - /* Function that returns an iterator to the end of the heap */ \ - struct SNAME##_iter (*it_end)(struct SNAME *); \ - }; \ - \ - /* Heap Node */ \ - struct SNAME##_node \ - { \ - /* 0 - Value belonging to the MinHeap */ \ - /* 1 - Value belonging to the MaxHeap */ \ - V data[2]; \ - }; \ - \ - /* Heap Iterator */ \ - struct SNAME##_iter \ - { \ - /* Target heap */ \ - struct SNAME *target; \ - \ - /* Cursor's position (index) */ \ - size_t cursor; \ - \ - /* If the iterator has reached the start of the iteration */ \ - bool start; \ - \ - /* If the iterator has reached the end of the iteration */ \ - bool end; \ - }; \ - \ - /* Collection Functions */ \ - /* Collection Allocation and Deallocation */ \ - struct SNAME *PFX##_new(size_t capacity, int (*compare)(V, V)); \ - void PFX##_clear(struct SNAME *_heap_, void (*deallocator)(V)); \ - void PFX##_free(struct SNAME *_heap_, void (*deallocator)(V)); \ - /* Collection Input and Output */ \ - bool PFX##_insert(struct SNAME *_heap_, V element); \ - bool PFX##_remove_max(struct SNAME *_heap_, V *result); \ - bool PFX##_remove_min(struct SNAME *_heap_, V *result); \ - /* Collection Update */ \ - bool PFX##_update_max(struct SNAME *_heap_, V element); \ - bool PFX##_update_min(struct SNAME *_heap_, V element); \ - /* Element Access */ \ - bool PFX##_max(struct SNAME *_heap_, V *value); \ - bool PFX##_min(struct SNAME *_heap_, V *value); \ - /* Collection State */ \ - bool PFX##_contains(struct SNAME *_heap_, V element); \ - bool PFX##_empty(struct SNAME *_heap_); \ - bool PFX##_full(struct SNAME *_heap_); \ - size_t PFX##_count(struct SNAME *_heap_); \ - size_t PFX##_capacity(struct SNAME *_heap_); \ - /* Collection Utility */ \ - bool PFX##_resize(struct SNAME *_heap_, size_t capacity); \ - struct SNAME *PFX##_copy_of(struct SNAME *_set_, V (*copy_func)(V)); \ - bool PFX##_equals(struct SNAME *_heap1_, struct SNAME *_heap2_); \ - struct cmc_string PFX##_to_string(struct SNAME *_heap_); \ - \ - /* Iterator Functions */ \ - /* Iterator Allocation and Deallocation */ \ - struct SNAME##_iter *PFX##_iter_new(struct SNAME *target); \ - void PFX##_iter_free(struct SNAME##_iter *iter); \ - /* Iterator Initialization */ \ - void PFX##_iter_init(struct SNAME##_iter *iter, struct SNAME *target); \ - /* Iterator State */ \ - bool PFX##_iter_start(struct SNAME##_iter *iter); \ - bool PFX##_iter_end(struct SNAME##_iter *iter); \ - /* Iterator Movement */ \ - void PFX##_iter_to_start(struct SNAME##_iter *iter); \ - void PFX##_iter_to_end(struct SNAME##_iter *iter); \ - bool PFX##_iter_next(struct SNAME##_iter *iter); \ - bool PFX##_iter_prev(struct SNAME##_iter *iter); \ - bool PFX##_iter_advance(struct SNAME##_iter *iter, size_t steps); \ - bool PFX##_iter_rewind(struct SNAME##_iter *iter, size_t steps); \ - bool PFX##_iter_go_to(struct SNAME##_iter *iter, size_t index); \ - /* Iterator Access */ \ - V PFX##_iter_value(struct SNAME##_iter *iter); \ - size_t PFX##_iter_index(struct SNAME##_iter *iter); \ - \ -/* SOURCE ********************************************************************/ -#define CMC_GENERATE_INTERVALHEAP_SOURCE(PFX, SNAME, V) \ - \ - /* Implementation Detail Functions */ \ - static void PFX##_impl_float_up_max(struct SNAME *_heap_); \ - static void PFX##_impl_float_up_min(struct SNAME *_heap_); \ - static void PFX##_impl_float_down_max(struct SNAME *_heap_); \ - static void PFX##_impl_float_down_min(struct SNAME *_heap_); \ - static struct SNAME##_iter PFX##_impl_it_start(struct SNAME *_heap_); \ - static struct SNAME##_iter PFX##_impl_it_end(struct SNAME *_heap_); \ - \ - struct SNAME *PFX##_new(size_t capacity, int (*compare)(V, V)) \ - { \ - if (capacity == 0 || capacity == UINT64_MAX) \ - return NULL; \ - \ - struct SNAME *_heap_ = malloc(sizeof(struct SNAME)); \ - \ - if (!_heap_) \ - return NULL; \ - \ - /* Since each node can store two elements, divide the actual capacity by 2 */ \ - /* Round the capacity of nodes up */ \ - capacity = capacity % 2 == 0 ? capacity / 2 : (capacity + 1) / 2; \ - \ - _heap_->buffer = calloc(capacity, sizeof(struct SNAME##_node)); \ - \ - if (!_heap_->buffer) \ - { \ - free(_heap_); \ - return NULL; \ - } \ - \ - _heap_->capacity = capacity; \ - _heap_->size = 0; \ - _heap_->count = 0; \ - _heap_->cmp = compare; \ - \ - _heap_->it_start = PFX##_impl_it_start; \ - _heap_->it_end = PFX##_impl_it_end; \ - \ - return _heap_; \ - } \ - \ - void PFX##_clear(struct SNAME *_heap_, void (*deallocator)(V)) \ - { \ - if (deallocator) \ - { \ - for (size_t i = 0; i < _heap_->count; i++) \ - { \ - deallocator(_heap_->buffer[i / 2].data[i % 2]); \ - } \ - } \ - \ - memset(_heap_->buffer, 0, sizeof(V) * _heap_->capacity); \ - \ - _heap_->size = 0; \ - _heap_->count = 0; \ - } \ - \ - void PFX##_free(struct SNAME *_heap_, void (*deallocator)(V)) \ - { \ - if (deallocator) \ - { \ - for (size_t i = 0; i < _heap_->count; i++) \ - { \ - deallocator(_heap_->buffer[i / 2].data[i % 2]); \ - } \ - } \ - \ - free(_heap_->buffer); \ - \ - free(_heap_); \ - } \ - \ - bool PFX##_insert(struct SNAME *_heap_, V element) \ - { \ - if (PFX##_full(_heap_)) \ - { \ - if (!PFX##_resize(_heap_, PFX##_capacity(_heap_) * 4)) \ - return false; \ - } \ - \ - if (PFX##_count(_heap_) % 2 == 0) \ - { \ - /* Occupying a new node */ \ - _heap_->buffer[_heap_->size].data[0] = element; \ - _heap_->buffer[_heap_->size].data[1] = (V){0}; \ - \ - _heap_->size++; \ - } \ - else \ - { \ - struct SNAME##_node *curr_node = &(_heap_->buffer[_heap_->size - 1]); \ - \ - /* Decide if the new element goes into the MinHeap or MaxHeap */ \ - if (_heap_->cmp(curr_node->data[0], element) > 0) \ - { \ - /* Swap current value and add new element to the MinHeap */ \ - curr_node->data[1] = curr_node->data[0]; \ - curr_node->data[0] = element; \ - } \ - else \ - { \ - /* No need to swap and add the new element to the MaxHeap */ \ - curr_node->data[1] = element; \ - } \ - } \ - \ - _heap_->count++; \ - \ - if (PFX##_count(_heap_) <= 2) \ - return true; \ - \ - /* Determine wheather to do a MaxHeap insert or a MinHeap insert */ \ - struct SNAME##_node *parent = &(_heap_->buffer[(_heap_->size - 1) / 2]); \ - \ - if (_heap_->cmp(parent->data[0], element) > 0) \ - PFX##_impl_float_up_min(_heap_); \ - else if (_heap_->cmp(parent->data[1], element) < 0) \ - PFX##_impl_float_up_max(_heap_); \ - /* else no float up required */ \ - \ - return true; \ - } \ - \ - bool PFX##_remove_max(struct SNAME *_heap_, V *result) \ - { \ - if (PFX##_empty(_heap_)) \ - return false; \ - \ - if (PFX##_count(_heap_) == 1) \ - { \ - *result = _heap_->buffer[0].data[0]; \ - \ - _heap_->buffer[0].data[0] = (V){0}; \ - \ - _heap_->count--; \ - \ - return true; \ - } \ - else \ - *result = _heap_->buffer[0].data[1]; \ - \ - /* Swap the result with the last element in the MaxHeap and float it down */ \ - struct SNAME##_node *last_node = &(_heap_->buffer[_heap_->size - 1]); \ - \ - if (PFX##_count(_heap_) % 2 == 1) \ - { \ - /* Grab from MinHeap and discard last node */ \ - _heap_->buffer[0].data[1] = last_node->data[0]; \ - \ - last_node->data[0] = (V){0}; \ - \ - _heap_->size--; \ - } \ - else \ - { \ - _heap_->buffer[0].data[1] = last_node->data[1]; \ - \ - last_node->data[1] = (V){0}; \ - } \ - \ - _heap_->count--; \ - \ - /* FLoat Down on the MaxHeap */ \ - PFX##_impl_float_down_max(_heap_); \ - \ - return true; \ - } \ - \ - bool PFX##_remove_min(struct SNAME *_heap_, V *result) \ - { \ - if (PFX##_empty(_heap_)) \ - return false; \ - \ - *result = _heap_->buffer[0].data[0]; \ - \ - if (PFX##_count(_heap_) == 1) \ - { \ - _heap_->buffer[0].data[0] = (V){0}; \ - \ - _heap_->count--; \ - \ - return true; \ - } \ - \ - /* Swap the result with the last element in the MinHeap and float it down */ \ - struct SNAME##_node *last_node = &(_heap_->buffer[_heap_->size - 1]); \ - \ - _heap_->buffer[0].data[0] = last_node->data[0]; \ - \ - if (PFX##_count(_heap_) % 2 == 1) \ - { \ - /* Discard last node */ \ - last_node->data[0] = (V){0}; \ - \ - _heap_->size--; \ - } \ - else \ - { \ - /* Place the MaxHeap value in the MinHeap value spot */ \ - last_node->data[0] = last_node->data[1]; \ - last_node->data[1] = (V){0}; \ - } \ - \ - _heap_->count--; \ - \ - /* FLoat Down on the MinHeap */ \ - PFX##_impl_float_down_min(_heap_); \ - \ - return true; \ - } \ - \ - bool PFX##_update_max(struct SNAME *_heap_, V element) \ - { \ - if (PFX##_empty(_heap_)) \ - return false; \ - \ - if (PFX##_count(_heap_) == 1) \ - { \ - _heap_->buffer[0].data[0] = element; \ - } \ - else if (_heap_->cmp(element, _heap_->buffer[0].data[0]) < 0) \ - { \ - /* Corner case: we are updating the Max value but it is less than */ \ - /* the Min value */ \ - _heap_->buffer[0].data[1] = _heap_->buffer[0].data[0]; \ - _heap_->buffer[0].data[0] = element; \ - \ - PFX##_impl_float_down_max(_heap_); \ - } \ - else \ - { \ - /* Update Max element and float it down */ \ - _heap_->buffer[0].data[1] = element; \ - \ - PFX##_impl_float_down_max(_heap_); \ - } \ - \ - return true; \ - } \ - \ - bool PFX##_update_min(struct SNAME *_heap_, V element) \ - { \ - if (PFX##_empty(_heap_)) \ - return false; \ - \ - if (PFX##_count(_heap_) == 1) \ - { \ - _heap_->buffer[0].data[0] = element; \ - } \ - else if (_heap_->cmp(element, _heap_->buffer[0].data[1]) > 0) \ - { \ - /* Corner case: we are updating the Min value but it is greater */ \ - /* than the Max value. */ \ - _heap_->buffer[0].data[0] = _heap_->buffer[0].data[1]; \ - _heap_->buffer[0].data[1] = element; \ - \ - PFX##_impl_float_down_min(_heap_); \ - } \ - else \ - { \ - /* Update Min element and float it down */ \ - _heap_->buffer[0].data[0] = element; \ - \ - PFX##_impl_float_down_min(_heap_); \ - } \ - \ - return true; \ - } \ - \ - bool PFX##_max(struct SNAME *_heap_, V *value) \ - { \ - if (PFX##_empty(_heap_)) \ - return false; \ - \ - /* If there is only one element, then the maximum element is the same */ \ - /* as the one in the MinHeap */ \ - if (PFX##_count(_heap_) == 1) \ - *value = _heap_->buffer[0].data[0]; \ - else \ - *value = _heap_->buffer[0].data[1]; \ - \ - return true; \ - } \ - \ - bool PFX##_min(struct SNAME *_heap_, V *value) \ - { \ - if (PFX##_empty(_heap_)) \ - return false; \ - \ - *value = _heap_->buffer[0].data[0]; \ - \ - return true; \ - } \ - \ - bool PFX##_contains(struct SNAME *_heap_, V element) \ - { \ - for (size_t i = 0; i < _heap_->count; i++) \ - { \ - if (_heap_->cmp(_heap_->buffer[i / 2].data[i % 2], element) == 0) \ - return true; \ - } \ - \ - return false; \ - } \ - \ - bool PFX##_empty(struct SNAME *_heap_) \ - { \ - return _heap_->count == 0; \ - } \ - \ - bool PFX##_full(struct SNAME *_heap_) \ - { \ - /* The heap is full if all nodes are completely filled */ \ - return _heap_->size >= _heap_->capacity && _heap_->count % 2 == 0; \ - } \ - \ - size_t PFX##_count(struct SNAME *_heap_) \ - { \ - return _heap_->count; \ - } \ - \ - size_t PFX##_capacity(struct SNAME *_heap_) \ - { \ - return _heap_->capacity; \ - } \ - \ - bool PFX##_resize(struct SNAME *_heap_, size_t capacity) \ - { \ - if (PFX##_capacity(_heap_) == capacity) \ - return true; \ - \ - if (capacity < PFX##_count(_heap_)) \ - return false; \ - \ - capacity = capacity % 2 == 0 ? capacity / 2 : (capacity + 1) / 2; \ - \ - struct SNAME##_node *new_buffer = realloc(_heap_->buffer, sizeof(struct SNAME##_node) * capacity); \ - \ - if (!new_buffer) \ - return false; \ - \ - memset(new_buffer + _heap_->capacity, 0, sizeof(struct SNAME##_node) * _heap_->capacity); \ - \ - _heap_->buffer = new_buffer; \ - _heap_->capacity = capacity; \ - \ - return true; \ - } \ - \ - struct SNAME *PFX##_copy_of(struct SNAME *_heap_, V (*copy_func)(V)) \ - { \ - struct SNAME *result = malloc(sizeof(struct SNAME)); \ - \ - if (!result) \ - return NULL; \ - \ - memcpy(result, _heap_, sizeof(struct SNAME)); \ - \ - result->buffer = malloc(sizeof(struct SNAME##_node) * _heap_->capacity); \ - \ - if (!result->buffer) \ - { \ - free(result); \ - return NULL; \ - } \ - \ - if (copy_func) \ - { \ - for (size_t i = 0; i < _heap_->count; i++) \ - result->buffer[i / 2].data[i % 2] = copy_func(_heap_->buffer[i / 2].data[i % 2]); \ - } \ - else \ - memcpy(result->buffer, _heap_->buffer, sizeof(struct SNAME##_node) * _heap_->capacity); \ - \ - return result; \ - } \ - \ - bool PFX##_equals(struct SNAME *_heap1_, struct SNAME *_heap2_) \ - { \ - if (PFX##_count(_heap1_) != PFX##_count(_heap2_)) \ - return false; \ - \ - for (size_t i = 0; i < _heap1_->count; i++) \ - { \ - V element1 = _heap1_->buffer[i / 2].data[i % 2]; \ - V element2 = _heap2_->buffer[i / 2].data[i % 2]; \ - \ - if (_heap1_->cmp(element1, element2) == 0) \ - return true; \ - } \ - \ - return false; \ - } \ - \ - struct cmc_string PFX##_to_string(struct SNAME *_heap_) \ - { \ - struct cmc_string str; \ - struct SNAME *h_ = _heap_; \ - const char *name = #SNAME; \ - \ - snprintf(str.s, cmc_string_len, cmc_string_fmt_intervalheap, \ - name, h_, h_->buffer, h_->capacity, h_->size, h_->count, h_->cmp); \ - \ - return str; \ - } \ - \ - struct SNAME##_iter *PFX##_iter_new(struct SNAME *target) \ - { \ - struct SNAME##_iter *iter = malloc(sizeof(struct SNAME##_iter)); \ - \ - if (!iter) \ - return NULL; \ - \ - PFX##_iter_init(iter, target); \ - \ - return iter; \ - } \ - \ - void PFX##_iter_free(struct SNAME##_iter *iter) \ - { \ - free(iter); \ - } \ - \ - void PFX##_iter_init(struct SNAME##_iter *iter, struct SNAME *target) \ - { \ - iter->target = target; \ - iter->cursor = 0; \ - iter->start = true; \ - iter->end = PFX##_empty(target); \ - } \ - \ - bool PFX##_iter_start(struct SNAME##_iter *iter) \ - { \ - return PFX##_empty(iter->target) || iter->start; \ - } \ - \ - bool PFX##_iter_end(struct SNAME##_iter *iter) \ - { \ - return PFX##_empty(iter->target) || iter->end; \ - } \ - \ - void PFX##_iter_to_start(struct SNAME##_iter *iter) \ - { \ - if (!PFX##_empty(iter->target)) \ - { \ - iter->cursor = 0; \ - iter->start = true; \ - iter->end = PFX##_empty(iter->target); \ - } \ - } \ - \ - void PFX##_iter_to_end(struct SNAME##_iter *iter) \ - { \ - if (!PFX##_empty(iter->target)) \ - { \ - iter->cursor = iter->target->count - 1; \ - iter->start = PFX##_empty(iter->target); \ - iter->end = true; \ - } \ - } \ - \ - bool PFX##_iter_next(struct SNAME##_iter *iter) \ - { \ - if (iter->end) \ - return false; \ - \ - if (iter->cursor + 1 == PFX##_count(iter->target)) \ - { \ - iter->end = true; \ - return false; \ - } \ - \ - iter->start = PFX##_empty(iter->target); \ - \ - iter->cursor++; \ - \ - return true; \ - } \ - \ - bool PFX##_iter_prev(struct SNAME##_iter *iter) \ - { \ - if (iter->start) \ - return false; \ - \ - if (iter->cursor == 0) \ - { \ - iter->start = true; \ - return false; \ - } \ - \ - iter->end = PFX##_empty(iter->target); \ - \ - iter->cursor--; \ - \ - return true; \ - } \ - \ - /* Returns true only if the iterator moved */ \ - bool PFX##_iter_advance(struct SNAME##_iter *iter, size_t steps) \ - { \ - if (iter->start) \ - return false; \ - \ - if (iter->cursor == 0) \ - { \ - iter->start = true; \ - return false; \ - } \ - \ - if (steps == 0 || iter->cursor + steps >= PFX##_count(iter->target)) \ - return false; \ - \ - iter->start = PFX##_empty(iter->target); \ - \ - iter->cursor += steps; \ - \ - return true; \ - } \ - \ - /* Returns true only if the iterator moved */ \ - bool PFX##_iter_rewind(struct SNAME##_iter *iter, size_t steps) \ - { \ - if (iter->start) \ - return false; \ - \ - if (iter->cursor == 0) \ - { \ - iter->start = true; \ - return false; \ - } \ - \ - if (steps == 0 || iter->cursor < steps) \ - return false; \ - \ - iter->end = PFX##_empty(iter->target); \ - \ - iter->cursor -= steps; \ - \ - return true; \ - } \ - \ - /* Returns true only if the iterator was able to be positioned at the given index */ \ - bool PFX##_iter_go_to(struct SNAME##_iter *iter, size_t index) \ - { \ - if (index >= PFX##_count(iter->target)) \ - return false; \ - \ - if (iter->cursor > index) \ - return PFX##_iter_rewind(iter, iter->cursor - index); \ - else if (iter->cursor < index) \ - return PFX##_iter_advance(iter, index - iter->cursor); \ - \ - return true; \ - } \ - \ - V PFX##_iter_value(struct SNAME##_iter *iter) \ - { \ - if (PFX##_empty(iter->target)) \ - return (V){0}; \ - \ - return iter->target->buffer[iter->cursor / 2].data[iter->cursor % 2]; \ - } \ - \ - size_t PFX##_iter_index(struct SNAME##_iter *iter) \ - { \ - return iter->cursor; \ - } \ - \ - static void PFX##_impl_float_up_max(struct SNAME *_heap_) \ - { \ - size_t index = _heap_->size - 1; \ - \ - struct SNAME##_node *curr_node = &(_heap_->buffer[index]); \ - \ - /* FLoat Up on the MaxHeap */ \ - while (index > 0) \ - { \ - /* Parent index */ \ - size_t P_index = (index - 1) / 2; \ - \ - struct SNAME##_node *parent = &(_heap_->buffer[P_index]); \ - \ - if (index == _heap_->size - 1 && PFX##_count(_heap_) % 2 != 0) \ - { \ - /* In this case, the current node has no MaxHeap value so we */ \ - /* instead compare with the MinHeap value */ \ - if (_heap_->cmp(curr_node->data[0], parent->data[1]) < 0) \ - break; \ - \ - /* Since the comparison above passed now we need to swap the */ \ - /* current node with the parent but it will have to be done */ \ - /* with the node's MinHeap value since the MaxHeap value */ \ - /* doesn't exist */ \ - V tmp = curr_node->data[0]; \ - curr_node->data[0] = parent->data[1]; \ - parent->data[1] = tmp; \ - } \ - else \ - { \ - /* Usual case, just compare both MaxHeap values */ \ - if (_heap_->cmp(curr_node->data[1], parent->data[1]) < 0) \ - break; \ - \ - /* Swap with parent and repeat */ \ - V tmp = curr_node->data[1]; \ - curr_node->data[1] = parent->data[1]; \ - parent->data[1] = tmp; \ - } \ - \ - /* Update indexe and node */ \ - index = P_index; \ - curr_node = parent; \ - } \ - } \ - \ - static void PFX##_impl_float_up_min(struct SNAME *_heap_) \ - { \ - size_t index = _heap_->size - 1; \ - \ - struct SNAME##_node *curr_node = &(_heap_->buffer[index]); \ - \ - /* FLoat Up on the MinHeap */ \ - while (index > 0) \ - { \ - /* Parent index */ \ - size_t P_index = (index - 1) / 2; \ - \ - struct SNAME##_node *parent = &(_heap_->buffer[P_index]); \ - \ - if (_heap_->cmp(curr_node->data[0], parent->data[0]) >= 0) \ - break; \ - \ - /* Swap with parent and repeat */ \ - V tmp = curr_node->data[0]; \ - curr_node->data[0] = parent->data[0]; \ - parent->data[0] = tmp; \ - \ - /* Update indexe and node */ \ - index = P_index; \ - curr_node = parent; \ - } \ - } \ - \ - static void PFX##_impl_float_down_max(struct SNAME *_heap_) \ - { \ - /* Floats Down from the MinHeap */ \ - size_t index = 0; \ - \ - struct SNAME##_node *curr_node = &(_heap_->buffer[index]); \ - \ - while (true) \ - { \ - /* If there are no children it is done */ \ - if (2 * index + 1 >= _heap_->size) \ - break; \ - \ - /* Child index to be compared with current value */ \ - size_t child; \ - size_t L_index = index * 2 + 1; \ - size_t R_index = index * 2 + 2; \ - \ - /* If there are two children, pick the smallest one */ \ - if (R_index < _heap_->size) \ - { \ - struct SNAME##_node *L = &(_heap_->buffer[L_index]); \ - struct SNAME##_node *R = &(_heap_->buffer[R_index]); \ - \ - /* If the right child is the last node and there is no MaxHeap value */ \ - /* then do the comparison with the MinHeap value */ \ - if (R_index == _heap_->size - 1 && PFX##_count(_heap_) % 2 != 0) \ - child = _heap_->cmp(L->data[1], R->data[0]) > 0 ? L_index : R_index; \ - else \ - child = _heap_->cmp(L->data[1], R->data[1]) > 0 ? L_index : R_index; \ - } \ - /* Pick the only one available */ \ - else \ - child = L_index; \ - \ - struct SNAME##_node *child_node = &(_heap_->buffer[child]); \ - \ - /* Again, check if the child node is the last one and has no MaxHeap value */ \ - if (child == _heap_->size - 1 && PFX##_count(_heap_) % 2 != 0) \ - { \ - /* Odd case, compare with MinHeap value */ \ - /* If current value is not less than the child node's value, it is done */ \ - if (_heap_->cmp(curr_node->data[1], child_node->data[0]) >= 0) \ - break; \ - \ - /* Otherwise swap and continue */ \ - V tmp = child_node->data[0]; \ - child_node->data[0] = curr_node->data[1]; \ - curr_node->data[1] = tmp; \ - } \ - else \ - { \ - /* If current value is not less than the child node's value, it is done */ \ - if (_heap_->cmp(curr_node->data[1], child_node->data[1]) >= 0) \ - break; \ - \ - /* Otherwise swap and continue */ \ - V tmp = child_node->data[1]; \ - child_node->data[1] = curr_node->data[1]; \ - curr_node->data[1] = tmp; \ - \ - /* Check if the MinHeap and MaxHeap values need to be swapped */ \ - if (_heap_->cmp(child_node->data[0], child_node->data[1]) > 0) \ - { \ - /* Swap because the MinHeap value is greater than the MaxHeap value */ \ - tmp = child_node->data[0]; \ - child_node->data[0] = child_node->data[1]; \ - child_node->data[1] = tmp; \ - } \ - } \ - \ - /* Update index and node */ \ - index = child; \ - curr_node = child_node; \ - } \ - } \ - \ - static void PFX##_impl_float_down_min(struct SNAME *_heap_) \ - { \ - /* Floats Down from the MinHeap */ \ - size_t index = 0; \ - \ - struct SNAME##_node *curr_node = &(_heap_->buffer[index]); \ - \ - while (true) \ - { \ - /* If there are no children it is done */ \ - if (2 * index + 1 >= _heap_->size) \ - break; \ - \ - /* Child index to be compared with current value */ \ - size_t child; \ - size_t L_index = index * 2 + 1; \ - size_t R_index = index * 2 + 2; \ - \ - /* If there are two children, pick the smallest one */ \ - if (R_index < _heap_->size) \ - { \ - struct SNAME##_node *L = &(_heap_->buffer[L_index]); \ - struct SNAME##_node *R = &(_heap_->buffer[R_index]); \ - \ - child = _heap_->cmp(L->data[0], R->data[0]) < 0 ? L_index : R_index; \ - } \ - /* Pick the only one available */ \ - else \ - child = L_index; \ - \ - struct SNAME##_node *child_node = &(_heap_->buffer[child]); \ - \ - /* If current value is smaller than the child node's value, it is done */ \ - if (_heap_->cmp(curr_node->data[0], child_node->data[0]) < 0) \ - break; \ - \ - /* Otherwise swap and continue */ \ - V tmp = child_node->data[0]; \ - child_node->data[0] = curr_node->data[0]; \ - curr_node->data[0] = tmp; \ - \ - /* If the child node is the last node check if the MinHeap and */ \ - /* MaxHeap values need to be swapped */ \ - if (child != _heap_->size - 1 || PFX##_count(_heap_) % 2 == 0) \ - { \ - if (_heap_->cmp(child_node->data[0], child_node->data[1]) > 0) \ - { \ - /* Swap because the MinHeap value is greater than the MaxHeap value */ \ - tmp = child_node->data[0]; \ - child_node->data[0] = child_node->data[1]; \ - child_node->data[1] = tmp; \ - } \ - } \ - \ - /* Update index and node */ \ - index = child; \ - curr_node = child_node; \ - } \ - } \ - \ - static struct SNAME##_iter PFX##_impl_it_start(struct SNAME *_heap_) \ - { \ - struct SNAME##_iter iter; \ - \ - PFX##_iter_init(&iter, _heap_); \ - PFX##_iter_to_start(&iter); \ - \ - return iter; \ - } \ - \ - static struct SNAME##_iter PFX##_impl_it_end(struct SNAME *_heap_) \ - { \ - struct SNAME##_iter iter; \ - \ - PFX##_iter_init(&iter, _heap_); \ - PFX##_iter_to_end(&iter); \ - \ - return iter; \ +/* ------------------------------------------------------------------------------------------------- + * Header + ------------------------------------------------------------------------------------------------ */ +#define CMC_GENERATE_INTERVALHEAP_HEADER(PFX, SNAME, V) \ + \ + /* Heap Structure */ \ + struct SNAME \ + { \ + /* Dynamic array of nodes */ \ + struct SNAME##_node *buffer; \ + \ + /* Current array capacity (how many nodes can be stored) */ \ + size_t capacity; \ + \ + /* Current amount of nodes in the dynamic array */ \ + size_t size; \ + \ + /* Current amount of elements in the heap */ \ + size_t count; \ + \ + /* Element comparison function */ \ + int (*cmp)(V, V); \ + \ + /* Function that returns an iterator to the start of the heap */ \ + struct SNAME##_iter (*it_start)(struct SNAME *); \ + \ + /* Function that returns an iterator to the end of the heap */ \ + struct SNAME##_iter (*it_end)(struct SNAME *); \ + \ + /* Custom allocation functions */ \ + struct cmc_alloc_node *alloc; \ + \ + /* Custom callback functions */ \ + struct cmc_callbacks_intervalheap *callbacks; \ + }; \ + \ + /* Heap Node */ \ + struct SNAME##_node \ + { \ + /* 0 - Value belonging to the MinHeap */ \ + /* 1 - Value belonging to the MaxHeap */ \ + V data[2]; \ + }; \ + \ + /* Heap Iterator */ \ + struct SNAME##_iter \ + { \ + /* Target heap */ \ + struct SNAME *target; \ + \ + /* Cursor's position (index) */ \ + size_t cursor; \ + \ + /* If the iterator has reached the start of the iteration */ \ + bool start; \ + \ + /* If the iterator has reached the end of the iteration */ \ + bool end; \ + }; \ + \ + /* Collection Functions */ \ + /* Collection Allocation and Deallocation */ \ + struct SNAME *PFX##_new(size_t capacity, int (*compare)(V, V)); \ + struct SNAME *PFX##_new_custom(size_t capacity, int (*compare)(V, V), \ + struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_intervalheap *callbacks); \ + void PFX##_clear(struct SNAME *_heap_, void (*deallocator)(V)); \ + void PFX##_free(struct SNAME *_heap_, void (*deallocator)(V)); \ + /* Customization of Allocation and Callbacks */ \ + void PFX##_customize(struct SNAME *_heap_, struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_intervalheap *callbacks); \ + /* Collection Input and Output */ \ + bool PFX##_insert(struct SNAME *_heap_, V element); \ + bool PFX##_remove_max(struct SNAME *_heap_, V *result); \ + bool PFX##_remove_min(struct SNAME *_heap_, V *result); \ + /* Collection Update */ \ + bool PFX##_update_max(struct SNAME *_heap_, V element); \ + bool PFX##_update_min(struct SNAME *_heap_, V element); \ + /* Element Access */ \ + bool PFX##_max(struct SNAME *_heap_, V *value); \ + bool PFX##_min(struct SNAME *_heap_, V *value); \ + /* Collection State */ \ + bool PFX##_contains(struct SNAME *_heap_, V element); \ + bool PFX##_empty(struct SNAME *_heap_); \ + bool PFX##_full(struct SNAME *_heap_); \ + size_t PFX##_count(struct SNAME *_heap_); \ + size_t PFX##_capacity(struct SNAME *_heap_); \ + /* Collection Utility */ \ + bool PFX##_resize(struct SNAME *_heap_, size_t capacity); \ + struct SNAME *PFX##_copy_of(struct SNAME *_set_, V (*copy_func)(V)); \ + bool PFX##_equals(struct SNAME *_heap1_, struct SNAME *_heap2_); \ + struct cmc_string PFX##_to_string(struct SNAME *_heap_); \ + \ + /* Iterator Functions */ \ + /* Iterator Allocation and Deallocation */ \ + struct SNAME##_iter *PFX##_iter_new(struct SNAME *target); \ + void PFX##_iter_free(struct SNAME##_iter *iter); \ + /* Iterator Initialization */ \ + void PFX##_iter_init(struct SNAME##_iter *iter, struct SNAME *target); \ + /* Iterator State */ \ + bool PFX##_iter_start(struct SNAME##_iter *iter); \ + bool PFX##_iter_end(struct SNAME##_iter *iter); \ + /* Iterator Movement */ \ + void PFX##_iter_to_start(struct SNAME##_iter *iter); \ + void PFX##_iter_to_end(struct SNAME##_iter *iter); \ + bool PFX##_iter_next(struct SNAME##_iter *iter); \ + bool PFX##_iter_prev(struct SNAME##_iter *iter); \ + bool PFX##_iter_advance(struct SNAME##_iter *iter, size_t steps); \ + bool PFX##_iter_rewind(struct SNAME##_iter *iter, size_t steps); \ + bool PFX##_iter_go_to(struct SNAME##_iter *iter, size_t index); \ + /* Iterator Access */ \ + V PFX##_iter_value(struct SNAME##_iter *iter); \ + size_t PFX##_iter_index(struct SNAME##_iter *iter); + +/* ------------------------------------------------------------------------------------------------- + * Source + ------------------------------------------------------------------------------------------------ */ +#define CMC_GENERATE_INTERVALHEAP_SOURCE(PFX, SNAME, V) \ + \ + /* Implementation Detail Functions */ \ + static void PFX##_impl_float_up_max(struct SNAME *_heap_); \ + static void PFX##_impl_float_up_min(struct SNAME *_heap_); \ + static void PFX##_impl_float_down_max(struct SNAME *_heap_); \ + static void PFX##_impl_float_down_min(struct SNAME *_heap_); \ + static struct SNAME##_iter PFX##_impl_it_start(struct SNAME *_heap_); \ + static struct SNAME##_iter PFX##_impl_it_end(struct SNAME *_heap_); \ + \ + struct SNAME *PFX##_new(size_t capacity, int (*compare)(V, V)) \ + { \ + struct cmc_alloc_node *alloc = &cmc_alloc_node_default; \ + \ + if (capacity == 0 || capacity == UINT64_MAX) \ + return NULL; \ + \ + struct SNAME *_heap_ = alloc->malloc(sizeof(struct SNAME)); \ + \ + if (!_heap_) \ + return NULL; \ + \ + /* Since each node can store two elements, divide the actual capacity by 2 */ \ + /* Round the capacity of nodes up */ \ + capacity = capacity % 2 == 0 ? capacity / 2 : (capacity + 1) / 2; \ + \ + _heap_->buffer = alloc->calloc(capacity, sizeof(struct SNAME##_node)); \ + \ + if (!_heap_->buffer) \ + { \ + alloc->free(_heap_); \ + return NULL; \ + } \ + \ + _heap_->capacity = capacity; \ + _heap_->size = 0; \ + _heap_->count = 0; \ + _heap_->cmp = compare; \ + \ + _heap_->it_start = PFX##_impl_it_start; \ + _heap_->it_end = PFX##_impl_it_end; \ + \ + _heap_->alloc = alloc; \ + _heap_->callbacks = NULL; \ + \ + return _heap_; \ + } \ + \ + struct SNAME *PFX##_new_custom(size_t capacity, int (*compare)(V, V), \ + struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_intervalheap *callbacks) \ + { \ + if (capacity == 0 || capacity == UINT64_MAX) \ + return NULL; \ + \ + if (!alloc) \ + alloc = &cmc_alloc_node_default; \ + \ + struct SNAME *_heap_ = alloc->malloc(sizeof(struct SNAME)); \ + \ + if (!_heap_) \ + return NULL; \ + \ + /* Since each node can store two elements, divide the actual capacity by 2 */ \ + /* Round the capacity of nodes up */ \ + capacity = capacity % 2 == 0 ? capacity / 2 : (capacity + 1) / 2; \ + \ + _heap_->buffer = alloc->calloc(capacity, sizeof(struct SNAME##_node)); \ + \ + if (!_heap_->buffer) \ + { \ + alloc->free(_heap_); \ + return NULL; \ + } \ + \ + _heap_->capacity = capacity; \ + _heap_->size = 0; \ + _heap_->count = 0; \ + _heap_->cmp = compare; \ + \ + _heap_->it_start = PFX##_impl_it_start; \ + _heap_->it_end = PFX##_impl_it_end; \ + \ + _heap_->alloc = alloc; \ + _heap_->callbacks = callbacks; \ + \ + return _heap_; \ + } \ + \ + void PFX##_clear(struct SNAME *_heap_, void (*deallocator)(V)) \ + { \ + if (deallocator) \ + { \ + for (size_t i = 0; i < _heap_->count; i++) \ + { \ + deallocator(_heap_->buffer[i / 2].data[i % 2]); \ + } \ + } \ + \ + memset(_heap_->buffer, 0, sizeof(V) * _heap_->capacity); \ + \ + _heap_->size = 0; \ + _heap_->count = 0; \ + } \ + \ + void PFX##_free(struct SNAME *_heap_, void (*deallocator)(V)) \ + { \ + if (deallocator) \ + { \ + for (size_t i = 0; i < _heap_->count; i++) \ + { \ + deallocator(_heap_->buffer[i / 2].data[i % 2]); \ + } \ + } \ + \ + _heap_->alloc->free(_heap_->buffer); \ + \ + _heap_->alloc->free(_heap_); \ + } \ + \ + void PFX##_customize(struct SNAME *_heap_, struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_intervalheap *callbacks) \ + { \ + if (alloc) \ + _heap_->alloc = alloc; \ + \ + if (callbacks) \ + _heap_->callbacks = callbacks; \ + } \ + \ + bool PFX##_insert(struct SNAME *_heap_, V element) \ + { \ + if (PFX##_full(_heap_)) \ + { \ + if (!PFX##_resize(_heap_, PFX##_capacity(_heap_) * 4)) \ + return false; \ + } \ + \ + if (PFX##_count(_heap_) % 2 == 0) \ + { \ + /* Occupying a new node */ \ + _heap_->buffer[_heap_->size].data[0] = element; \ + _heap_->buffer[_heap_->size].data[1] = (V){0}; \ + \ + _heap_->size++; \ + } \ + else \ + { \ + struct SNAME##_node *curr_node = &(_heap_->buffer[_heap_->size - 1]); \ + \ + /* Decide if the new element goes into the MinHeap or MaxHeap */ \ + if (_heap_->cmp(curr_node->data[0], element) > 0) \ + { \ + /* Swap current value and add new element to the MinHeap */ \ + curr_node->data[1] = curr_node->data[0]; \ + curr_node->data[0] = element; \ + } \ + else \ + { \ + /* No need to swap and add the new element to the MaxHeap */ \ + curr_node->data[1] = element; \ + } \ + } \ + \ + _heap_->count++; \ + \ + if (PFX##_count(_heap_) <= 2) \ + return true; \ + \ + /* Determine wheather to do a MaxHeap insert or a MinHeap insert */ \ + struct SNAME##_node *parent = &(_heap_->buffer[(_heap_->size - 1) / 2]); \ + \ + if (_heap_->cmp(parent->data[0], element) > 0) \ + PFX##_impl_float_up_min(_heap_); \ + else if (_heap_->cmp(parent->data[1], element) < 0) \ + PFX##_impl_float_up_max(_heap_); \ + /* else no float up required */ \ + \ + return true; \ + } \ + \ + bool PFX##_remove_max(struct SNAME *_heap_, V *result) \ + { \ + if (PFX##_empty(_heap_)) \ + return false; \ + \ + if (PFX##_count(_heap_) == 1) \ + { \ + *result = _heap_->buffer[0].data[0]; \ + \ + _heap_->buffer[0].data[0] = (V){0}; \ + \ + _heap_->count--; \ + \ + return true; \ + } \ + else \ + *result = _heap_->buffer[0].data[1]; \ + \ + /* Swap the result with the last element in the MaxHeap and float it down */ \ + struct SNAME##_node *last_node = &(_heap_->buffer[_heap_->size - 1]); \ + \ + if (PFX##_count(_heap_) % 2 == 1) \ + { \ + /* Grab from MinHeap and discard last node */ \ + _heap_->buffer[0].data[1] = last_node->data[0]; \ + \ + last_node->data[0] = (V){0}; \ + \ + _heap_->size--; \ + } \ + else \ + { \ + _heap_->buffer[0].data[1] = last_node->data[1]; \ + \ + last_node->data[1] = (V){0}; \ + } \ + \ + _heap_->count--; \ + \ + /* FLoat Down on the MaxHeap */ \ + PFX##_impl_float_down_max(_heap_); \ + \ + return true; \ + } \ + \ + bool PFX##_remove_min(struct SNAME *_heap_, V *result) \ + { \ + if (PFX##_empty(_heap_)) \ + return false; \ + \ + *result = _heap_->buffer[0].data[0]; \ + \ + if (PFX##_count(_heap_) == 1) \ + { \ + _heap_->buffer[0].data[0] = (V){0}; \ + \ + _heap_->count--; \ + \ + return true; \ + } \ + \ + /* Swap the result with the last element in the MinHeap and float it down */ \ + struct SNAME##_node *last_node = &(_heap_->buffer[_heap_->size - 1]); \ + \ + _heap_->buffer[0].data[0] = last_node->data[0]; \ + \ + if (PFX##_count(_heap_) % 2 == 1) \ + { \ + /* Discard last node */ \ + last_node->data[0] = (V){0}; \ + \ + _heap_->size--; \ + } \ + else \ + { \ + /* Place the MaxHeap value in the MinHeap value spot */ \ + last_node->data[0] = last_node->data[1]; \ + last_node->data[1] = (V){0}; \ + } \ + \ + _heap_->count--; \ + \ + /* FLoat Down on the MinHeap */ \ + PFX##_impl_float_down_min(_heap_); \ + \ + return true; \ + } \ + \ + bool PFX##_update_max(struct SNAME *_heap_, V element) \ + { \ + if (PFX##_empty(_heap_)) \ + return false; \ + \ + if (PFX##_count(_heap_) == 1) \ + { \ + _heap_->buffer[0].data[0] = element; \ + } \ + else if (_heap_->cmp(element, _heap_->buffer[0].data[0]) < 0) \ + { \ + /* Corner case: we are updating the Max value but it is less than */ \ + /* the Min value */ \ + _heap_->buffer[0].data[1] = _heap_->buffer[0].data[0]; \ + _heap_->buffer[0].data[0] = element; \ + \ + PFX##_impl_float_down_max(_heap_); \ + } \ + else \ + { \ + /* Update Max element and float it down */ \ + _heap_->buffer[0].data[1] = element; \ + \ + PFX##_impl_float_down_max(_heap_); \ + } \ + \ + return true; \ + } \ + \ + bool PFX##_update_min(struct SNAME *_heap_, V element) \ + { \ + if (PFX##_empty(_heap_)) \ + return false; \ + \ + if (PFX##_count(_heap_) == 1) \ + { \ + _heap_->buffer[0].data[0] = element; \ + } \ + else if (_heap_->cmp(element, _heap_->buffer[0].data[1]) > 0) \ + { \ + /* Corner case: we are updating the Min value but it is greater */ \ + /* than the Max value. */ \ + _heap_->buffer[0].data[0] = _heap_->buffer[0].data[1]; \ + _heap_->buffer[0].data[1] = element; \ + \ + PFX##_impl_float_down_min(_heap_); \ + } \ + else \ + { \ + /* Update Min element and float it down */ \ + _heap_->buffer[0].data[0] = element; \ + \ + PFX##_impl_float_down_min(_heap_); \ + } \ + \ + return true; \ + } \ + \ + bool PFX##_max(struct SNAME *_heap_, V *value) \ + { \ + if (PFX##_empty(_heap_)) \ + return false; \ + \ + /* If there is only one element, then the maximum element is the same */ \ + /* as the one in the MinHeap */ \ + if (PFX##_count(_heap_) == 1) \ + *value = _heap_->buffer[0].data[0]; \ + else \ + *value = _heap_->buffer[0].data[1]; \ + \ + return true; \ + } \ + \ + bool PFX##_min(struct SNAME *_heap_, V *value) \ + { \ + if (PFX##_empty(_heap_)) \ + return false; \ + \ + *value = _heap_->buffer[0].data[0]; \ + \ + return true; \ + } \ + \ + bool PFX##_contains(struct SNAME *_heap_, V element) \ + { \ + for (size_t i = 0; i < _heap_->count; i++) \ + { \ + if (_heap_->cmp(_heap_->buffer[i / 2].data[i % 2], element) == 0) \ + return true; \ + } \ + \ + return false; \ + } \ + \ + bool PFX##_empty(struct SNAME *_heap_) \ + { \ + return _heap_->count == 0; \ + } \ + \ + bool PFX##_full(struct SNAME *_heap_) \ + { \ + /* The heap is full if all nodes are completely filled */ \ + return _heap_->size >= _heap_->capacity && _heap_->count % 2 == 0; \ + } \ + \ + size_t PFX##_count(struct SNAME *_heap_) \ + { \ + return _heap_->count; \ + } \ + \ + size_t PFX##_capacity(struct SNAME *_heap_) \ + { \ + return _heap_->capacity; \ + } \ + \ + bool PFX##_resize(struct SNAME *_heap_, size_t capacity) \ + { \ + if (PFX##_capacity(_heap_) == capacity) \ + return true; \ + \ + if (capacity < PFX##_count(_heap_)) \ + return false; \ + \ + capacity = capacity % 2 == 0 ? capacity / 2 : (capacity + 1) / 2; \ + \ + struct SNAME##_node *new_buffer = _heap_->alloc->realloc( \ + _heap_->buffer, sizeof(struct SNAME##_node) * capacity); \ + \ + if (!new_buffer) \ + return false; \ + \ + memset(new_buffer + _heap_->capacity, 0, sizeof(struct SNAME##_node) * _heap_->capacity); \ + \ + _heap_->buffer = new_buffer; \ + _heap_->capacity = capacity; \ + \ + return true; \ + } \ + \ + struct SNAME *PFX##_copy_of(struct SNAME *_heap_, V (*copy_func)(V)) \ + { \ + struct SNAME *result = _heap_->alloc->malloc(sizeof(struct SNAME)); \ + \ + if (!result) \ + return NULL; \ + \ + memcpy(result, _heap_, sizeof(struct SNAME)); \ + \ + result->buffer = _heap_->alloc->malloc(sizeof(struct SNAME##_node) * _heap_->capacity); \ + \ + if (!result->buffer) \ + { \ + _heap_->alloc->free(result); \ + return NULL; \ + } \ + \ + if (copy_func) \ + { \ + for (size_t i = 0; i < _heap_->count; i++) \ + result->buffer[i / 2].data[i % 2] = copy_func(_heap_->buffer[i / 2].data[i % 2]); \ + } \ + else \ + memcpy(result->buffer, _heap_->buffer, \ + sizeof(struct SNAME##_node) * _heap_->capacity); \ + \ + result->alloc = _heap_->alloc; \ + result->callbacks = _heap_->callbacks; \ + \ + return result; \ + } \ + \ + bool PFX##_equals(struct SNAME *_heap1_, struct SNAME *_heap2_) \ + { \ + if (PFX##_count(_heap1_) != PFX##_count(_heap2_)) \ + return false; \ + \ + for (size_t i = 0; i < _heap1_->count; i++) \ + { \ + V element1 = _heap1_->buffer[i / 2].data[i % 2]; \ + V element2 = _heap2_->buffer[i / 2].data[i % 2]; \ + \ + if (_heap1_->cmp(element1, element2) == 0) \ + return true; \ + } \ + \ + return false; \ + } \ + \ + struct cmc_string PFX##_to_string(struct SNAME *_heap_) \ + { \ + struct cmc_string str; \ + struct SNAME *h_ = _heap_; \ + \ + int n = snprintf(str.s, cmc_string_len, cmc_string_fmt_intervalheap, \ + #SNAME, #V, h_, h_->buffer, h_->capacity, h_->size, \ + h_->count, h_->cmp, h_->alloc, h_->callbacks); \ + \ + if (n < 0 || n == (int)cmc_string_len) \ + return (struct cmc_string){0}; \ + \ + str.s[n] = '\0'; \ + \ + return str; \ + } \ + \ + struct SNAME##_iter *PFX##_iter_new(struct SNAME *target) \ + { \ + struct SNAME##_iter *iter = target->alloc->malloc(sizeof(struct SNAME##_iter)); \ + \ + if (!iter) \ + return NULL; \ + \ + PFX##_iter_init(iter, target); \ + \ + return iter; \ + } \ + \ + void PFX##_iter_free(struct SNAME##_iter *iter) \ + { \ + iter->target->alloc->free(iter); \ + } \ + \ + void PFX##_iter_init(struct SNAME##_iter *iter, struct SNAME *target) \ + { \ + iter->target = target; \ + iter->cursor = 0; \ + iter->start = true; \ + iter->end = PFX##_empty(target); \ + } \ + \ + bool PFX##_iter_start(struct SNAME##_iter *iter) \ + { \ + return PFX##_empty(iter->target) || iter->start; \ + } \ + \ + bool PFX##_iter_end(struct SNAME##_iter *iter) \ + { \ + return PFX##_empty(iter->target) || iter->end; \ + } \ + \ + void PFX##_iter_to_start(struct SNAME##_iter *iter) \ + { \ + if (!PFX##_empty(iter->target)) \ + { \ + iter->cursor = 0; \ + iter->start = true; \ + iter->end = PFX##_empty(iter->target); \ + } \ + } \ + \ + void PFX##_iter_to_end(struct SNAME##_iter *iter) \ + { \ + if (!PFX##_empty(iter->target)) \ + { \ + iter->cursor = iter->target->count - 1; \ + iter->start = PFX##_empty(iter->target); \ + iter->end = true; \ + } \ + } \ + \ + bool PFX##_iter_next(struct SNAME##_iter *iter) \ + { \ + if (iter->end) \ + return false; \ + \ + if (iter->cursor + 1 == PFX##_count(iter->target)) \ + { \ + iter->end = true; \ + return false; \ + } \ + \ + iter->start = PFX##_empty(iter->target); \ + \ + iter->cursor++; \ + \ + return true; \ + } \ + \ + bool PFX##_iter_prev(struct SNAME##_iter *iter) \ + { \ + if (iter->start) \ + return false; \ + \ + if (iter->cursor == 0) \ + { \ + iter->start = true; \ + return false; \ + } \ + \ + iter->end = PFX##_empty(iter->target); \ + \ + iter->cursor--; \ + \ + return true; \ + } \ + \ + /* Returns true only if the iterator moved */ \ + bool PFX##_iter_advance(struct SNAME##_iter *iter, size_t steps) \ + { \ + if (iter->start) \ + return false; \ + \ + if (iter->cursor == 0) \ + { \ + iter->start = true; \ + return false; \ + } \ + \ + if (steps == 0 || iter->cursor + steps >= PFX##_count(iter->target)) \ + return false; \ + \ + iter->start = PFX##_empty(iter->target); \ + \ + iter->cursor += steps; \ + \ + return true; \ + } \ + \ + /* Returns true only if the iterator moved */ \ + bool PFX##_iter_rewind(struct SNAME##_iter *iter, size_t steps) \ + { \ + if (iter->start) \ + return false; \ + \ + if (iter->cursor == 0) \ + { \ + iter->start = true; \ + return false; \ + } \ + \ + if (steps == 0 || iter->cursor < steps) \ + return false; \ + \ + iter->end = PFX##_empty(iter->target); \ + \ + iter->cursor -= steps; \ + \ + return true; \ + } \ + \ + /* Returns true only if the iterator was able to be positioned at the given index */ \ + bool PFX##_iter_go_to(struct SNAME##_iter *iter, size_t index) \ + { \ + if (index >= PFX##_count(iter->target)) \ + return false; \ + \ + if (iter->cursor > index) \ + return PFX##_iter_rewind(iter, iter->cursor - index); \ + else if (iter->cursor < index) \ + return PFX##_iter_advance(iter, index - iter->cursor); \ + \ + return true; \ + } \ + \ + V PFX##_iter_value(struct SNAME##_iter *iter) \ + { \ + if (PFX##_empty(iter->target)) \ + return (V){0}; \ + \ + return iter->target->buffer[iter->cursor / 2].data[iter->cursor % 2]; \ + } \ + \ + size_t PFX##_iter_index(struct SNAME##_iter *iter) \ + { \ + return iter->cursor; \ + } \ + \ + static void PFX##_impl_float_up_max(struct SNAME *_heap_) \ + { \ + size_t index = _heap_->size - 1; \ + \ + struct SNAME##_node *curr_node = &(_heap_->buffer[index]); \ + \ + /* FLoat Up on the MaxHeap */ \ + while (index > 0) \ + { \ + /* Parent index */ \ + size_t P_index = (index - 1) / 2; \ + \ + struct SNAME##_node *parent = &(_heap_->buffer[P_index]); \ + \ + if (index == _heap_->size - 1 && PFX##_count(_heap_) % 2 != 0) \ + { \ + /* In this case, the current node has no MaxHeap value so we */ \ + /* instead compare with the MinHeap value */ \ + if (_heap_->cmp(curr_node->data[0], parent->data[1]) < 0) \ + break; \ + \ + /* Since the comparison above passed now we need to swap the */ \ + /* current node with the parent but it will have to be done */ \ + /* with the node's MinHeap value since the MaxHeap value */ \ + /* doesn't exist */ \ + V tmp = curr_node->data[0]; \ + curr_node->data[0] = parent->data[1]; \ + parent->data[1] = tmp; \ + } \ + else \ + { \ + /* Usual case, just compare both MaxHeap values */ \ + if (_heap_->cmp(curr_node->data[1], parent->data[1]) < 0) \ + break; \ + \ + /* Swap with parent and repeat */ \ + V tmp = curr_node->data[1]; \ + curr_node->data[1] = parent->data[1]; \ + parent->data[1] = tmp; \ + } \ + \ + /* Update indexe and node */ \ + index = P_index; \ + curr_node = parent; \ + } \ + } \ + \ + static void PFX##_impl_float_up_min(struct SNAME *_heap_) \ + { \ + size_t index = _heap_->size - 1; \ + \ + struct SNAME##_node *curr_node = &(_heap_->buffer[index]); \ + \ + /* FLoat Up on the MinHeap */ \ + while (index > 0) \ + { \ + /* Parent index */ \ + size_t P_index = (index - 1) / 2; \ + \ + struct SNAME##_node *parent = &(_heap_->buffer[P_index]); \ + \ + if (_heap_->cmp(curr_node->data[0], parent->data[0]) >= 0) \ + break; \ + \ + /* Swap with parent and repeat */ \ + V tmp = curr_node->data[0]; \ + curr_node->data[0] = parent->data[0]; \ + parent->data[0] = tmp; \ + \ + /* Update indexe and node */ \ + index = P_index; \ + curr_node = parent; \ + } \ + } \ + \ + static void PFX##_impl_float_down_max(struct SNAME *_heap_) \ + { \ + /* Floats Down from the MinHeap */ \ + size_t index = 0; \ + \ + struct SNAME##_node *curr_node = &(_heap_->buffer[index]); \ + \ + while (true) \ + { \ + /* If there are no children it is done */ \ + if (2 * index + 1 >= _heap_->size) \ + break; \ + \ + /* Child index to be compared with current value */ \ + size_t child; \ + size_t L_index = index * 2 + 1; \ + size_t R_index = index * 2 + 2; \ + \ + /* If there are two children, pick the smallest one */ \ + if (R_index < _heap_->size) \ + { \ + struct SNAME##_node *L = &(_heap_->buffer[L_index]); \ + struct SNAME##_node *R = &(_heap_->buffer[R_index]); \ + \ + /* If the right child is the last node and there is no MaxHeap value */ \ + /* then do the comparison with the MinHeap value */ \ + if (R_index == _heap_->size - 1 && PFX##_count(_heap_) % 2 != 0) \ + child = _heap_->cmp(L->data[1], R->data[0]) > 0 ? L_index : R_index; \ + else \ + child = _heap_->cmp(L->data[1], R->data[1]) > 0 ? L_index : R_index; \ + } \ + /* Pick the only one available */ \ + else \ + child = L_index; \ + \ + struct SNAME##_node *child_node = &(_heap_->buffer[child]); \ + \ + /* Again, check if the child node is the last one and has no MaxHeap value */ \ + if (child == _heap_->size - 1 && PFX##_count(_heap_) % 2 != 0) \ + { \ + /* Odd case, compare with MinHeap value */ \ + /* If current value is not less than the child node's value, it is done */ \ + if (_heap_->cmp(curr_node->data[1], child_node->data[0]) >= 0) \ + break; \ + \ + /* Otherwise swap and continue */ \ + V tmp = child_node->data[0]; \ + child_node->data[0] = curr_node->data[1]; \ + curr_node->data[1] = tmp; \ + } \ + else \ + { \ + /* If current value is not less than the child node's value, it is done */ \ + if (_heap_->cmp(curr_node->data[1], child_node->data[1]) >= 0) \ + break; \ + \ + /* Otherwise swap and continue */ \ + V tmp = child_node->data[1]; \ + child_node->data[1] = curr_node->data[1]; \ + curr_node->data[1] = tmp; \ + \ + /* Check if the MinHeap and MaxHeap values need to be swapped */ \ + if (_heap_->cmp(child_node->data[0], child_node->data[1]) > 0) \ + { \ + /* Swap because the MinHeap value is greater than the MaxHeap value */ \ + tmp = child_node->data[0]; \ + child_node->data[0] = child_node->data[1]; \ + child_node->data[1] = tmp; \ + } \ + } \ + \ + /* Update index and node */ \ + index = child; \ + curr_node = child_node; \ + } \ + } \ + \ + static void PFX##_impl_float_down_min(struct SNAME *_heap_) \ + { \ + /* Floats Down from the MinHeap */ \ + size_t index = 0; \ + \ + struct SNAME##_node *curr_node = &(_heap_->buffer[index]); \ + \ + while (true) \ + { \ + /* If there are no children it is done */ \ + if (2 * index + 1 >= _heap_->size) \ + break; \ + \ + /* Child index to be compared with current value */ \ + size_t child; \ + size_t L_index = index * 2 + 1; \ + size_t R_index = index * 2 + 2; \ + \ + /* If there are two children, pick the smallest one */ \ + if (R_index < _heap_->size) \ + { \ + struct SNAME##_node *L = &(_heap_->buffer[L_index]); \ + struct SNAME##_node *R = &(_heap_->buffer[R_index]); \ + \ + child = _heap_->cmp(L->data[0], R->data[0]) < 0 ? L_index : R_index; \ + } \ + /* Pick the only one available */ \ + else \ + child = L_index; \ + \ + struct SNAME##_node *child_node = &(_heap_->buffer[child]); \ + \ + /* If current value is smaller than the child node's value, it is done */ \ + if (_heap_->cmp(curr_node->data[0], child_node->data[0]) < 0) \ + break; \ + \ + /* Otherwise swap and continue */ \ + V tmp = child_node->data[0]; \ + child_node->data[0] = curr_node->data[0]; \ + curr_node->data[0] = tmp; \ + \ + /* If the child node is the last node check if the MinHeap and */ \ + /* MaxHeap values need to be swapped */ \ + if (child != _heap_->size - 1 || PFX##_count(_heap_) % 2 == 0) \ + { \ + if (_heap_->cmp(child_node->data[0], child_node->data[1]) > 0) \ + { \ + /* Swap because the MinHeap value is greater than the MaxHeap value */ \ + tmp = child_node->data[0]; \ + child_node->data[0] = child_node->data[1]; \ + child_node->data[1] = tmp; \ + } \ + } \ + \ + /* Update index and node */ \ + index = child; \ + curr_node = child_node; \ + } \ + } \ + \ + static struct SNAME##_iter PFX##_impl_it_start(struct SNAME *_heap_) \ + { \ + struct SNAME##_iter iter; \ + \ + PFX##_iter_init(&iter, _heap_); \ + PFX##_iter_to_start(&iter); \ + \ + return iter; \ + } \ + \ + static struct SNAME##_iter PFX##_impl_it_end(struct SNAME *_heap_) \ + { \ + struct SNAME##_iter iter; \ + \ + PFX##_iter_init(&iter, _heap_); \ + PFX##_iter_to_end(&iter); \ + \ + return iter; \ } #endif /* CMC_INTERVALHEAP_H */ diff --git a/src/cmc/linkedlist.h b/src/cmc/linkedlist.h index c9c417f..f03b26b 100644 --- a/src/cmc/linkedlist.h +++ b/src/cmc/linkedlist.h @@ -33,10 +33,66 @@ #include #include #include -#include "../utl/cmc_string.h" +/* ------------------------------------------------------------------------------------------------- + * Core functionalities of the C Macro Collections Library + ------------------------------------------------------------------------------------------------ */ +#ifndef CMC_CORE_H +#define CMC_CORE_H + +/** + * struct cmc_string + * + * Used by all collections when calling the to_string function. + */ +struct cmc_string +{ + char s[400]; +}; + +static const size_t cmc_string_len = 400; + +/** + * struct cmc_alloc_node + * + * Custom allocation node. Allows collections to use custom allocation functions. + */ +struct cmc_alloc_node +{ + void *(*malloc)(size_t); + void *(*calloc)(size_t, size_t); + void *(*realloc)(void *, size_t); + void (*free)(void *); +} cmc_alloc_node_default = {malloc, calloc, realloc, free}; + +#endif /* CMC_CORE_H */ + +/* ------------------------------------------------------------------------------------------------- + * LinkedList specific + ------------------------------------------------------------------------------------------------ */ /* to_string format */ -static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", head:%p, tail:%p }"; +static const char *cmc_string_fmt_linkedlist = "struct %s<%s> " + "at %p { " + "count:%" PRIuMAX ", " + "head:%p, " + "tail:%p, " + "alloc:%p, " + "callbacks:%p }"; + +/** + * Custom LinkedList callbacks. + * + * There are two types of callbacks, 'before' and 'after': + * _ + */ +struct cmc_callbacks_linkedlist +{ + void (*before_clear)(void *); + void (*after_clear)(void *); + void (*before_free)(void *); + void (*after_free)(void *); + // TODO implement all callbacks +}; #define CMC_GENERATE_LINKEDLIST(PFX, SNAME, V) \ CMC_GENERATE_LINKEDLIST_HEADER(PFX, SNAME, V) \ @@ -48,7 +104,9 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h #define CMC_WRAPGEN_LINKEDLIST_SOURCE(PFX, SNAME, K, V) \ CMC_GENERATE_LINKEDLIST_SOURCE(PFX, SNAME, V) -/* HEADER ********************************************************************/ +/* ------------------------------------------------------------------------------------------------- + * Header + ------------------------------------------------------------------------------------------------ */ #define CMC_GENERATE_LINKEDLIST_HEADER(PFX, SNAME, V) \ \ /* Linked List Structure */ \ @@ -68,6 +126,12 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h \ /* Function that returns an iterator to the end of the list */ \ struct SNAME##_iter (*it_end)(struct SNAME *); \ + \ + /* Custom allocation functions */ \ + struct cmc_alloc_node *alloc; \ + \ + /* Custom callback functions */ \ + struct cmc_callbacks_linkedlist *callbacks; \ }; \ \ /* Doubly-linked list node */ \ @@ -105,8 +169,13 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h /* Collection Functions */ \ /* Collection Allocation and Deallocation */ \ struct SNAME *PFX##_new(void); \ + struct SNAME *PFX##_new_custom(struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_linkedlist *callbacks); \ void PFX##_clear(struct SNAME *_list_, void (*deallocator)(V)); \ void PFX##_free(struct SNAME *_list_, void (*deallocator)(V)); \ + /* Customization of Allocation and Callbacks */ \ + void PFX##_customize(struct SNAME *_list_, struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_linkedlist *callbacks); \ /* Collection Input and Output */ \ bool PFX##_push_front(struct SNAME *_list_, V element); \ bool PFX##_push_at(struct SNAME *_list_, V element, size_t index); \ @@ -130,8 +199,8 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h \ /* Node Related Functions */ \ /* Node Allocation and Deallocation */ \ - struct SNAME##_node *PFX##_new_node(V element); \ - void PFX##_free_node(struct SNAME##_node *_node_); \ + struct SNAME##_node *PFX##_new_node(struct SNAME *_list_, V element); \ + void PFX##_free_node(struct SNAME *_list_, struct SNAME##_node *_node_); \ /* Node Access Relative to a Linked List */ \ struct SNAME##_node *PFX##_head(struct SNAME *_list_); \ struct SNAME##_node *PFX##_get_node(struct SNAME *_list_, size_t index); \ @@ -167,9 +236,11 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h V PFX##_iter_value(struct SNAME##_iter *iter); \ V *PFX##_iter_rvalue(struct SNAME##_iter *iter); \ size_t PFX##_iter_index(struct SNAME##_iter *iter); \ - struct SNAME##_node *PFX##_iter_node(struct SNAME##_iter *iter); \ - \ -/* SOURCE ********************************************************************/ + struct SNAME##_node *PFX##_iter_node(struct SNAME##_iter *iter); + +/* ------------------------------------------------------------------------------------------------- + * Source + ------------------------------------------------------------------------------------------------ */ #define CMC_GENERATE_LINKEDLIST_SOURCE(PFX, SNAME, V) \ \ /* Implementation Detail Functions */ \ @@ -178,7 +249,9 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h \ struct SNAME *PFX##_new(void) \ { \ - struct SNAME *_list_ = malloc(sizeof(struct SNAME)); \ + struct cmc_alloc_node *alloc = &cmc_alloc_node_default; \ + \ + struct SNAME *_list_ = alloc->malloc(sizeof(struct SNAME)); \ \ if (!_list_) \ return NULL; \ @@ -190,6 +263,33 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h _list_->it_start = PFX##_impl_it_start; \ _list_->it_end = PFX##_impl_it_end; \ \ + _list_->alloc = alloc; \ + _list_->callbacks = NULL; \ + \ + return _list_; \ + } \ + \ + struct SNAME *PFX##_new_custom(struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_linkedlist *callbacks) \ + { \ + if (!alloc) \ + alloc = &cmc_alloc_node_default; \ + \ + struct SNAME *_list_ = alloc->malloc(sizeof(struct SNAME)); \ + \ + if (!_list_) \ + return NULL; \ + \ + _list_->count = 0; \ + _list_->head = NULL; \ + _list_->tail = NULL; \ + \ + _list_->it_start = PFX##_impl_it_start; \ + _list_->it_end = PFX##_impl_it_end; \ + \ + _list_->alloc = alloc; \ + _list_->callbacks = callbacks; \ + \ return _list_; \ } \ \ @@ -206,7 +306,7 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h deallocator(scan->data); \ } \ \ - free(scan); \ + _list_->alloc->free(scan); \ \ scan = _list_->head; \ } \ @@ -220,12 +320,22 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h { \ PFX##_clear(_list_, deallocator); \ \ - free(_list_); \ + _list_->alloc->free(_list_); \ + } \ + \ + void PFX##_customize(struct SNAME *_list_, struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_linkedlist *callbacks) \ + { \ + if (alloc) \ + _list_->alloc = alloc; \ + \ + if (callbacks) \ + _list_->callbacks = callbacks; \ } \ \ bool PFX##_push_front(struct SNAME *_list_, V element) \ { \ - struct SNAME##_node *_node_ = PFX##_new_node(element); \ + struct SNAME##_node *_node_ = PFX##_new_node(_list_, element); \ \ if (!_node_) \ return false; \ @@ -261,7 +371,7 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h return PFX##_push_back(_list_, element); \ } \ \ - struct SNAME##_node *_node_ = PFX##_new_node(element); \ + struct SNAME##_node *_node_ = PFX##_new_node(_list_, element); \ \ if (!_node_) \ return false; \ @@ -280,7 +390,7 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h \ bool PFX##_push_back(struct SNAME *_list_, V element) \ { \ - struct SNAME##_node *_node_ = PFX##_new_node(element); \ + struct SNAME##_node *_node_ = PFX##_new_node(_list_, element); \ \ if (!_node_) \ return false; \ @@ -310,7 +420,7 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h struct SNAME##_node *_node_ = _list_->head; \ _list_->head = _list_->head->next; \ \ - free(_node_); \ + _list_->alloc->free(_node_); \ \ if (_list_->head == NULL) \ _list_->tail = NULL; \ @@ -347,7 +457,7 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h _node_->next->prev = _node_->prev; \ _node_->prev->next = _node_->next; \ \ - free(_node_); \ + _list_->alloc->free(_node_); \ \ _list_->count--; \ \ @@ -362,7 +472,7 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h struct SNAME##_node *_node_ = _list_->tail; \ _list_->tail = _list_->tail->prev; \ \ - free(_node_); \ + _list_->alloc->free(_node_); \ \ if (_list_->tail == NULL) \ _list_->head = NULL; \ @@ -446,7 +556,7 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h \ struct SNAME *PFX##_copy_of(struct SNAME *_list_, V (*copy_func)(V)) \ { \ - struct SNAME *result = PFX##_new(); \ + struct SNAME *result = PFX##_new_custom(_list_->alloc, _list_->callbacks); \ \ if (!result) \ return NULL; \ @@ -460,9 +570,9 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h struct SNAME##_node *new_node; \ \ if (copy_func) \ - new_node = PFX##_new_node(copy_func(scan->data)); \ + new_node = PFX##_new_node(_list_, copy_func(scan->data)); \ else \ - new_node = PFX##_new_node(scan->data); \ + new_node = PFX##_new_node(_list_, scan->data); \ \ if (!result->head) \ { \ @@ -508,17 +618,22 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h { \ struct cmc_string str; \ struct SNAME *l_ = _list_; \ - const char *name = #SNAME; \ \ - snprintf(str.s, cmc_string_len, cmc_string_fmt_linkedlist, \ - name, l_, l_->count, l_->head, l_->tail); \ + int n = snprintf(str.s, cmc_string_len, cmc_string_fmt_linkedlist, \ + #SNAME, #V, l_, l_->count, l_->head, l_->tail, \ + l_->alloc, l_->callbacks); \ + \ + if (n < 0 || n == (int)cmc_string_len) \ + return (struct cmc_string){0}; \ + \ + str.s[n] = '\0'; \ \ return str; \ } \ \ - struct SNAME##_node *PFX##_new_node(V element) \ + struct SNAME##_node *PFX##_new_node(struct SNAME *_list_, V element) \ { \ - struct SNAME##_node *_node_ = malloc(sizeof(struct SNAME##_node)); \ + struct SNAME##_node *_node_ = _list_->alloc->malloc(sizeof(struct SNAME##_node)); \ \ if (!_node_) \ return NULL; \ @@ -530,9 +645,9 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h return _node_; \ } \ \ - void PFX##_free_node(struct SNAME##_node *_node_) \ + void PFX##_free_node(struct SNAME *_list_, struct SNAME##_node *_node_) \ { \ - free(_node_); \ + _list_->alloc->free(_node_); \ } \ \ struct SNAME##_node *PFX##_head(struct SNAME *_list_) \ @@ -577,7 +692,7 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h \ bool PFX##_insert_after(struct SNAME *_owner_, struct SNAME##_node *_node_, V element) \ { \ - struct SNAME##_node *new_node = PFX##_new_node(element); \ + struct SNAME##_node *new_node = PFX##_new_node(_owner_, element); \ \ if (!new_node) \ return false; \ @@ -599,7 +714,7 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h \ bool PFX##_insert_before(struct SNAME *_owner_, struct SNAME##_node *_node_, V element) \ { \ - struct SNAME##_node *new_node = PFX##_new_node(element); \ + struct SNAME##_node *new_node = PFX##_new_node(_owner_, element); \ \ if (!new_node) \ return false; \ @@ -634,7 +749,7 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h else \ _owner_->tail = _node_; \ \ - free(tmp); \ + _owner_->alloc->free(tmp); \ \ _owner_->count--; \ \ @@ -653,7 +768,7 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h else \ _owner_->tail = _node_->prev; \ \ - free(_node_); \ + _owner_->alloc->free(_node_); \ \ _owner_->count--; \ \ @@ -675,7 +790,7 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h else \ _owner_->head = _node_; \ \ - free(tmp); \ + _owner_->alloc->free(tmp); \ \ _owner_->count--; \ \ @@ -694,7 +809,7 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h \ struct SNAME##_iter *PFX##_iter_new(struct SNAME *target) \ { \ - struct SNAME##_iter *iter = malloc(sizeof(struct SNAME##_iter)); \ + struct SNAME##_iter *iter = target->alloc->malloc(sizeof(struct SNAME##_iter)); \ \ if (!iter) \ return NULL; \ @@ -706,7 +821,7 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h \ void PFX##_iter_free(struct SNAME##_iter *iter) \ { \ - free(iter); \ + iter->target->alloc->free(iter); \ } \ \ void PFX##_iter_init(struct SNAME##_iter *iter, struct SNAME *target) \ diff --git a/src/cmc/list.h b/src/cmc/list.h index 5e52ebd..094f6ec 100644 --- a/src/cmc/list.h +++ b/src/cmc/list.h @@ -48,10 +48,66 @@ #include #include #include -#include "../utl/cmc_string.h" +/* ------------------------------------------------------------------------------------------------- + * Core functionalities of the C Macro Collections Library + ------------------------------------------------------------------------------------------------ */ +#ifndef CMC_CORE_H +#define CMC_CORE_H + +/** + * struct cmc_string + * + * Used by all collections when calling the to_string function. + */ +struct cmc_string +{ + char s[400]; +}; + +static const size_t cmc_string_len = 400; + +/** + * struct cmc_alloc_node + * + * Custom allocation node. Allows collections to use custom allocation functions. + */ +struct cmc_alloc_node +{ + void *(*malloc)(size_t); + void *(*calloc)(size_t, size_t); + void *(*realloc)(void *, size_t); + void (*free)(void *); +} cmc_alloc_node_default = {malloc, calloc, realloc, free}; + +#endif /* CMC_CORE_H */ + +/* ------------------------------------------------------------------------------------------------- + * List specific + ------------------------------------------------------------------------------------------------ */ /* to_string format */ -static const char *cmc_string_fmt_list = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX " }"; +static const char *cmc_string_fmt_list = "struct %s<%s> " + "at %p { " + "buffer:%p, " + "capacity:%" PRIuMAX ", " + "count:%" PRIuMAX ", " + "alloc:%p, " + "callbacks:%p }"; + +/** + * Custom List callbacks. + * + * There are two types of callbacks, 'before' and 'after': + * _ + */ +struct cmc_callbacks_list +{ + void (*before_clear)(void *); + void (*after_clear)(void *); + void (*before_free)(void *); + void (*after_free)(void *); + // TODO implement all callbacks +}; #define CMC_GENERATE_LIST(PFX, SNAME, V) \ CMC_GENERATE_LIST_HEADER(PFX, SNAME, V) \ @@ -63,7 +119,9 @@ static const char *cmc_string_fmt_list = "%s at %p { buffer:%p, capacity:%" PRIu #define CMC_WRAPGEN_LIST_SOURCE(PFX, SNAME, K, V) \ CMC_GENERATE_LIST_SOURCE(PFX, SNAME, V) -/* HEADER ********************************************************************/ +/* ------------------------------------------------------------------------------------------------- + * Header + ------------------------------------------------------------------------------------------------ */ #define CMC_GENERATE_LIST_HEADER(PFX, SNAME, V) \ \ /* List Structure */ \ @@ -83,6 +141,12 @@ static const char *cmc_string_fmt_list = "%s at %p { buffer:%p, capacity:%" PRIu \ /* Function that returns an iterator to the end of the list */ \ struct SNAME##_iter (*it_end)(struct SNAME *); \ + \ + /* Custom allocation functions */ \ + struct cmc_alloc_node *alloc; \ + \ + /* Custom callback functions */ \ + struct cmc_callbacks_list *callbacks; \ }; \ \ /* List Iterator */ \ @@ -104,9 +168,14 @@ static const char *cmc_string_fmt_list = "%s at %p { buffer:%p, capacity:%" PRIu /* Collection Functions */ \ /* Collection Allocation and Deallocation */ \ struct SNAME *PFX##_new(size_t capacity); \ + struct SNAME *PFX##_new_custom(size_t capacity, struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_list *callbacks); \ struct SNAME *PFX##_new_from(V *elements, size_t size); \ void PFX##_clear(struct SNAME *_list_, void (*deallocator)(V)); \ void PFX##_free(struct SNAME *_list_, void (*deallocator)(V)); \ + /* Customization of Allocation and Callbacks */ \ + void PFX##_customize(struct SNAME *_list_, struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_list *callbacks); \ /* Collection Input and Output */ \ bool PFX##_push_front(struct SNAME *_list_, V element); \ bool PFX##_push_at(struct SNAME *_list_, V element, size_t index); \ @@ -160,9 +229,11 @@ static const char *cmc_string_fmt_list = "%s at %p { buffer:%p, capacity:%" PRIu /* Iterator Access */ \ V PFX##_iter_value(struct SNAME##_iter *iter); \ V *PFX##_iter_rvalue(struct SNAME##_iter *iter); \ - size_t PFX##_iter_index(struct SNAME##_iter *iter); \ - \ -/* SOURCE ********************************************************************/ + size_t PFX##_iter_index(struct SNAME##_iter *iter); + +/* ------------------------------------------------------------------------------------------------- + * Source + ------------------------------------------------------------------------------------------------ */ #define CMC_GENERATE_LIST_SOURCE(PFX, SNAME, V) \ \ /* Implementation Detail Functions */ \ @@ -171,19 +242,21 @@ static const char *cmc_string_fmt_list = "%s at %p { buffer:%p, capacity:%" PRIu \ struct SNAME *PFX##_new(size_t capacity) \ { \ + struct cmc_alloc_node *alloc = &cmc_alloc_node_default; \ + \ if (capacity < 1) \ return NULL; \ \ - struct SNAME *_list_ = malloc(sizeof(struct SNAME)); \ + struct SNAME *_list_ = alloc->malloc(sizeof(struct SNAME)); \ \ if (!_list_) \ return NULL; \ \ - _list_->buffer = calloc(capacity, sizeof(V)); \ + _list_->buffer = alloc->calloc(capacity, sizeof(V)); \ \ if (!_list_->buffer) \ { \ - free(_list_); \ + alloc->free(_list_); \ return NULL; \ } \ \ @@ -193,6 +266,43 @@ static const char *cmc_string_fmt_list = "%s at %p { buffer:%p, capacity:%" PRIu _list_->it_start = PFX##_impl_it_start; \ _list_->it_end = PFX##_impl_it_end; \ \ + _list_->alloc = alloc; \ + _list_->callbacks = NULL; \ + \ + return _list_; \ + } \ + \ + struct SNAME *PFX##_new_custom(size_t capacity, struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_list *callbacks) \ + { \ + if (capacity < 1) \ + return NULL; \ + \ + if (!alloc) \ + alloc = &cmc_alloc_node_default; \ + \ + struct SNAME *_list_ = alloc->malloc(sizeof(struct SNAME)); \ + \ + if (!_list_) \ + return NULL; \ + \ + _list_->buffer = alloc->calloc(capacity, sizeof(V)); \ + \ + if (!_list_->buffer) \ + { \ + alloc->free(_list_); \ + return NULL; \ + } \ + \ + _list_->capacity = capacity; \ + _list_->count = 0; \ + \ + _list_->it_start = PFX##_impl_it_start; \ + _list_->it_end = PFX##_impl_it_end; \ + \ + _list_->alloc = alloc; \ + _list_->callbacks = callbacks; \ + \ return _list_; \ } \ \ @@ -234,8 +344,18 @@ static const char *cmc_string_fmt_list = "%s at %p { buffer:%p, capacity:%" PRIu deallocator(_list_->buffer[i]); \ } \ \ - free(_list_->buffer); \ - free(_list_); \ + _list_->alloc->free(_list_->buffer); \ + _list_->alloc->free(_list_); \ + } \ + \ + void PFX##_customize(struct SNAME *_list_, struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_list *callbacks) \ + { \ + if (alloc) \ + _list_->alloc = alloc; \ + \ + if (callbacks) \ + _list_->callbacks = callbacks; \ } \ \ bool PFX##_push_front(struct SNAME *_list_, V element) \ @@ -536,7 +656,7 @@ static const char *cmc_string_fmt_list = "%s at %p { buffer:%p, capacity:%" PRIu if (capacity < PFX##_count(_list_)) \ return false; \ \ - V *new_buffer = realloc(_list_->buffer, sizeof(V) * capacity); \ + V *new_buffer = _list_->alloc->realloc(_list_->buffer, sizeof(V) * capacity); \ \ if (!new_buffer) \ return false; \ @@ -549,7 +669,8 @@ static const char *cmc_string_fmt_list = "%s at %p { buffer:%p, capacity:%" PRIu \ struct SNAME *PFX##_copy_of(struct SNAME *_list_, V (*copy_func)(V)) \ { \ - struct SNAME *result = PFX##_new(_list_->capacity); \ + struct SNAME *result = PFX##_new_custom(_list_->capacity, _list_->alloc, \ + _list_->callbacks); \ \ if (!result) \ return NULL; \ @@ -585,17 +706,22 @@ static const char *cmc_string_fmt_list = "%s at %p { buffer:%p, capacity:%" PRIu { \ struct cmc_string str; \ struct SNAME *l_ = _list_; \ - const char *name = #SNAME; \ \ - snprintf(str.s, cmc_string_len, cmc_string_fmt_list, \ - name, l_, l_->buffer, l_->capacity, l_->count); \ + int n = snprintf(str.s, cmc_string_len, cmc_string_fmt_list, \ + #SNAME, #V, l_, l_->buffer, l_->capacity, l_->count, \ + l_->alloc, l_->callbacks); \ + \ + if (n < 0 || n == (int)cmc_string_len) \ + return (struct cmc_string){0}; \ + \ + str.s[n] = '\0'; \ \ return str; \ } \ \ struct SNAME##_iter *PFX##_iter_new(struct SNAME *target) \ { \ - struct SNAME##_iter *iter = malloc(sizeof(struct SNAME##_iter)); \ + struct SNAME##_iter *iter = target->alloc->malloc(sizeof(struct SNAME##_iter)); \ \ if (!iter) \ return NULL; \ @@ -607,7 +733,7 @@ static const char *cmc_string_fmt_list = "%s at %p { buffer:%p, capacity:%" PRIu \ void PFX##_iter_free(struct SNAME##_iter *iter) \ { \ - free(iter); \ + iter->target->alloc->free(iter); \ } \ \ void PFX##_iter_init(struct SNAME##_iter *iter, struct SNAME *target) \ diff --git a/src/cmc/multimap.h b/src/cmc/multimap.h index e31d23b..c93eab7 100644 --- a/src/cmc/multimap.h +++ b/src/cmc/multimap.h @@ -48,47 +48,88 @@ #include #include #include -#include "../utl/cmc_string.h" +/* ------------------------------------------------------------------------------------------------- + * Core functionalities of the C Macro Collections Library + ------------------------------------------------------------------------------------------------ */ +#ifndef CMC_CORE_H +#define CMC_CORE_H + +/** + * struct cmc_string + * + * Used by all collections when calling the to_string function. + */ +struct cmc_string +{ + char s[400]; +}; + +static const size_t cmc_string_len = 400; + +/** + * struct cmc_alloc_node + * + * Custom allocation node. Allows collections to use custom allocation functions. + */ +struct cmc_alloc_node +{ + void *(*malloc)(size_t); + void *(*calloc)(size_t, size_t); + void *(*realloc)(void *, size_t); + void (*free)(void *); +} cmc_alloc_node_default = {malloc, calloc, realloc, free}; + +#endif /* CMC_CORE_H */ + +/* ------------------------------------------------------------------------------------------------- + * Hashtable Implementation + ------------------------------------------------------------------------------------------------ */ +#ifndef CMC_IMPL_HASHTABLE_PRIMES +#define CMC_IMPL_HASHTABLE_PRIMES + +static const size_t cmc_hashtable_primes[] = + {53, 97, 191, 383, 769, 1531, 3067, 6143, 12289, 24571, 49157, 98299, 196613, 393209, 786431, + 1572869, 3145721, 6291449, 12582917, 25165813, 50331653, 100663291, 201326611, 402653189, + 805306357, 1610612741, 3221225473, 6442450939, 12884901893, 25769803799, 51539607551, + 103079215111, 206158430209, 412316860441, 824633720831, 1649267441651, 3298534883309, + 6597069766657, 13194139533299, 26388279066623, 52776558133303, 105553116266489, + 211106232532969, 422212465066001, 844424930131963, 1688849860263953, 3377699720527861, + 6755399441055731, 13510798882111483, 27021597764222939, 54043195528445957, 108086391056891903, + 216172782113783773, 432345564227567621, 864691128455135207, 1729382256910270481, + 3458764513820540933, 6917529027641081903, 13835058055282163729llu}; + +#endif /* CMC_IMPL_HASHTABLE_PRIMES */ + +/* ------------------------------------------------------------------------------------------------- + * MultiMap specific + ------------------------------------------------------------------------------------------------ */ /* to_string format */ -static const char *cmc_string_fmt_multimap = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", load:%lf, cmp:%p, hash:%p }"; +static const char *cmc_string_fmt_multimap = "struct %s<%s, %s> " + "at %p { " + "buffer:%p, " + "capacity:%" PRIuMAX ", " + "count:%" PRIuMAX ", " + "load:%lf, " + "cmp:%p, " + "hash:%p, " + "alloc:%p, " + "callbacks:%p }"; -#ifndef CMC_IMPL_HASHTABLE_SETUP -#define CMC_IMPL_HASHTABLE_SETUP - -static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, - 3067, 6143, 12289, 24571, 49157, - 98299, 196613, 393209, 786431, - 1572869, 3145721, 6291449, - 12582917, 25165813, 50331653, - 100663291, 201326611, 402653189, - 805306357, 1610612741, - 3221225473, 6442450939, - 12884901893, 25769803799, - 51539607551, 103079215111, - 206158430209, 412316860441, - 824633720831, 1649267441651, - 3298534883309, 6597069766657, - 13194139533299, 26388279066623, - 52776558133303, 105553116266489, - 211106232532969, 422212465066001, - 844424930131963, - 1688849860263953, - 3377699720527861, - 6755399441055731, - 13510798882111483, - 27021597764222939, - 54043195528445957, - 108086391056891903, - 216172782113783773, - 432345564227567621, - 864691128455135207, - 1729382256910270481, - 3458764513820540933, - 6917529027641081903, - 13835058055282163729llu}; - -#endif /* CMC_IMPL_HASHTABLE_SETUP */ +/** + * Custom MultiMap callbacks. + * + * There are two types of callbacks, 'before' and 'after': + * _ + */ +struct cmc_callbacks_multimap +{ + void (*before_clear)(void *); + void (*after_clear)(void *); + void (*before_free)(void *); + void (*after_free)(void *); + // TODO implement all callbacks +}; #define CMC_GENERATE_MULTIMAP(PFX, SNAME, K, V) \ CMC_GENERATE_MULTIMAP_HEADER(PFX, SNAME, K, V) \ @@ -100,1021 +141,1104 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, #define CMC_WRAPGEN_MULTIMAP_SOURCE(PFX, SNAME, K, V) \ CMC_GENERATE_MULTIMAP_SOURCE(PFX, SNAME, K, V) -/* HEADER ********************************************************************/ -#define CMC_GENERATE_MULTIMAP_HEADER(PFX, SNAME, K, V) \ - \ - /* Multimap Structure */ \ - struct SNAME \ - { \ - /* Array of linked list to entries */ \ - struct SNAME##_entry *(*buffer)[2]; \ - \ - /* Current array capacity */ \ - size_t capacity; \ - \ - /* Current amount of keys */ \ - size_t count; \ - \ - /* Load factor in range (0.0, infinity) */ \ - double load; \ - \ - /* Key comparison functions */ \ - int (*cmp)(K, K); \ - \ - /* Key hash function */ \ - size_t (*hash)(K); \ - \ - /* Function that returns an iterator to the start of the multimap */ \ - struct SNAME##_iter (*it_start)(struct SNAME *); \ - \ - /* Function that returns an iterator to the end of the multimap */ \ - struct SNAME##_iter (*it_end)(struct SNAME *); \ - }; \ - \ - /* Multimap Entry */ \ - struct SNAME##_entry \ - { \ - /* Entry Key */ \ - K key; \ - \ - /* Entry Value */ \ - V value; \ - \ - /* Next entry on the linked list */ \ - struct SNAME##_entry *next; \ - \ - /* Previous entry on the linked list */ \ - struct SNAME##_entry *prev; \ - }; \ - \ - struct SNAME##_iter \ - { \ - /* Target multimap */ \ - struct SNAME *target; \ - \ - /* Current entry */ \ - struct SNAME##_entry *curr_entry; \ - \ - /* Cursor`s position (index) */ \ - size_t cursor; \ - \ - /* Keeps track of relative index to the iteration of elements */ \ - size_t index; \ - \ - /* The index of the first element */ \ - size_t first; \ - \ - /* The index of the last element */ \ - size_t last; \ - \ - /* If the iterator has reached the start of the iteration */ \ - bool start; \ - \ - /* If the iterator has reached the end of the iteration */ \ - bool end; \ - }; \ - \ - /* Collection Functions */ \ - /* Collection Allocation and Deallocation */ \ - struct SNAME *PFX##_new(size_t capacity, double load, int (*compare)(K, K), size_t (*hash)(K)); \ - void PFX##_clear(struct SNAME *_map_, void (*deallocator)(K, V)); \ - void PFX##_free(struct SNAME *_map_, void (*deallocator)(K, V)); \ - /* Collection Input and Output */ \ - bool PFX##_insert(struct SNAME *_map_, K key, V value); \ - bool PFX##_update(struct SNAME *_map_, K key, V new_value, V *old_value); \ - size_t PFX##_update_all(struct SNAME *_map_, K key, V new_value, V **old_values); \ - bool PFX##_remove(struct SNAME *_map_, K key, V *out_value); \ - size_t PFX##_remove_all(struct SNAME *_map_, K key, V **out_values); \ - /* Element Access */ \ - bool PFX##_max(struct SNAME *_map_, K *key, V *value); \ - bool PFX##_min(struct SNAME *_map_, K *key, V *value); \ - V PFX##_get(struct SNAME *_map_, K key); \ - V *PFX##_get_ref(struct SNAME *_map_, K key); \ - /* Collection State */ \ - bool PFX##_contains(struct SNAME *_map_, K key); \ - bool PFX##_empty(struct SNAME *_map_); \ - bool PFX##_full(struct SNAME *_map_); \ - size_t PFX##_count(struct SNAME *_map_); \ - size_t PFX##_key_count(struct SNAME *_map_, K key); \ - size_t PFX##_capacity(struct SNAME *_map_); \ - double PFX##_load(struct SNAME *_map_); \ - /* Collection Utility */ \ - bool PFX##_resize(struct SNAME *_map_, size_t capacity); \ - struct SNAME *PFX##_copy_of(struct SNAME *_map_, K (*key_copy_func)(K), V (*value_copy_func)(V)); \ - bool PFX##_equals(struct SNAME *_map1_, struct SNAME *_map2_, bool ignore_key_count); \ - struct cmc_string PFX##_to_string(struct SNAME *_map_); \ - \ - /* Iterator Functions */ \ - /* Iterator Allocation and Deallocation */ \ - struct SNAME##_iter *PFX##_iter_new(struct SNAME *target); \ - void PFX##_iter_free(struct SNAME##_iter *iter); \ - /* Iterator Initialization */ \ - void PFX##_iter_init(struct SNAME##_iter *iter, struct SNAME *target); \ - /* Iterator State */ \ - bool PFX##_iter_start(struct SNAME##_iter *iter); \ - bool PFX##_iter_end(struct SNAME##_iter *iter); \ - /* Iterator Movement */ \ - void PFX##_iter_to_start(struct SNAME##_iter *iter); \ - void PFX##_iter_to_end(struct SNAME##_iter *iter); \ - bool PFX##_iter_next(struct SNAME##_iter *iter); \ - bool PFX##_iter_prev(struct SNAME##_iter *iter); \ - bool PFX##_iter_advance(struct SNAME##_iter *iter, size_t steps); \ - bool PFX##_iter_rewind(struct SNAME##_iter *iter, size_t steps); \ - bool PFX##_iter_go_to(struct SNAME##_iter *iter, size_t index); \ - /* Iterator Access */ \ - K PFX##_iter_key(struct SNAME##_iter *iter); \ - V PFX##_iter_value(struct SNAME##_iter *iter); \ - V *PFX##_iter_rvalue(struct SNAME##_iter *iter); \ - size_t PFX##_iter_index(struct SNAME##_iter *iter); \ - \ -/* SOURCE ********************************************************************/ -#define CMC_GENERATE_MULTIMAP_SOURCE(PFX, SNAME, K, V) \ - \ - /* Implementation Detail Functions */ \ - struct SNAME##_entry *PFX##_impl_new_entry(K key, V value); \ - struct SNAME##_entry *PFX##_impl_get_entry(struct SNAME *_map_, K key); \ - size_t PFX##_impl_calculate_size(size_t required); \ - static struct SNAME##_iter PFX##_impl_it_start(struct SNAME *_map_); \ - static struct SNAME##_iter PFX##_impl_it_end(struct SNAME *_map_); \ - \ - struct SNAME *PFX##_new(size_t capacity, double load, int (*compare)(K, K), size_t (*hash)(K)) \ - { \ - if (capacity == 0 || load <= 0) \ - return NULL; \ - \ - /* Prevent integer overflow */ \ - if (capacity >= UINTMAX_MAX * load) \ - return NULL; \ - \ - size_t real_capacity = PFX##_impl_calculate_size(capacity / load); \ - \ - struct SNAME *_map_ = malloc(sizeof(struct SNAME)); \ - \ - if (!_map_) \ - return NULL; \ - \ - _map_->buffer = calloc(real_capacity, sizeof(struct SNAME##_entry * [2])); \ - \ - if (!_map_->buffer) \ - { \ - free(_map_); \ - return NULL; \ - } \ - \ - _map_->count = 0; \ - _map_->capacity = real_capacity; \ - _map_->load = load; \ - _map_->cmp = compare; \ - _map_->hash = hash; \ - \ - _map_->it_start = PFX##_impl_it_start; \ - _map_->it_end = PFX##_impl_it_end; \ - \ - return _map_; \ - } \ - \ - void PFX##_clear(struct SNAME *_map_, void (*deallocator)(K, V)) \ - { \ - size_t index = 0; \ - struct SNAME##_entry *scan; \ - \ - while (index < _map_->capacity) \ - { \ - scan = _map_->buffer[index][0]; \ - \ - if (scan != NULL) \ - { \ - if (scan->next == NULL && scan->prev == NULL) \ - { \ - if (deallocator) \ - deallocator(scan->key, scan->value); \ - \ - free(scan); \ - } \ - else \ - { \ - while (scan != NULL) \ - { \ - struct SNAME##_entry *tmp = scan; \ - \ - scan = scan->next; \ - \ - if (deallocator) \ - deallocator(tmp->key, tmp->value); \ - \ - free(tmp); \ - } \ - } \ - } \ - \ - index++; \ - } \ - \ - memset(_map_->buffer, 0, sizeof(struct SNAME##_entry * [2]) * _map_->capacity); \ - \ - _map_->count = 0; \ - } \ - \ - void PFX##_free(struct SNAME *_map_, void (*deallocator)(K, V)) \ - { \ - size_t index = 0; \ - struct SNAME##_entry *scan; \ - \ - while (index < _map_->capacity) \ - { \ - scan = _map_->buffer[index][0]; \ - \ - if (scan != NULL) \ - { \ - if (scan->next == NULL && scan->prev == NULL) \ - free(scan); \ - else \ - { \ - while (scan != NULL) \ - { \ - struct SNAME##_entry *tmp = scan; \ - \ - scan = scan->next; \ - \ - if (deallocator) \ - deallocator(tmp->key, tmp->value); \ - \ - free(tmp); \ - } \ - } \ - } \ - \ - index++; \ - } \ - \ - free(_map_->buffer); \ - free(_map_); \ - } \ - \ - bool PFX##_insert(struct SNAME *_map_, K key, V value) \ - { \ - if (PFX##_full(_map_)) \ - { \ - if (!PFX##_resize(_map_, PFX##_capacity(_map_) + 1)) \ - return false; \ - } \ - \ - size_t hash = _map_->hash(key); \ - size_t pos = hash % _map_->capacity; \ - \ - struct SNAME##_entry *entry = PFX##_impl_new_entry(key, value); \ - \ - if (_map_->buffer[pos][0] == NULL) \ - { \ - _map_->buffer[pos][0] = entry; \ - _map_->buffer[pos][1] = entry; \ - } \ - else \ - { \ - entry->prev = _map_->buffer[pos][1]; \ - \ - _map_->buffer[pos][1]->next = entry; \ - _map_->buffer[pos][1] = entry; \ - } \ - \ - _map_->count++; \ - \ - return true; \ - } \ - \ - bool PFX##_update(struct SNAME *_map_, K key, V new_value, V *old_value) \ - { \ - struct SNAME##_entry *entry = PFX##_impl_get_entry(_map_, key); \ - \ - if (!entry) \ - return false; \ - \ - if (old_value) \ - *old_value = entry->value; \ - \ - entry->value = new_value; \ - \ - return false; \ - } \ - \ - size_t PFX##_update_all(struct SNAME *_map_, K key, V new_value, V **old_values) \ - { \ - size_t total = PFX##_key_count(_map_, key); \ - size_t index = 0; \ - \ - if (total == 0) \ - return total; \ - \ - if (old_values) \ - { \ - *old_values = malloc(sizeof(V) * total); \ - \ - if (!(*old_values)) \ - return false; \ - } \ - \ - size_t hash = _map_->hash(key); \ - \ - struct SNAME##_entry *entry = _map_->buffer[hash % _map_->capacity][0]; \ - \ - while (entry != NULL) \ - { \ - if (_map_->cmp(entry->key, key) == 0) \ - { \ - if (old_values) \ - (*old_values)[index++] = entry->value; \ - \ - entry->value = new_value; \ - } \ - \ - entry = entry->next; \ - } \ - \ - return index; \ - } \ - \ - bool PFX##_remove(struct SNAME *_map_, K key, V *out_value) \ - { \ - size_t hash = _map_->hash(key); \ - \ - struct SNAME##_entry **head = &(_map_->buffer[hash % _map_->capacity][0]); \ - struct SNAME##_entry **tail = &(_map_->buffer[hash % _map_->capacity][1]); \ - \ - if (*head == NULL) \ - return false; \ - \ - struct SNAME##_entry *entry = *head; \ - \ - if (entry->next == NULL && entry->prev == NULL) \ - { \ - if (_map_->cmp(entry->key, key) == 0) \ - { \ - *head = NULL; \ - *tail = NULL; \ - \ - if (out_value) \ - *out_value = entry->value; \ - } \ - else \ - return false; \ - } \ - else \ - { \ - bool found = false; \ - \ - while (entry != NULL) \ - { \ - if (_map_->cmp(entry->key, key) == 0) \ - { \ - if (*head == entry) \ - *head = entry->next; \ - if (*tail == entry) \ - *tail = entry->prev; \ - \ - if (entry->prev != NULL) \ - entry->prev->next = entry->next; \ - if (entry->next != NULL) \ - entry->next->prev = entry->prev; \ - \ - if (out_value) \ - *out_value = entry->value; \ - \ - found = true; \ - \ - break; \ - } \ - else \ - entry = entry->next; \ - } \ - \ - if (!found) \ - return false; \ - } \ - \ - free(entry); \ - \ - _map_->count--; \ - \ - return true; \ - } \ - \ - size_t PFX##_remove_all(struct SNAME *_map_, K key, V **out_values) \ - { \ - size_t hash = _map_->hash(key); \ - \ - struct SNAME##_entry **head = &(_map_->buffer[hash % _map_->capacity][0]); \ - struct SNAME##_entry **tail = &(_map_->buffer[hash % _map_->capacity][1]); \ - \ - if (*head == NULL) \ - return 0; \ - \ - size_t total = PFX##_key_count(_map_, key); \ - size_t index = 0; \ - \ - if (out_values) \ - *out_values = malloc(sizeof(struct SNAME##_entry) * total); \ - \ - struct SNAME##_entry *entry = *head; \ - \ - if (entry->next == NULL) \ - { \ - *head = NULL; \ - *tail = NULL; \ - \ - if (out_values) \ - (*out_values)[index++] = entry->value; \ - \ - free(entry); \ - } \ - else \ - { \ - while (entry != NULL) \ - { \ - if (_map_->cmp(entry->key, key) == 0) \ - { \ - if (*head == entry) \ - *head = entry->next; \ - if (*tail == entry) \ - *tail = entry->prev; \ - \ - struct SNAME##_entry *temp = entry->next; \ - \ - if (entry->prev != NULL) \ - entry->prev->next = entry->next; \ - if (entry->next != NULL) \ - entry->next->prev = entry->prev; \ - \ - if (out_values) \ - (*out_values)[index++] = entry->value; \ - \ - free(entry); \ - \ - entry = temp; \ - } \ - else \ - entry = entry->next; \ - } \ - } \ - \ - _map_->count -= index; \ - \ - return index; \ - } \ - \ - bool PFX##_max(struct SNAME *_map_, K *key, V *value) \ - { \ - if (PFX##_empty(_map_)) \ - return false; \ - \ - struct SNAME##_iter iter; \ - \ - for (PFX##_iter_init(&iter, _map_); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \ - { \ - K result_key = PFX##_iter_key(&iter); \ - V result_value = PFX##_iter_value(&iter); \ - size_t index = PFX##_iter_index(&iter); \ - \ - if (index == 0) \ - { \ - *key = result_key; \ - *value = result_value; \ - } \ - else if (_map_->cmp(result_key, *key) > 0) \ - { \ - *key = result_key; \ - *value = result_value; \ - } \ - } \ - \ - return true; \ - } \ - \ - bool PFX##_min(struct SNAME *_map_, K *key, V *value) \ - { \ - if (PFX##_empty(_map_)) \ - return false; \ - \ - struct SNAME##_iter iter; \ - \ - for (PFX##_iter_init(&iter, _map_); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \ - { \ - K result_key = PFX##_iter_key(&iter); \ - V result_value = PFX##_iter_value(&iter); \ - size_t index = PFX##_iter_index(&iter); \ - \ - if (index == 0) \ - { \ - *key = result_key; \ - *value = result_value; \ - } \ - else if (_map_->cmp(result_key, *key) < 0) \ - { \ - *key = result_key; \ - *value = result_value; \ - } \ - } \ - \ - return true; \ - } \ - \ - V PFX##_get(struct SNAME *_map_, K key) \ - { \ - struct SNAME##_entry *entry = PFX##_impl_get_entry(_map_, key); \ - \ - if (!entry) \ - return (V){0}; \ - \ - return entry->value; \ - } \ - \ - V *PFX##_get_ref(struct SNAME *_map_, K key) \ - { \ - struct SNAME##_entry *entry = PFX##_impl_get_entry(_map_, key); \ - \ - if (!entry) \ - return NULL; \ - \ - return &(entry->value); \ - } \ - \ - bool PFX##_contains(struct SNAME *_map_, K key) \ - { \ - return PFX##_impl_get_entry(_map_, key) != NULL; \ - } \ - \ - bool PFX##_empty(struct SNAME *_map_) \ - { \ - return _map_->count == 0; \ - } \ - \ - bool PFX##_full(struct SNAME *_map_) \ - { \ - return (double)PFX##_capacity(_map_) * PFX##_load(_map_) <= (double)PFX##_count(_map_); \ - } \ - \ - size_t PFX##_count(struct SNAME *_map_) \ - { \ - return _map_->count; \ - } \ - \ - size_t PFX##_key_count(struct SNAME *_map_, K key) \ - { \ - size_t hash = _map_->hash(key); \ - \ - struct SNAME##_entry *entry = _map_->buffer[hash % _map_->capacity][0]; \ - \ - size_t total_count = 0; \ - \ - if (!entry) \ - return total_count; \ - \ - while (entry != NULL) \ - { \ - if (_map_->cmp(entry->key, key) == 0) \ - total_count++; \ - \ - entry = entry->next; \ - } \ - \ - return total_count; \ - } \ - \ - size_t PFX##_capacity(struct SNAME *_map_) \ - { \ - return _map_->capacity; \ - } \ - \ - double PFX##_load(struct SNAME *_map_) \ - { \ - return _map_->load; \ - } \ - \ - bool PFX##_resize(struct SNAME *_map_, size_t capacity) \ - { \ - if (PFX##_capacity(_map_) == capacity) \ - return true; \ - \ - if (PFX##_capacity(_map_) > capacity / PFX##_load(_map_)) \ - return true; \ - \ - /* Prevent integer overflow */ \ - if (capacity >= UINTMAX_MAX * PFX##_load(_map_)) \ - return false; \ - \ - /* Calculate required capacity based on the prime numbers */ \ - size_t theoretical_size = PFX##_impl_calculate_size(capacity); \ - \ - /* Not possible to shrink with current available prime numbers */ \ - if (theoretical_size < PFX##_count(_map_) / PFX##_load(_map_)) \ - return false; \ - \ - struct SNAME *_new_map_ = PFX##_new(capacity, PFX##_load(_map_), _map_->cmp, _map_->hash); \ - \ - if (!_new_map_) \ - return false; \ - \ - struct SNAME##_iter iter; \ - \ - for (PFX##_iter_init(&iter, _map_); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \ - { \ - K key = PFX##_iter_key(&iter); \ - V value = PFX##_iter_value(&iter); \ - \ - PFX##_insert(_new_map_, key, value); \ - } \ - \ - if (PFX##_count(_map_) != PFX##_count(_new_map_)) \ - { \ - PFX##_free(_new_map_, NULL); \ - return false; \ - } \ - \ - struct SNAME##_entry *(*tmp_b)[2] = _map_->buffer; \ - _map_->buffer = _new_map_->buffer; \ - _new_map_->buffer = tmp_b; \ - \ - size_t tmp_c = _map_->capacity; \ - _map_->capacity = _new_map_->capacity; \ - _new_map_->capacity = tmp_c; \ - \ - PFX##_free(_new_map_, NULL); \ - \ - return true; \ - } \ - \ - struct SNAME *PFX##_copy_of(struct SNAME *_map_, K (*key_copy_func)(K), V (*value_copy_func)(V)) \ - { \ - struct SNAME *result = PFX##_new(_map_->capacity, _map_->load, _map_->cmp, _map_->hash); \ - \ - if (!result) \ - return NULL; \ - \ - struct SNAME##_iter iter; \ - PFX##_iter_init(&iter, _map_); \ - \ - if (!PFX##_empty(_map_)) \ - { \ - for (PFX##_iter_to_start(&iter); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \ - { \ - K key = PFX##_iter_key(&iter); \ - V value = PFX##_iter_value(&iter); \ - \ - if (key_copy_func) \ - key = key_copy_func(key); \ - if (value_copy_func) \ - value = value_copy_func(value); \ - \ - PFX##_insert(result, key, value); \ - } \ - } \ - \ - return result; \ - } \ - \ - bool PFX##_equals(struct SNAME *_map1_, struct SNAME *_map2_, bool ignore_key_count) \ - { \ - if (ignore_key_count) \ - { \ - struct SNAME##_iter iter; \ - PFX##_iter_init(&iter, _map1_); \ - \ - for (PFX##_iter_to_start(&iter); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \ - { \ - if (PFX##_impl_get_entry(_map2_, PFX##_iter_key(&iter)) == NULL) \ - return false; \ - } \ - } \ - else \ - { \ - /* Since the key count matters this can be checked and an early exit */ \ - if (PFX##_count(_map1_) != PFX##_count(_map2_)) \ - return false; \ - \ - struct SNAME##_iter iter; \ - PFX##_iter_init(&iter, _map1_); \ - \ - for (PFX##_iter_to_start(&iter); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \ - { \ - K key = PFX##_iter_key(&iter); \ - \ - if (PFX##_key_count(_map1_, key) != PFX##_key_count(_map2_, key)) \ - return false; \ - } \ - } \ - \ - return true; \ - } \ - \ - struct cmc_string PFX##_to_string(struct SNAME *_map_) \ - { \ - struct cmc_string str; \ - struct SNAME *m_ = _map_; \ - const char *name = #SNAME; \ - \ - snprintf(str.s, cmc_string_len, cmc_string_fmt_multimap, \ - name, m_, m_->buffer, m_->capacity, m_->count, m_->load, m_->cmp, m_->hash); \ - \ - return str; \ - } \ - \ - struct SNAME##_iter *PFX##_iter_new(struct SNAME *target) \ - { \ - struct SNAME##_iter *iter = malloc(sizeof(struct SNAME##_iter)); \ - \ - if (!iter) \ - return NULL; \ - \ - PFX##_iter_init(iter, target); \ - \ - return iter; \ - } \ - \ - void PFX##_iter_free(struct SNAME##_iter *iter) \ - { \ - free(iter); \ - } \ - \ - void PFX##_iter_init(struct SNAME##_iter *iter, struct SNAME *target) \ - { \ - memset(iter, 0, sizeof(struct SNAME##_iter)); \ - \ - iter->target = target; \ - iter->start = true; \ - iter->end = PFX##_empty(target); \ - \ - if (!PFX##_empty(target)) \ - { \ - for (size_t i = 0; i < target->capacity; i++) \ - { \ - if (target->buffer[i][0] != NULL) \ - { \ - iter->curr_entry = target->buffer[i][0]; \ - iter->first = i; \ - break; \ - } \ - } \ - \ - iter->cursor = iter->first; \ - \ - for (size_t i = target->capacity; i > 0; i--) \ - { \ - if (target->buffer[i - 1][0] != NULL) \ - { \ - iter->last = i - 1; \ - break; \ - } \ - } \ - } \ - } \ - \ - bool PFX##_iter_start(struct SNAME##_iter *iter) \ - { \ - return PFX##_empty(iter->target) || iter->start; \ - } \ - \ - bool PFX##_iter_end(struct SNAME##_iter *iter) \ - { \ - return PFX##_empty(iter->target) || iter->end; \ - } \ - \ - void PFX##_iter_to_start(struct SNAME##_iter *iter) \ - { \ - if (!PFX##_empty(iter->target)) \ - { \ - iter->cursor = iter->first; \ - iter->index = 0; \ - iter->start = true; \ - iter->end = PFX##_empty(iter->target); \ - iter->curr_entry = iter->target->buffer[iter->first][0]; \ - } \ - } \ - \ - void PFX##_iter_to_end(struct SNAME##_iter *iter) \ - { \ - if (!PFX##_empty(iter->target)) \ - { \ - iter->cursor = iter->last; \ - iter->index = iter->target->count - 1; \ - iter->start = PFX##_empty(iter->target); \ - iter->end = true; \ - iter->curr_entry = iter->target->buffer[iter->last][1]; \ - } \ - } \ - \ - bool PFX##_iter_next(struct SNAME##_iter *iter) \ - { \ - if (iter->end) \ - return false; \ - \ - if (iter->curr_entry->next != NULL) \ - { \ - iter->curr_entry = iter->curr_entry->next; \ - iter->index++; \ - } \ - else \ - { \ - if (iter->cursor == iter->last) \ - { \ - iter->end = true; \ - return false; \ - } \ - \ - iter->cursor++; \ - \ - while (iter->target->buffer[iter->cursor][0] == NULL) \ - iter->cursor++; \ - \ - iter->curr_entry = iter->target->buffer[iter->cursor][0]; \ - \ - iter->index++; \ - } \ - \ - iter->start = PFX##_empty(iter->target); \ - \ - return true; \ - } \ - \ - bool PFX##_iter_prev(struct SNAME##_iter *iter) \ - { \ - if (iter->start) \ - return false; \ - \ - if (iter->curr_entry->prev != NULL) \ - { \ - iter->curr_entry = iter->curr_entry->prev; \ - iter->index--; \ - } \ - else \ - { \ - if (iter->cursor == iter->first) \ - { \ - iter->start = true; \ - return false; \ - } \ - \ - iter->cursor--; \ - \ - while (iter->target->buffer[iter->cursor][1] == NULL) \ - iter->cursor--; \ - \ - iter->curr_entry = iter->target->buffer[iter->cursor][1]; \ - \ - iter->index--; \ - } \ - \ - iter->end = PFX##_empty(iter->target); \ - \ - return true; \ - } \ - \ - /* Returns true only if the iterator moved */ \ - bool PFX##_iter_advance(struct SNAME##_iter *iter, size_t steps) \ - { \ - if (iter->end) \ - return false; \ - \ - if (iter->index + 1 == PFX##_count(iter->target)) \ - { \ - iter->end = true; \ - return false; \ - } \ - \ - if (steps == 0 || iter->index + steps >= PFX##_count(iter->target)) \ - return false; \ - \ - for (size_t i = 0; i < steps; i++) \ - PFX##_iter_next(iter); \ - \ - return true; \ - } \ - \ - /* Returns true only if the iterator moved */ \ - bool PFX##_iter_rewind(struct SNAME##_iter *iter, size_t steps) \ - { \ - if (iter->start) \ - return false; \ - \ - if (iter->index == 0) \ - { \ - iter->start = true; \ - return false; \ - } \ - \ - if (steps == 0 || iter->index < steps) \ - return false; \ - \ - for (size_t i = 0; i < steps; i++) \ - PFX##_iter_prev(iter); \ - \ - return true; \ - } \ - \ - /* Returns true only if the iterator was able to be positioned at the given index */ \ - bool PFX##_iter_go_to(struct SNAME##_iter *iter, size_t index) \ - { \ - if (index >= PFX##_count(iter->target)) \ - return false; \ - \ - if (iter->index > index) \ - return PFX##_iter_rewind(iter, iter->index - index); \ - else if (iter->index < index) \ - return PFX##_iter_advance(iter, index - iter->index); \ - \ - return true; \ - } \ - \ - K PFX##_iter_key(struct SNAME##_iter *iter) \ - { \ - if (PFX##_empty(iter->target)) \ - return (K){0}; \ - \ - return iter->curr_entry->key; \ - } \ - \ - V PFX##_iter_value(struct SNAME##_iter *iter) \ - { \ - if (PFX##_empty(iter->target)) \ - return (V){0}; \ - \ - return iter->curr_entry->value; \ - } \ - \ - V *PFX##_iter_rvalue(struct SNAME##_iter *iter) \ - { \ - if (PFX##_empty(iter->target)) \ - return NULL; \ - \ - return &(iter->curr_entry->value); \ - } \ - \ - size_t PFX##_iter_index(struct SNAME##_iter *iter) \ - { \ - return iter->index; \ - } \ - \ - struct SNAME##_entry *PFX##_impl_new_entry(K key, V value) \ - { \ - struct SNAME##_entry *entry = malloc(sizeof(struct SNAME##_entry)); \ - \ - if (!entry) \ - return NULL; \ - \ - entry->key = key; \ - entry->value = value; \ - entry->next = NULL; \ - entry->prev = NULL; \ - \ - return entry; \ - } \ - \ - struct SNAME##_entry *PFX##_impl_get_entry(struct SNAME *_map_, K key) \ - { \ - size_t hash = _map_->hash(key); \ - \ - struct SNAME##_entry *entry = _map_->buffer[hash % _map_->capacity][0]; \ - \ - while (entry != NULL) \ - { \ - if (_map_->cmp(entry->key, key) == 0) \ - return entry; \ - \ - entry = entry->next; \ - } \ - \ - return NULL; \ - } \ - \ - size_t PFX##_impl_calculate_size(size_t required) \ - { \ - const size_t count = sizeof(cmc_hashtable_primes) / sizeof(cmc_hashtable_primes[0]); \ - \ - if (cmc_hashtable_primes[count - 1] < required) \ - return required; \ - \ - size_t i = 0; \ - while (cmc_hashtable_primes[i] < required) \ - i++; \ - \ - return cmc_hashtable_primes[i]; \ - } \ - \ - static struct SNAME##_iter PFX##_impl_it_start(struct SNAME *_map_) \ - { \ - struct SNAME##_iter iter; \ - \ - PFX##_iter_init(&iter, _map_); \ - \ - return iter; \ - } \ - \ - static struct SNAME##_iter PFX##_impl_it_end(struct SNAME *_map_) \ - { \ - struct SNAME##_iter iter; \ - \ - PFX##_iter_init(&iter, _map_); \ - PFX##_iter_to_end(&iter); \ - \ - return iter; \ +/* ------------------------------------------------------------------------------------------------- + * Header + ------------------------------------------------------------------------------------------------ */ +#define CMC_GENERATE_MULTIMAP_HEADER(PFX, SNAME, K, V) \ + \ + /* Multimap Structure */ \ + struct SNAME \ + { \ + /* Array of linked list to entries */ \ + struct SNAME##_entry *(*buffer)[2]; \ + \ + /* Current array capacity */ \ + size_t capacity; \ + \ + /* Current amount of keys */ \ + size_t count; \ + \ + /* Load factor in range (0.0, infinity) */ \ + double load; \ + \ + /* Key comparison functions */ \ + int (*cmp)(K, K); \ + \ + /* Key hash function */ \ + size_t (*hash)(K); \ + \ + /* Function that returns an iterator to the start of the multimap */ \ + struct SNAME##_iter (*it_start)(struct SNAME *); \ + \ + /* Function that returns an iterator to the end of the multimap */ \ + struct SNAME##_iter (*it_end)(struct SNAME *); \ + \ + /* Custom allocation functions */ \ + struct cmc_alloc_node *alloc; \ + \ + /* Custom callback functions */ \ + struct cmc_callbacks_multimap *callbacks; \ + }; \ + \ + /* Multimap Entry */ \ + struct SNAME##_entry \ + { \ + /* Entry Key */ \ + K key; \ + \ + /* Entry Value */ \ + V value; \ + \ + /* Next entry on the linked list */ \ + struct SNAME##_entry *next; \ + \ + /* Previous entry on the linked list */ \ + struct SNAME##_entry *prev; \ + }; \ + \ + struct SNAME##_iter \ + { \ + /* Target multimap */ \ + struct SNAME *target; \ + \ + /* Current entry */ \ + struct SNAME##_entry *curr_entry; \ + \ + /* Cursor`s position (index) */ \ + size_t cursor; \ + \ + /* Keeps track of relative index to the iteration of elements */ \ + size_t index; \ + \ + /* The index of the first element */ \ + size_t first; \ + \ + /* The index of the last element */ \ + size_t last; \ + \ + /* If the iterator has reached the start of the iteration */ \ + bool start; \ + \ + /* If the iterator has reached the end of the iteration */ \ + bool end; \ + }; \ + \ + /* Collection Functions */ \ + /* Collection Allocation and Deallocation */ \ + struct SNAME *PFX##_new(size_t capacity, double load, int (*compare)(K, K), \ + size_t (*hash)(K)); \ + struct SNAME *PFX##_new_custom(size_t capacity, double load, int (*compare)(K, K), \ + size_t (*hash)(K), struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_multimap *callbacks); \ + void PFX##_clear(struct SNAME *_map_, void (*deallocator)(K, V)); \ + void PFX##_free(struct SNAME *_map_, void (*deallocator)(K, V)); \ + /* Customization of Allocation and Callbacks */ \ + void PFX##_customize(struct SNAME *_map_, struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_multimap *callbacks); \ + /* Collection Input and Output */ \ + bool PFX##_insert(struct SNAME *_map_, K key, V value); \ + bool PFX##_update(struct SNAME *_map_, K key, V new_value, V *old_value); \ + size_t PFX##_update_all(struct SNAME *_map_, K key, V new_value, V **old_values); \ + bool PFX##_remove(struct SNAME *_map_, K key, V *out_value); \ + size_t PFX##_remove_all(struct SNAME *_map_, K key, V **out_values); \ + /* Element Access */ \ + bool PFX##_max(struct SNAME *_map_, K *key, V *value); \ + bool PFX##_min(struct SNAME *_map_, K *key, V *value); \ + V PFX##_get(struct SNAME *_map_, K key); \ + V *PFX##_get_ref(struct SNAME *_map_, K key); \ + /* Collection State */ \ + bool PFX##_contains(struct SNAME *_map_, K key); \ + bool PFX##_empty(struct SNAME *_map_); \ + bool PFX##_full(struct SNAME *_map_); \ + size_t PFX##_count(struct SNAME *_map_); \ + size_t PFX##_key_count(struct SNAME *_map_, K key); \ + size_t PFX##_capacity(struct SNAME *_map_); \ + double PFX##_load(struct SNAME *_map_); \ + /* Collection Utility */ \ + bool PFX##_resize(struct SNAME *_map_, size_t capacity); \ + struct SNAME *PFX##_copy_of(struct SNAME *_map_, K (*key_copy_func)(K), \ + V (*value_copy_func)(V)); \ + bool PFX##_equals(struct SNAME *_map1_, struct SNAME *_map2_, bool ignore_key_count); \ + struct cmc_string PFX##_to_string(struct SNAME *_map_); \ + \ + /* Iterator Functions */ \ + /* Iterator Allocation and Deallocation */ \ + struct SNAME##_iter *PFX##_iter_new(struct SNAME *target); \ + void PFX##_iter_free(struct SNAME##_iter *iter); \ + /* Iterator Initialization */ \ + void PFX##_iter_init(struct SNAME##_iter *iter, struct SNAME *target); \ + /* Iterator State */ \ + bool PFX##_iter_start(struct SNAME##_iter *iter); \ + bool PFX##_iter_end(struct SNAME##_iter *iter); \ + /* Iterator Movement */ \ + void PFX##_iter_to_start(struct SNAME##_iter *iter); \ + void PFX##_iter_to_end(struct SNAME##_iter *iter); \ + bool PFX##_iter_next(struct SNAME##_iter *iter); \ + bool PFX##_iter_prev(struct SNAME##_iter *iter); \ + bool PFX##_iter_advance(struct SNAME##_iter *iter, size_t steps); \ + bool PFX##_iter_rewind(struct SNAME##_iter *iter, size_t steps); \ + bool PFX##_iter_go_to(struct SNAME##_iter *iter, size_t index); \ + /* Iterator Access */ \ + K PFX##_iter_key(struct SNAME##_iter *iter); \ + V PFX##_iter_value(struct SNAME##_iter *iter); \ + V *PFX##_iter_rvalue(struct SNAME##_iter *iter); \ + size_t PFX##_iter_index(struct SNAME##_iter *iter); + +/* ------------------------------------------------------------------------------------------------- + * Source + ------------------------------------------------------------------------------------------------ */ +#define CMC_GENERATE_MULTIMAP_SOURCE(PFX, SNAME, K, V) \ + \ + /* Implementation Detail Functions */ \ + struct SNAME##_entry *PFX##_impl_new_entry(K key, V value); \ + struct SNAME##_entry *PFX##_impl_get_entry(struct SNAME *_map_, K key); \ + size_t PFX##_impl_calculate_size(size_t required); \ + static struct SNAME##_iter PFX##_impl_it_start(struct SNAME *_map_); \ + static struct SNAME##_iter PFX##_impl_it_end(struct SNAME *_map_); \ + \ + struct SNAME *PFX##_new(size_t capacity, double load, int (*compare)(K, K), size_t (*hash)(K)) \ + { \ + struct cmc_alloc_node *alloc = &cmc_alloc_node_default; \ + \ + if (capacity == 0 || load <= 0) \ + return NULL; \ + \ + /* Prevent integer overflow */ \ + if (capacity >= UINTMAX_MAX * load) \ + return NULL; \ + \ + size_t real_capacity = PFX##_impl_calculate_size(capacity / load); \ + \ + struct SNAME *_map_ = alloc->malloc(sizeof(struct SNAME)); \ + \ + if (!_map_) \ + return NULL; \ + \ + _map_->buffer = alloc->calloc(real_capacity, sizeof(struct SNAME##_entry * [2])); \ + \ + if (!_map_->buffer) \ + { \ + alloc->free(_map_); \ + return NULL; \ + } \ + \ + _map_->count = 0; \ + _map_->capacity = real_capacity; \ + _map_->load = load; \ + _map_->cmp = compare; \ + _map_->hash = hash; \ + \ + _map_->it_start = PFX##_impl_it_start; \ + _map_->it_end = PFX##_impl_it_end; \ + \ + _map_->alloc = alloc; \ + _map_->callbacks = NULL; \ + \ + return _map_; \ + } \ + \ + struct SNAME *PFX##_new_custom(size_t capacity, double load, int (*compare)(K, K), \ + size_t (*hash)(K), struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_multimap *callbacks) \ + { \ + if (capacity == 0 || load <= 0) \ + return NULL; \ + \ + /* Prevent integer overflow */ \ + if (capacity >= UINTMAX_MAX * load) \ + return NULL; \ + \ + if (!alloc) \ + alloc = &cmc_alloc_node_default; \ + \ + size_t real_capacity = PFX##_impl_calculate_size(capacity / load); \ + \ + struct SNAME *_map_ = alloc->malloc(sizeof(struct SNAME)); \ + \ + if (!_map_) \ + return NULL; \ + \ + _map_->buffer = alloc->calloc(real_capacity, sizeof(struct SNAME##_entry * [2])); \ + \ + if (!_map_->buffer) \ + { \ + alloc->free(_map_); \ + return NULL; \ + } \ + \ + _map_->count = 0; \ + _map_->capacity = real_capacity; \ + _map_->load = load; \ + _map_->cmp = compare; \ + _map_->hash = hash; \ + \ + _map_->it_start = PFX##_impl_it_start; \ + _map_->it_end = PFX##_impl_it_end; \ + \ + _map_->alloc = alloc; \ + _map_->callbacks = callbacks; \ + \ + return _map_; \ + } \ + \ + void PFX##_clear(struct SNAME *_map_, void (*deallocator)(K, V)) \ + { \ + size_t index = 0; \ + struct SNAME##_entry *scan; \ + \ + while (index < _map_->capacity) \ + { \ + scan = _map_->buffer[index][0]; \ + \ + if (scan != NULL) \ + { \ + if (scan->next == NULL && scan->prev == NULL) \ + { \ + if (deallocator) \ + deallocator(scan->key, scan->value); \ + \ + free(scan); \ + } \ + else \ + { \ + while (scan != NULL) \ + { \ + struct SNAME##_entry *tmp = scan; \ + \ + scan = scan->next; \ + \ + if (deallocator) \ + deallocator(tmp->key, tmp->value); \ + \ + free(tmp); \ + } \ + } \ + } \ + \ + index++; \ + } \ + \ + memset(_map_->buffer, 0, sizeof(struct SNAME##_entry * [2]) * _map_->capacity); \ + \ + _map_->count = 0; \ + } \ + \ + void PFX##_free(struct SNAME *_map_, void (*deallocator)(K, V)) \ + { \ + size_t index = 0; \ + struct SNAME##_entry *scan; \ + \ + while (index < _map_->capacity) \ + { \ + scan = _map_->buffer[index][0]; \ + \ + if (scan != NULL) \ + { \ + if (scan->next == NULL && scan->prev == NULL) \ + free(scan); \ + else \ + { \ + while (scan != NULL) \ + { \ + struct SNAME##_entry *tmp = scan; \ + \ + scan = scan->next; \ + \ + if (deallocator) \ + deallocator(tmp->key, tmp->value); \ + \ + free(tmp); \ + } \ + } \ + } \ + \ + index++; \ + } \ + \ + free(_map_->buffer); \ + free(_map_); \ + } \ + \ + void PFX##_customize(struct SNAME *_map_, struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_multimap *callbacks) \ + { \ + if (alloc) \ + _map_->alloc = alloc; \ + \ + if (callbacks) \ + _map_->callbacks = callbacks; \ + } \ + \ + bool PFX##_insert(struct SNAME *_map_, K key, V value) \ + { \ + if (PFX##_full(_map_)) \ + { \ + if (!PFX##_resize(_map_, PFX##_capacity(_map_) + 1)) \ + return false; \ + } \ + \ + size_t hash = _map_->hash(key); \ + size_t pos = hash % _map_->capacity; \ + \ + struct SNAME##_entry *entry = PFX##_impl_new_entry(key, value); \ + \ + if (_map_->buffer[pos][0] == NULL) \ + { \ + _map_->buffer[pos][0] = entry; \ + _map_->buffer[pos][1] = entry; \ + } \ + else \ + { \ + entry->prev = _map_->buffer[pos][1]; \ + \ + _map_->buffer[pos][1]->next = entry; \ + _map_->buffer[pos][1] = entry; \ + } \ + \ + _map_->count++; \ + \ + return true; \ + } \ + \ + bool PFX##_update(struct SNAME *_map_, K key, V new_value, V *old_value) \ + { \ + struct SNAME##_entry *entry = PFX##_impl_get_entry(_map_, key); \ + \ + if (!entry) \ + return false; \ + \ + if (old_value) \ + *old_value = entry->value; \ + \ + entry->value = new_value; \ + \ + return false; \ + } \ + \ + size_t PFX##_update_all(struct SNAME *_map_, K key, V new_value, V **old_values) \ + { \ + size_t total = PFX##_key_count(_map_, key); \ + size_t index = 0; \ + \ + if (total == 0) \ + return total; \ + \ + if (old_values) \ + { \ + *old_values = malloc(sizeof(V) * total); \ + \ + if (!(*old_values)) \ + return false; \ + } \ + \ + size_t hash = _map_->hash(key); \ + \ + struct SNAME##_entry *entry = _map_->buffer[hash % _map_->capacity][0]; \ + \ + while (entry != NULL) \ + { \ + if (_map_->cmp(entry->key, key) == 0) \ + { \ + if (old_values) \ + (*old_values)[index++] = entry->value; \ + \ + entry->value = new_value; \ + } \ + \ + entry = entry->next; \ + } \ + \ + return index; \ + } \ + \ + bool PFX##_remove(struct SNAME *_map_, K key, V *out_value) \ + { \ + size_t hash = _map_->hash(key); \ + \ + struct SNAME##_entry **head = &(_map_->buffer[hash % _map_->capacity][0]); \ + struct SNAME##_entry **tail = &(_map_->buffer[hash % _map_->capacity][1]); \ + \ + if (*head == NULL) \ + return false; \ + \ + struct SNAME##_entry *entry = *head; \ + \ + if (entry->next == NULL && entry->prev == NULL) \ + { \ + if (_map_->cmp(entry->key, key) == 0) \ + { \ + *head = NULL; \ + *tail = NULL; \ + \ + if (out_value) \ + *out_value = entry->value; \ + } \ + else \ + return false; \ + } \ + else \ + { \ + bool found = false; \ + \ + while (entry != NULL) \ + { \ + if (_map_->cmp(entry->key, key) == 0) \ + { \ + if (*head == entry) \ + *head = entry->next; \ + if (*tail == entry) \ + *tail = entry->prev; \ + \ + if (entry->prev != NULL) \ + entry->prev->next = entry->next; \ + if (entry->next != NULL) \ + entry->next->prev = entry->prev; \ + \ + if (out_value) \ + *out_value = entry->value; \ + \ + found = true; \ + \ + break; \ + } \ + else \ + entry = entry->next; \ + } \ + \ + if (!found) \ + return false; \ + } \ + \ + free(entry); \ + \ + _map_->count--; \ + \ + return true; \ + } \ + \ + size_t PFX##_remove_all(struct SNAME *_map_, K key, V **out_values) \ + { \ + size_t hash = _map_->hash(key); \ + \ + struct SNAME##_entry **head = &(_map_->buffer[hash % _map_->capacity][0]); \ + struct SNAME##_entry **tail = &(_map_->buffer[hash % _map_->capacity][1]); \ + \ + if (*head == NULL) \ + return 0; \ + \ + size_t total = PFX##_key_count(_map_, key); \ + size_t index = 0; \ + \ + if (out_values) \ + *out_values = malloc(sizeof(struct SNAME##_entry) * total); \ + \ + struct SNAME##_entry *entry = *head; \ + \ + if (entry->next == NULL) \ + { \ + *head = NULL; \ + *tail = NULL; \ + \ + if (out_values) \ + (*out_values)[index++] = entry->value; \ + \ + free(entry); \ + } \ + else \ + { \ + while (entry != NULL) \ + { \ + if (_map_->cmp(entry->key, key) == 0) \ + { \ + if (*head == entry) \ + *head = entry->next; \ + if (*tail == entry) \ + *tail = entry->prev; \ + \ + struct SNAME##_entry *temp = entry->next; \ + \ + if (entry->prev != NULL) \ + entry->prev->next = entry->next; \ + if (entry->next != NULL) \ + entry->next->prev = entry->prev; \ + \ + if (out_values) \ + (*out_values)[index++] = entry->value; \ + \ + free(entry); \ + \ + entry = temp; \ + } \ + else \ + entry = entry->next; \ + } \ + } \ + \ + _map_->count -= index; \ + \ + return index; \ + } \ + \ + bool PFX##_max(struct SNAME *_map_, K *key, V *value) \ + { \ + if (PFX##_empty(_map_)) \ + return false; \ + \ + struct SNAME##_iter iter; \ + \ + for (PFX##_iter_init(&iter, _map_); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \ + { \ + K result_key = PFX##_iter_key(&iter); \ + V result_value = PFX##_iter_value(&iter); \ + size_t index = PFX##_iter_index(&iter); \ + \ + if (index == 0) \ + { \ + *key = result_key; \ + *value = result_value; \ + } \ + else if (_map_->cmp(result_key, *key) > 0) \ + { \ + *key = result_key; \ + *value = result_value; \ + } \ + } \ + \ + return true; \ + } \ + \ + bool PFX##_min(struct SNAME *_map_, K *key, V *value) \ + { \ + if (PFX##_empty(_map_)) \ + return false; \ + \ + struct SNAME##_iter iter; \ + \ + for (PFX##_iter_init(&iter, _map_); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \ + { \ + K result_key = PFX##_iter_key(&iter); \ + V result_value = PFX##_iter_value(&iter); \ + size_t index = PFX##_iter_index(&iter); \ + \ + if (index == 0) \ + { \ + *key = result_key; \ + *value = result_value; \ + } \ + else if (_map_->cmp(result_key, *key) < 0) \ + { \ + *key = result_key; \ + *value = result_value; \ + } \ + } \ + \ + return true; \ + } \ + \ + V PFX##_get(struct SNAME *_map_, K key) \ + { \ + struct SNAME##_entry *entry = PFX##_impl_get_entry(_map_, key); \ + \ + if (!entry) \ + return (V){0}; \ + \ + return entry->value; \ + } \ + \ + V *PFX##_get_ref(struct SNAME *_map_, K key) \ + { \ + struct SNAME##_entry *entry = PFX##_impl_get_entry(_map_, key); \ + \ + if (!entry) \ + return NULL; \ + \ + return &(entry->value); \ + } \ + \ + bool PFX##_contains(struct SNAME *_map_, K key) \ + { \ + return PFX##_impl_get_entry(_map_, key) != NULL; \ + } \ + \ + bool PFX##_empty(struct SNAME *_map_) \ + { \ + return _map_->count == 0; \ + } \ + \ + bool PFX##_full(struct SNAME *_map_) \ + { \ + return (double)PFX##_capacity(_map_) * PFX##_load(_map_) <= (double)PFX##_count(_map_); \ + } \ + \ + size_t PFX##_count(struct SNAME *_map_) \ + { \ + return _map_->count; \ + } \ + \ + size_t PFX##_key_count(struct SNAME *_map_, K key) \ + { \ + size_t hash = _map_->hash(key); \ + \ + struct SNAME##_entry *entry = _map_->buffer[hash % _map_->capacity][0]; \ + \ + size_t total_count = 0; \ + \ + if (!entry) \ + return total_count; \ + \ + while (entry != NULL) \ + { \ + if (_map_->cmp(entry->key, key) == 0) \ + total_count++; \ + \ + entry = entry->next; \ + } \ + \ + return total_count; \ + } \ + \ + size_t PFX##_capacity(struct SNAME *_map_) \ + { \ + return _map_->capacity; \ + } \ + \ + double PFX##_load(struct SNAME *_map_) \ + { \ + return _map_->load; \ + } \ + \ + bool PFX##_resize(struct SNAME *_map_, size_t capacity) \ + { \ + if (PFX##_capacity(_map_) == capacity) \ + return true; \ + \ + if (PFX##_capacity(_map_) > capacity / PFX##_load(_map_)) \ + return true; \ + \ + /* Prevent integer overflow */ \ + if (capacity >= UINTMAX_MAX * PFX##_load(_map_)) \ + return false; \ + \ + /* Calculate required capacity based on the prime numbers */ \ + size_t theoretical_size = PFX##_impl_calculate_size(capacity); \ + \ + /* Not possible to shrink with current available prime numbers */ \ + if (theoretical_size < PFX##_count(_map_) / PFX##_load(_map_)) \ + return false; \ + \ + struct SNAME *_new_map_ = PFX##_new(capacity, PFX##_load(_map_), _map_->cmp, _map_->hash); \ + \ + if (!_new_map_) \ + return false; \ + \ + struct SNAME##_iter iter; \ + \ + for (PFX##_iter_init(&iter, _map_); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \ + { \ + K key = PFX##_iter_key(&iter); \ + V value = PFX##_iter_value(&iter); \ + \ + PFX##_insert(_new_map_, key, value); \ + } \ + \ + if (PFX##_count(_map_) != PFX##_count(_new_map_)) \ + { \ + PFX##_free(_new_map_, NULL); \ + return false; \ + } \ + \ + struct SNAME##_entry *(*tmp_b)[2] = _map_->buffer; \ + _map_->buffer = _new_map_->buffer; \ + _new_map_->buffer = tmp_b; \ + \ + size_t tmp_c = _map_->capacity; \ + _map_->capacity = _new_map_->capacity; \ + _new_map_->capacity = tmp_c; \ + \ + PFX##_free(_new_map_, NULL); \ + \ + return true; \ + } \ + \ + struct SNAME *PFX##_copy_of(struct SNAME *_map_, K (*key_copy_func)(K), \ + V (*value_copy_func)(V)) \ + { \ + struct SNAME *result = PFX##_new(_map_->capacity, _map_->load, _map_->cmp, _map_->hash); \ + \ + if (!result) \ + return NULL; \ + \ + struct SNAME##_iter iter; \ + PFX##_iter_init(&iter, _map_); \ + \ + if (!PFX##_empty(_map_)) \ + { \ + for (PFX##_iter_to_start(&iter); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \ + { \ + K key = PFX##_iter_key(&iter); \ + V value = PFX##_iter_value(&iter); \ + \ + if (key_copy_func) \ + key = key_copy_func(key); \ + if (value_copy_func) \ + value = value_copy_func(value); \ + \ + PFX##_insert(result, key, value); \ + } \ + } \ + \ + return result; \ + } \ + \ + bool PFX##_equals(struct SNAME *_map1_, struct SNAME *_map2_, bool ignore_key_count) \ + { \ + if (ignore_key_count) \ + { \ + struct SNAME##_iter iter; \ + PFX##_iter_init(&iter, _map1_); \ + \ + for (PFX##_iter_to_start(&iter); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \ + { \ + if (PFX##_impl_get_entry(_map2_, PFX##_iter_key(&iter)) == NULL) \ + return false; \ + } \ + } \ + else \ + { \ + /* Since the key count matters this can be checked and an early exit */ \ + if (PFX##_count(_map1_) != PFX##_count(_map2_)) \ + return false; \ + \ + struct SNAME##_iter iter; \ + PFX##_iter_init(&iter, _map1_); \ + \ + for (PFX##_iter_to_start(&iter); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \ + { \ + K key = PFX##_iter_key(&iter); \ + \ + if (PFX##_key_count(_map1_, key) != PFX##_key_count(_map2_, key)) \ + return false; \ + } \ + } \ + \ + return true; \ + } \ + \ + struct cmc_string PFX##_to_string(struct SNAME *_map_) \ + { \ + struct cmc_string str; \ + struct SNAME *m_ = _map_; \ + \ + int n = snprintf(str.s, cmc_string_len, cmc_string_fmt_multimap, \ + #SNAME, #K, #V, m_, m_->buffer, m_->capacity, m_->count, \ + m_->load, m_->cmp, m_->hash, m_->alloc, m_->callbacks); \ + \ + if (n < 0 || n == (int)cmc_string_len) \ + return (struct cmc_string){0}; \ + \ + str.s[n] = '\0'; \ + \ + return str; \ + } \ + \ + struct SNAME##_iter *PFX##_iter_new(struct SNAME *target) \ + { \ + struct SNAME##_iter *iter = malloc(sizeof(struct SNAME##_iter)); \ + \ + if (!iter) \ + return NULL; \ + \ + PFX##_iter_init(iter, target); \ + \ + return iter; \ + } \ + \ + void PFX##_iter_free(struct SNAME##_iter *iter) \ + { \ + free(iter); \ + } \ + \ + void PFX##_iter_init(struct SNAME##_iter *iter, struct SNAME *target) \ + { \ + memset(iter, 0, sizeof(struct SNAME##_iter)); \ + \ + iter->target = target; \ + iter->start = true; \ + iter->end = PFX##_empty(target); \ + \ + if (!PFX##_empty(target)) \ + { \ + for (size_t i = 0; i < target->capacity; i++) \ + { \ + if (target->buffer[i][0] != NULL) \ + { \ + iter->curr_entry = target->buffer[i][0]; \ + iter->first = i; \ + break; \ + } \ + } \ + \ + iter->cursor = iter->first; \ + \ + for (size_t i = target->capacity; i > 0; i--) \ + { \ + if (target->buffer[i - 1][0] != NULL) \ + { \ + iter->last = i - 1; \ + break; \ + } \ + } \ + } \ + } \ + \ + bool PFX##_iter_start(struct SNAME##_iter *iter) \ + { \ + return PFX##_empty(iter->target) || iter->start; \ + } \ + \ + bool PFX##_iter_end(struct SNAME##_iter *iter) \ + { \ + return PFX##_empty(iter->target) || iter->end; \ + } \ + \ + void PFX##_iter_to_start(struct SNAME##_iter *iter) \ + { \ + if (!PFX##_empty(iter->target)) \ + { \ + iter->cursor = iter->first; \ + iter->index = 0; \ + iter->start = true; \ + iter->end = PFX##_empty(iter->target); \ + iter->curr_entry = iter->target->buffer[iter->first][0]; \ + } \ + } \ + \ + void PFX##_iter_to_end(struct SNAME##_iter *iter) \ + { \ + if (!PFX##_empty(iter->target)) \ + { \ + iter->cursor = iter->last; \ + iter->index = iter->target->count - 1; \ + iter->start = PFX##_empty(iter->target); \ + iter->end = true; \ + iter->curr_entry = iter->target->buffer[iter->last][1]; \ + } \ + } \ + \ + bool PFX##_iter_next(struct SNAME##_iter *iter) \ + { \ + if (iter->end) \ + return false; \ + \ + if (iter->curr_entry->next != NULL) \ + { \ + iter->curr_entry = iter->curr_entry->next; \ + iter->index++; \ + } \ + else \ + { \ + if (iter->cursor == iter->last) \ + { \ + iter->end = true; \ + return false; \ + } \ + \ + iter->cursor++; \ + \ + while (iter->target->buffer[iter->cursor][0] == NULL) \ + iter->cursor++; \ + \ + iter->curr_entry = iter->target->buffer[iter->cursor][0]; \ + \ + iter->index++; \ + } \ + \ + iter->start = PFX##_empty(iter->target); \ + \ + return true; \ + } \ + \ + bool PFX##_iter_prev(struct SNAME##_iter *iter) \ + { \ + if (iter->start) \ + return false; \ + \ + if (iter->curr_entry->prev != NULL) \ + { \ + iter->curr_entry = iter->curr_entry->prev; \ + iter->index--; \ + } \ + else \ + { \ + if (iter->cursor == iter->first) \ + { \ + iter->start = true; \ + return false; \ + } \ + \ + iter->cursor--; \ + \ + while (iter->target->buffer[iter->cursor][1] == NULL) \ + iter->cursor--; \ + \ + iter->curr_entry = iter->target->buffer[iter->cursor][1]; \ + \ + iter->index--; \ + } \ + \ + iter->end = PFX##_empty(iter->target); \ + \ + return true; \ + } \ + \ + /* Returns true only if the iterator moved */ \ + bool PFX##_iter_advance(struct SNAME##_iter *iter, size_t steps) \ + { \ + if (iter->end) \ + return false; \ + \ + if (iter->index + 1 == PFX##_count(iter->target)) \ + { \ + iter->end = true; \ + return false; \ + } \ + \ + if (steps == 0 || iter->index + steps >= PFX##_count(iter->target)) \ + return false; \ + \ + for (size_t i = 0; i < steps; i++) \ + PFX##_iter_next(iter); \ + \ + return true; \ + } \ + \ + /* Returns true only if the iterator moved */ \ + bool PFX##_iter_rewind(struct SNAME##_iter *iter, size_t steps) \ + { \ + if (iter->start) \ + return false; \ + \ + if (iter->index == 0) \ + { \ + iter->start = true; \ + return false; \ + } \ + \ + if (steps == 0 || iter->index < steps) \ + return false; \ + \ + for (size_t i = 0; i < steps; i++) \ + PFX##_iter_prev(iter); \ + \ + return true; \ + } \ + \ + /* Returns true only if the iterator was able to be positioned at the given index */ \ + bool PFX##_iter_go_to(struct SNAME##_iter *iter, size_t index) \ + { \ + if (index >= PFX##_count(iter->target)) \ + return false; \ + \ + if (iter->index > index) \ + return PFX##_iter_rewind(iter, iter->index - index); \ + else if (iter->index < index) \ + return PFX##_iter_advance(iter, index - iter->index); \ + \ + return true; \ + } \ + \ + K PFX##_iter_key(struct SNAME##_iter *iter) \ + { \ + if (PFX##_empty(iter->target)) \ + return (K){0}; \ + \ + return iter->curr_entry->key; \ + } \ + \ + V PFX##_iter_value(struct SNAME##_iter *iter) \ + { \ + if (PFX##_empty(iter->target)) \ + return (V){0}; \ + \ + return iter->curr_entry->value; \ + } \ + \ + V *PFX##_iter_rvalue(struct SNAME##_iter *iter) \ + { \ + if (PFX##_empty(iter->target)) \ + return NULL; \ + \ + return &(iter->curr_entry->value); \ + } \ + \ + size_t PFX##_iter_index(struct SNAME##_iter *iter) \ + { \ + return iter->index; \ + } \ + \ + struct SNAME##_entry *PFX##_impl_new_entry(K key, V value) \ + { \ + struct SNAME##_entry *entry = malloc(sizeof(struct SNAME##_entry)); \ + \ + if (!entry) \ + return NULL; \ + \ + entry->key = key; \ + entry->value = value; \ + entry->next = NULL; \ + entry->prev = NULL; \ + \ + return entry; \ + } \ + \ + struct SNAME##_entry *PFX##_impl_get_entry(struct SNAME *_map_, K key) \ + { \ + size_t hash = _map_->hash(key); \ + \ + struct SNAME##_entry *entry = _map_->buffer[hash % _map_->capacity][0]; \ + \ + while (entry != NULL) \ + { \ + if (_map_->cmp(entry->key, key) == 0) \ + return entry; \ + \ + entry = entry->next; \ + } \ + \ + return NULL; \ + } \ + \ + size_t PFX##_impl_calculate_size(size_t required) \ + { \ + const size_t count = sizeof(cmc_hashtable_primes) / sizeof(cmc_hashtable_primes[0]); \ + \ + if (cmc_hashtable_primes[count - 1] < required) \ + return required; \ + \ + size_t i = 0; \ + while (cmc_hashtable_primes[i] < required) \ + i++; \ + \ + return cmc_hashtable_primes[i]; \ + } \ + \ + static struct SNAME##_iter PFX##_impl_it_start(struct SNAME *_map_) \ + { \ + struct SNAME##_iter iter; \ + \ + PFX##_iter_init(&iter, _map_); \ + \ + return iter; \ + } \ + \ + static struct SNAME##_iter PFX##_impl_it_end(struct SNAME *_map_) \ + { \ + struct SNAME##_iter iter; \ + \ + PFX##_iter_init(&iter, _map_); \ + PFX##_iter_to_end(&iter); \ + \ + return iter; \ } #endif /* CMC_MULTIMAP_H */ diff --git a/src/cmc/multiset.h b/src/cmc/multiset.h index fc452ea..79f3c83 100644 --- a/src/cmc/multiset.h +++ b/src/cmc/multiset.h @@ -26,11 +26,43 @@ #include #include #include -#include "../utl/cmc_string.h" -/* to_string format */ -static const char *cmc_string_fmt_multiset = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", cardinality:%" PRIuMAX ", load:%lf, cmp:%p, hash:%p }"; +/* ------------------------------------------------------------------------------------------------- + * Core functionalities of the C Macro Collections Library + ------------------------------------------------------------------------------------------------ */ +#ifndef CMC_CORE_H +#define CMC_CORE_H +/** + * struct cmc_string + * + * Used by all collections when calling the to_string function. + */ +struct cmc_string +{ + char s[400]; +}; + +static const size_t cmc_string_len = 400; + +/** + * struct cmc_alloc_node + * + * Custom allocation node. Allows collections to use custom allocation functions. + */ +struct cmc_alloc_node +{ + void *(*malloc)(size_t); + void *(*calloc)(size_t, size_t); + void *(*realloc)(void *, size_t); + void (*free)(void *); +} cmc_alloc_node_default = {malloc, calloc, realloc, free}; + +#endif /* CMC_CORE_H */ + +/* ------------------------------------------------------------------------------------------------- + * Hashtable Implementation + ------------------------------------------------------------------------------------------------ */ #ifndef CMC_IMPL_HASHTABLE_STATE #define CMC_IMPL_HASHTABLE_STATE @@ -43,42 +75,52 @@ enum cmc_entry_state #endif /* CMC_IMPL_HASHTABLE_STATE */ -#ifndef CMC_IMPL_HASHTABLE_SETUP -#define CMC_IMPL_HASHTABLE_SETUP +#ifndef CMC_IMPL_HASHTABLE_PRIMES +#define CMC_IMPL_HASHTABLE_PRIMES -static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, - 3067, 6143, 12289, 24571, 49157, - 98299, 196613, 393209, 786431, - 1572869, 3145721, 6291449, - 12582917, 25165813, 50331653, - 100663291, 201326611, 402653189, - 805306357, 1610612741, - 3221225473, 6442450939, - 12884901893, 25769803799, - 51539607551, 103079215111, - 206158430209, 412316860441, - 824633720831, 1649267441651, - 3298534883309, 6597069766657, - 13194139533299, 26388279066623, - 52776558133303, 105553116266489, - 211106232532969, 422212465066001, - 844424930131963, - 1688849860263953, - 3377699720527861, - 6755399441055731, - 13510798882111483, - 27021597764222939, - 54043195528445957, - 108086391056891903, - 216172782113783773, - 432345564227567621, - 864691128455135207, - 1729382256910270481, - 3458764513820540933, - 6917529027641081903, - 13835058055282163729llu}; +static const size_t cmc_hashtable_primes[] = + {53, 97, 191, 383, 769, 1531, 3067, 6143, 12289, 24571, 49157, 98299, 196613, 393209, 786431, + 1572869, 3145721, 6291449, 12582917, 25165813, 50331653, 100663291, 201326611, 402653189, + 805306357, 1610612741, 3221225473, 6442450939, 12884901893, 25769803799, 51539607551, + 103079215111, 206158430209, 412316860441, 824633720831, 1649267441651, 3298534883309, + 6597069766657, 13194139533299, 26388279066623, 52776558133303, 105553116266489, + 211106232532969, 422212465066001, 844424930131963, 1688849860263953, 3377699720527861, + 6755399441055731, 13510798882111483, 27021597764222939, 54043195528445957, 108086391056891903, + 216172782113783773, 432345564227567621, 864691128455135207, 1729382256910270481, + 3458764513820540933, 6917529027641081903, 13835058055282163729llu}; -#endif /* CMC_IMPL_HASHTABLE_SETUP */ +#endif /* CMC_IMPL_HASHTABLE_PRIMES */ + +/* ------------------------------------------------------------------------------------------------- + * MultiSet specific + ------------------------------------------------------------------------------------------------ */ +/* to_string format */ +static const char *cmc_string_fmt_multiset = "struct %s<%s> " + "at %p { " + "buffer:%p, " + "capacity:%" PRIuMAX ", " + "count:%" PRIuMAX ", " + "cardinality:%" PRIuMAX ", " + "load:%lf, " + "cmp:%p, " + "hash:%p, " + "alloc:%p, " + "callbacks:%p }"; + +/** + * Custom MultiSet callbacks. + * + * There are two types of callbacks, 'before' and 'after': + * _ + */ +struct cmc_callbacks_multiset +{ + void (*before_clear)(void *); + void (*after_clear)(void *); + void (*before_free)(void *); + void (*after_free)(void *); + // TODO implement all callbacks +}; #define CMC_GENERATE_MULTISET(PFX, SNAME, V) \ CMC_GENERATE_MULTISET_HEADER(PFX, SNAME, V) \ @@ -90,7 +132,9 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, #define CMC_WRAPGEN_MULTISET_SOURCE(PFX, SNAME, K, V) \ CMC_GENERATE_MULTISET_SOURCE(PFX, SNAME, V) -/* HEADER ********************************************************************/ +/* ------------------------------------------------------------------------------------------------- + * Header + ------------------------------------------------------------------------------------------------ */ #define CMC_GENERATE_MULTISET_HEADER(PFX, SNAME, V) \ \ /* Hashset Structure */ \ @@ -122,6 +166,12 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, \ /* Function that returns an iterator to the end of the hashset */ \ struct SNAME##_iter (*it_end)(struct SNAME *); \ + \ + /* Custom allocation functions */ \ + struct cmc_alloc_node *alloc; \ + \ + /* Custom callback functions */ \ + struct cmc_callbacks_multiset *callbacks; \ }; \ \ struct SNAME##_entry \ @@ -168,8 +218,14 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, /* Collection Allocation and Deallocation */ \ struct SNAME *PFX##_new(size_t capacity, double load, int (*compare)(V, V), \ size_t (*hash)(V)); \ + struct SNAME *PFX##_new_custom(size_t capacity, double load, int (*compare)(V, V), \ + size_t (*hash)(V), struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_multiset *callbacks); \ void PFX##_clear(struct SNAME *_set_, void (*deallocator)(V)); \ void PFX##_free(struct SNAME *_set_, void (*deallocator)(V)); \ + /* Customization of Allocation and Callbacks */ \ + void PFX##_customize(struct SNAME *_set_, struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_multiset *callbacks); \ /* Collection Input and Output */ \ bool PFX##_insert(struct SNAME *_set_, V element); \ bool PFX##_insert_many(struct SNAME *_set_, V element, size_t count); \ @@ -226,9 +282,11 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, /* Iterator Access */ \ V PFX##_iter_value(struct SNAME##_iter *iter); \ size_t PFX##_iter_multiplicity(struct SNAME##_iter *iter); \ - size_t PFX##_iter_index(struct SNAME##_iter *iter); \ - \ -/* SOURCE ********************************************************************/ + size_t PFX##_iter_index(struct SNAME##_iter *iter); + +/* ------------------------------------------------------------------------------------------------- + * Source + ------------------------------------------------------------------------------------------------ */ #define CMC_GENERATE_MULTISET_SOURCE(PFX, SNAME, V) \ \ /* Implementation Detail Functions */ \ @@ -241,6 +299,8 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, \ struct SNAME *PFX##_new(size_t capacity, double load, int (*compare)(V, V), size_t (*hash)(V)) \ { \ + struct cmc_alloc_node *alloc = &cmc_alloc_node_default; \ + \ if (capacity == 0 || load <= 0 || load >= 1) \ return NULL; \ \ @@ -250,16 +310,16 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, \ size_t real_capacity = PFX##_impl_calculate_size(capacity / load); \ \ - struct SNAME *_set_ = malloc(sizeof(struct SNAME)); \ + struct SNAME *_set_ = alloc->malloc(sizeof(struct SNAME)); \ \ if (!_set_) \ return NULL; \ \ - _set_->buffer = calloc(real_capacity, sizeof(struct SNAME##_entry)); \ + _set_->buffer = alloc->calloc(real_capacity, sizeof(struct SNAME##_entry)); \ \ if (!_set_->buffer) \ { \ - free(_set_); \ + alloc->free(_set_); \ return NULL; \ } \ \ @@ -273,6 +333,54 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, _set_->it_start = PFX##_impl_it_start; \ _set_->it_end = PFX##_impl_it_end; \ \ + _set_->alloc = alloc; \ + _set_->callbacks = NULL; \ + \ + return _set_; \ + } \ + \ + struct SNAME *PFX##_new_custom(size_t capacity, double load, int (*compare)(V, V), \ + size_t (*hash)(V), struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_multiset *callbacks) \ + { \ + if (capacity == 0 || load <= 0 || load >= 1) \ + return NULL; \ + \ + /* Prevent integer overflow */ \ + if (capacity >= UINTMAX_MAX * load) \ + return NULL; \ + \ + size_t real_capacity = PFX##_impl_calculate_size(capacity / load); \ + \ + if (!alloc) \ + alloc = &cmc_alloc_node_default; \ + \ + struct SNAME *_set_ = alloc->malloc(sizeof(struct SNAME)); \ + \ + if (!_set_) \ + return NULL; \ + \ + _set_->buffer = alloc->calloc(real_capacity, sizeof(struct SNAME##_entry)); \ + \ + if (!_set_->buffer) \ + { \ + alloc->free(_set_); \ + return NULL; \ + } \ + \ + _set_->count = 0; \ + _set_->cardinality = 0; \ + _set_->capacity = real_capacity; \ + _set_->load = load; \ + _set_->cmp = compare; \ + _set_->hash = hash; \ + \ + _set_->it_start = PFX##_impl_it_start; \ + _set_->it_end = PFX##_impl_it_end; \ + \ + _set_->alloc = alloc; \ + _set_->callbacks = callbacks; \ + \ return _set_; \ } \ \ @@ -315,6 +423,16 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, free(_set_); \ } \ \ + void PFX##_customize(struct SNAME *_set_, struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_multiset *callbacks) \ + { \ + if (alloc) \ + _set_->alloc = alloc; \ + \ + if (callbacks) \ + _set_->callbacks = callbacks; \ + } \ + \ bool PFX##_insert(struct SNAME *_set_, V element) \ { \ bool new_node; \ @@ -628,11 +746,16 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, { \ struct cmc_string str; \ struct SNAME *s_ = _set_; \ - const char *name = #SNAME; \ \ - snprintf(str.s, cmc_string_len, cmc_string_fmt_multiset, \ - name, s_, s_->buffer, s_->capacity, s_->count, \ - s_->cardinality, s_->load, s_->cmp, s_->hash); \ + int n = snprintf(str.s, cmc_string_len, cmc_string_fmt_multiset, \ + #SNAME, #V, s_, s_->buffer, s_->capacity, s_->count, \ + s_->cardinality, s_->load, s_->cmp, s_->hash, \ + s_->alloc, s_->callbacks); \ + \ + if (n < 0 || n == (int)cmc_string_len) \ + return (struct cmc_string){0}; \ + \ + str.s[n] = '\0'; \ \ return str; \ } \ diff --git a/src/cmc/queue.h b/src/cmc/queue.h index ed0487c..ee92cd8 100644 --- a/src/cmc/queue.h +++ b/src/cmc/queue.h @@ -48,10 +48,68 @@ #include #include #include -#include "../utl/cmc_string.h" +/* ------------------------------------------------------------------------------------------------- + * Core functionalities of the C Macro Collections Library + ------------------------------------------------------------------------------------------------ */ +#ifndef CMC_CORE_H +#define CMC_CORE_H + +/** + * struct cmc_string + * + * Used by all collections when calling the to_string function. + */ +struct cmc_string +{ + char s[400]; +}; + +static const size_t cmc_string_len = 400; + +/** + * struct cmc_alloc_node + * + * Custom allocation node. Allows collections to use custom allocation functions. + */ +struct cmc_alloc_node +{ + void *(*malloc)(size_t); + void *(*calloc)(size_t, size_t); + void *(*realloc)(void *, size_t); + void (*free)(void *); +} cmc_alloc_node_default = {malloc, calloc, realloc, free}; + +#endif /* CMC_CORE_H */ + +/* ------------------------------------------------------------------------------------------------- + * Queue specific + ------------------------------------------------------------------------------------------------ */ /* to_string format */ -static const char *cmc_string_fmt_queue = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", front:%" PRIuMAX ", back:%" PRIuMAX " }"; +static const char *cmc_string_fmt_queue = "struct %s<%s> " + "at %p { " + "buffer:%p, " + "capacity:%" PRIuMAX ", " + "count:%" PRIuMAX ", " + "front:%" PRIuMAX ", " + "back:%" PRIuMAX ", " + "alloc:%p, " + "callbacks:%p }"; + +/** + * Custom Queue callbacks. + * + * There are two types of callbacks, 'before' and 'after': + * _ + */ +struct cmc_callbacks_queue +{ + void (*before_clear)(void *); + void (*after_clear)(void *); + void (*before_free)(void *); + void (*after_free)(void *); + // TODO implement all callbacks +}; #define CMC_GENERATE_QUEUE(PFX, SNAME, V) \ CMC_GENERATE_QUEUE_HEADER(PFX, SNAME, V) \ @@ -63,7 +121,9 @@ static const char *cmc_string_fmt_queue = "%s at %p { buffer:%p, capacity:%" PRI #define CMC_WRAPGEN_QUEUE_SOURCE(PFX, SNAME, K, V) \ CMC_GENERATE_QUEUE_SOURCE(PFX, SNAME, V) -/* HEADER ********************************************************************/ +/* ------------------------------------------------------------------------------------------------- + * Header + ------------------------------------------------------------------------------------------------ */ #define CMC_GENERATE_QUEUE_HEADER(PFX, SNAME, V) \ \ /* Queue Structure */ \ @@ -89,6 +149,12 @@ static const char *cmc_string_fmt_queue = "%s at %p { buffer:%p, capacity:%" PRI \ /* Function that returns an iterator to the end of the queue */ \ struct SNAME##_iter (*it_end)(struct SNAME *); \ + \ + /* Custom allocation functions */ \ + struct cmc_alloc_node *alloc; \ + \ + /* Custom callback functions */ \ + struct cmc_callbacks_queue *callbacks; \ }; \ \ /* Queue Iterator */ \ @@ -113,8 +179,13 @@ static const char *cmc_string_fmt_queue = "%s at %p { buffer:%p, capacity:%" PRI /* Collection Functions */ \ /* Collection Allocation and Deallocation */ \ struct SNAME *PFX##_new(size_t capacity); \ + struct SNAME *PFX##_new_custom(size_t capacity, struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_queue *callbacks); \ void PFX##_clear(struct SNAME *_queue_, void (*deallocator)(V)); \ void PFX##_free(struct SNAME *_queue_, void (*deallocator)(V)); \ + /* Customization of Allocation and Callbacks */ \ + void PFX##_customize(struct SNAME *_queue_, struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_queue *callbacks); \ /* Collection Input and Output */ \ bool PFX##_enqueue(struct SNAME *_queue_, V element); \ bool PFX##_dequeue(struct SNAME *_queue_); \ @@ -152,9 +223,11 @@ static const char *cmc_string_fmt_queue = "%s at %p { buffer:%p, capacity:%" PRI /* Iterator Access */ \ V PFX##_iter_value(struct SNAME##_iter *iter); \ V *PFX##_iter_rvalue(struct SNAME##_iter *iter); \ - size_t PFX##_iter_index(struct SNAME##_iter *iter); \ - \ -/* SOURCE ********************************************************************/ + size_t PFX##_iter_index(struct SNAME##_iter *iter); + +/* ------------------------------------------------------------------------------------------------- + * Source + ------------------------------------------------------------------------------------------------ */ #define CMC_GENERATE_QUEUE_SOURCE(PFX, SNAME, V) \ \ /* Implementation Detail Functions */ \ @@ -163,19 +236,21 @@ static const char *cmc_string_fmt_queue = "%s at %p { buffer:%p, capacity:%" PRI \ struct SNAME *PFX##_new(size_t capacity) \ { \ + struct cmc_alloc_node *alloc = &cmc_alloc_node_default; \ + \ if (capacity < 1) \ return NULL; \ \ - struct SNAME *_queue_ = malloc(sizeof(struct SNAME)); \ + struct SNAME *_queue_ = alloc->malloc(sizeof(struct SNAME)); \ \ if (!_queue_) \ return NULL; \ \ - _queue_->buffer = calloc(capacity, sizeof(V)); \ + _queue_->buffer = alloc->calloc(capacity, sizeof(V)); \ \ if (!_queue_->buffer) \ { \ - free(_queue_); \ + alloc->free(_queue_); \ return NULL; \ } \ \ @@ -187,6 +262,45 @@ static const char *cmc_string_fmt_queue = "%s at %p { buffer:%p, capacity:%" PRI _queue_->it_start = PFX##_impl_it_start; \ _queue_->it_end = PFX##_impl_it_end; \ \ + _queue_->alloc = alloc; \ + _queue_->callbacks = NULL; \ + \ + return _queue_; \ + } \ + \ + struct SNAME *PFX##_new_custom(size_t capacity, struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_queue *callbacks) \ + { \ + if (capacity < 1) \ + return NULL; \ + \ + if (!alloc) \ + alloc = &cmc_alloc_node_default; \ + \ + struct SNAME *_queue_ = alloc->malloc(sizeof(struct SNAME)); \ + \ + if (!_queue_) \ + return NULL; \ + \ + _queue_->buffer = alloc->calloc(capacity, sizeof(V)); \ + \ + if (!_queue_->buffer) \ + { \ + alloc->free(_queue_); \ + return NULL; \ + } \ + \ + _queue_->capacity = capacity; \ + _queue_->count = 0; \ + _queue_->front = 0; \ + _queue_->back = 0; \ + \ + _queue_->it_start = PFX##_impl_it_start; \ + _queue_->it_end = PFX##_impl_it_end; \ + \ + _queue_->alloc = alloc; \ + _queue_->callbacks = callbacks; \ + \ return _queue_; \ } \ \ @@ -221,8 +335,18 @@ static const char *cmc_string_fmt_queue = "%s at %p { buffer:%p, capacity:%" PRI } \ } \ \ - free(_queue_->buffer); \ - free(_queue_); \ + _queue_->alloc->free(_queue_->buffer); \ + _queue_->alloc->free(_queue_); \ + } \ + \ + void PFX##_customize(struct SNAME *_queue_, struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_queue *callbacks) \ + { \ + if (alloc) \ + _queue_->alloc = alloc; \ + \ + if (callbacks) \ + _queue_->callbacks = callbacks; \ } \ \ bool PFX##_enqueue(struct SNAME *_queue_, V element) \ @@ -303,7 +427,7 @@ static const char *cmc_string_fmt_queue = "%s at %p { buffer:%p, capacity:%" PRI if (capacity < PFX##_count(_queue_)) \ return false; \ \ - V *new_buffer = malloc(sizeof(V) * capacity); \ + V *new_buffer = _queue_->alloc->malloc(sizeof(V) * capacity); \ \ if (!new_buffer) \ return false; \ @@ -315,7 +439,7 @@ static const char *cmc_string_fmt_queue = "%s at %p { buffer:%p, capacity:%" PRI i = (i + 1) % PFX##_capacity(_queue_); \ } \ \ - free(_queue_->buffer); \ + _queue_->alloc->free(_queue_->buffer); \ \ _queue_->buffer = new_buffer; \ _queue_->capacity = capacity; \ @@ -378,17 +502,22 @@ static const char *cmc_string_fmt_queue = "%s at %p { buffer:%p, capacity:%" PRI { \ struct cmc_string str; \ struct SNAME *q_ = _queue_; \ - const char *name = #SNAME; \ \ - snprintf(str.s, cmc_string_len, cmc_string_fmt_queue, \ - name, q_, q_->buffer, q_->capacity, q_->count, q_->front, q_->back); \ + int n = snprintf(str.s, cmc_string_len, cmc_string_fmt_queue, \ + #SNAME, #V, q_, q_->buffer, q_->capacity, q_->count, \ + q_->front, q_->back, q_->alloc, q_->callbacks); \ + \ + if (n < 0 || n == (int)cmc_string_len) \ + return (struct cmc_string){0}; \ + \ + str.s[n] = '\0'; \ \ return str; \ } \ \ struct SNAME##_iter *PFX##_iter_new(struct SNAME *target) \ { \ - struct SNAME##_iter *iter = malloc(sizeof(struct SNAME##_iter)); \ + struct SNAME##_iter *iter = target->alloc->malloc(sizeof(struct SNAME##_iter)); \ \ if (!iter) \ return NULL; \ @@ -400,7 +529,7 @@ static const char *cmc_string_fmt_queue = "%s at %p { buffer:%p, capacity:%" PRI \ void PFX##_iter_free(struct SNAME##_iter *iter) \ { \ - free(iter); \ + iter->target->alloc->free(iter); \ } \ \ void PFX##_iter_init(struct SNAME##_iter *iter, struct SNAME *target) \ diff --git a/src/cmc/sortedlist.h b/src/cmc/sortedlist.h index 9253e40..e67339c 100644 --- a/src/cmc/sortedlist.h +++ b/src/cmc/sortedlist.h @@ -27,10 +27,68 @@ #include #include #include -#include "../utl/cmc_string.h" +/* ------------------------------------------------------------------------------------------------- + * Core functionalities of the C Macro Collections Library + ------------------------------------------------------------------------------------------------ */ +#ifndef CMC_CORE_H +#define CMC_CORE_H + +/** + * struct cmc_string + * + * Used by all collections when calling the to_string function. + */ +struct cmc_string +{ + char s[400]; +}; + +static const size_t cmc_string_len = 400; + +/** + * struct cmc_alloc_node + * + * Custom allocation node. Allows collections to use custom allocation functions. + */ +struct cmc_alloc_node +{ + void *(*malloc)(size_t); + void *(*calloc)(size_t, size_t); + void *(*realloc)(void *, size_t); + void (*free)(void *); +} cmc_alloc_node_default = {malloc, calloc, realloc, free}; + +#endif /* CMC_CORE_H */ + +/* ------------------------------------------------------------------------------------------------- + * SortedList specific + ------------------------------------------------------------------------------------------------ */ /* to_string format */ -static const char *cmc_string_fmt_sortedlist = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", is_sorted:%s, cmp:%p }"; +static const char *cmc_string_fmt_sortedlist = "struct %s<%s> " + "at %p { " + "buffer:%p, " + "capacity:%" PRIuMAX ", " + "count:%" PRIuMAX ", " + "is_sorted:%s, " + "cmp:%p, " + "alloc:%p, " + "callbacks:%p }"; + +/** + * Custom SortedList callbacks. + * + * There are two types of callbacks, 'before' and 'after': + * _ + */ +struct cmc_callbacks_sortedlist +{ + void (*before_clear)(void *); + void (*after_clear)(void *); + void (*before_free)(void *); + void (*after_free)(void *); + // TODO implement all callbacks +}; #define CMC_GENERATE_SORTEDLIST(PFX, SNAME, V) \ CMC_GENERATE_SORTEDLIST_HEADER(PFX, SNAME, V) \ @@ -42,98 +100,114 @@ static const char *cmc_string_fmt_sortedlist = "%s at %p { buffer:%p, capacity:% #define CMC_WRAPGEN_SORTEDLIST_SOURCE(PFX, SNAME, K, V) \ CMC_GENERATE_SORTEDLIST_SOURCE(PFX, SNAME, V) -/* HEADER ********************************************************************/ -#define CMC_GENERATE_SORTEDLIST_HEADER(PFX, SNAME, V) \ - \ - /* List Structure */ \ - struct SNAME \ - { \ - /* Dynamic array of elements */ \ - V *buffer; \ - \ - /* Current array capacity */ \ - size_t capacity; \ - \ - /* Current amount of elements */ \ - size_t count; \ - \ - /* Flag if the list is sorted or not, used by lazy evaluation */ \ - bool is_sorted; \ - \ - /* Element comparison function */ \ - int (*cmp)(V, V); \ - \ - /* Function that returns an iterator to the start of the list */ \ - struct SNAME##_iter (*it_start)(struct SNAME *); \ - \ - /* Function that returns an iterator to the end of the list */ \ - struct SNAME##_iter (*it_end)(struct SNAME *); \ - }; \ - \ - /* List Iterator */ \ - struct SNAME##_iter \ - { \ - /* Target list */ \ - struct SNAME *target; \ - \ - /* Cursor's position (index) */ \ - size_t cursor; \ - \ - /* If the iterator has reached the start of the iteration */ \ - bool start; \ - \ - /* If the iterator has reached the end of the iteration */ \ - bool end; \ - }; \ - \ - /* Collection Functions */ \ - /* Collection Allocation and Deallocation */ \ - struct SNAME *PFX##_new(size_t capacity, int (*compare)(V, V)); \ - void PFX##_clear(struct SNAME *_list_, void (*deallocator)(V)); \ - void PFX##_free(struct SNAME *_list_, void (*deallocator)(V)); \ - /* Collection Input and Output */ \ - bool PFX##_insert(struct SNAME *_list_, V element); \ - bool PFX##_remove(struct SNAME *_list_, size_t index); \ - /* Element Access */ \ - bool PFX##_max(struct SNAME *_list_, V *result); \ - bool PFX##_min(struct SNAME *_list_, V *result); \ - V PFX##_get(struct SNAME *_list_, size_t index); \ - size_t PFX##_indexof(struct SNAME *_list_, V element, bool from_start); \ - /* Collection State */ \ - bool PFX##_contains(struct SNAME *_list_, V element); \ - bool PFX##_empty(struct SNAME *_list_); \ - bool PFX##_full(struct SNAME *_list_); \ - size_t PFX##_count(struct SNAME *_list_); \ - size_t PFX##_capacity(struct SNAME *_list_); \ - /* Collection Utility */ \ - bool PFX##_resize(struct SNAME *_list_, size_t capacity); \ - void PFX##_sort(struct SNAME *_list_); \ - struct SNAME *PFX##_copy_of(struct SNAME *_list_, V (*copy_func)(V)); \ - bool PFX##_equals(struct SNAME *_list1_, struct SNAME *_list2_); \ - struct cmc_string PFX##_to_string(struct SNAME *_list_); \ - \ - /* Iterator Functions */ \ - /* Iterator Allocation and Deallocation */ \ - struct SNAME##_iter *PFX##_iter_new(struct SNAME *target); \ - void PFX##_iter_free(struct SNAME##_iter *iter); \ - /* Iterator Initialization */ \ - void PFX##_iter_init(struct SNAME##_iter *iter, struct SNAME *target); \ - /* Iterator State */ \ - bool PFX##_iter_start(struct SNAME##_iter *iter); \ - bool PFX##_iter_end(struct SNAME##_iter *iter); \ - /* Iterator Movement */ \ - void PFX##_iter_to_start(struct SNAME##_iter *iter); \ - void PFX##_iter_to_end(struct SNAME##_iter *iter); \ - bool PFX##_iter_next(struct SNAME##_iter *iter); \ - bool PFX##_iter_prev(struct SNAME##_iter *iter); \ - bool PFX##_iter_advance(struct SNAME##_iter *iter, size_t steps); \ - bool PFX##_iter_rewind(struct SNAME##_iter *iter, size_t steps); \ - bool PFX##_iter_go_to(struct SNAME##_iter *iter, size_t index); \ - /* Iterator Access */ \ - V PFX##_iter_value(struct SNAME##_iter *iter); \ - size_t PFX##_iter_index(struct SNAME##_iter *iter); \ - \ -/* SOURCE ********************************************************************/ +/* ------------------------------------------------------------------------------------------------- + * Header + ------------------------------------------------------------------------------------------------ */ +#define CMC_GENERATE_SORTEDLIST_HEADER(PFX, SNAME, V) \ + \ + /* List Structure */ \ + struct SNAME \ + { \ + /* Dynamic array of elements */ \ + V *buffer; \ + \ + /* Current array capacity */ \ + size_t capacity; \ + \ + /* Current amount of elements */ \ + size_t count; \ + \ + /* Flag if the list is sorted or not, used by lazy evaluation */ \ + bool is_sorted; \ + \ + /* Element comparison function */ \ + int (*cmp)(V, V); \ + \ + /* Function that returns an iterator to the start of the list */ \ + struct SNAME##_iter (*it_start)(struct SNAME *); \ + \ + /* Function that returns an iterator to the end of the list */ \ + struct SNAME##_iter (*it_end)(struct SNAME *); \ + \ + /* Custom allocation functions */ \ + struct cmc_alloc_node *alloc; \ + \ + /* Custom callback functions */ \ + struct cmc_callbacks_sortedlist *callbacks; \ + }; \ + \ + /* List Iterator */ \ + struct SNAME##_iter \ + { \ + /* Target list */ \ + struct SNAME *target; \ + \ + /* Cursor's position (index) */ \ + size_t cursor; \ + \ + /* If the iterator has reached the start of the iteration */ \ + bool start; \ + \ + /* If the iterator has reached the end of the iteration */ \ + bool end; \ + }; \ + \ + /* Collection Functions */ \ + /* Collection Allocation and Deallocation */ \ + struct SNAME *PFX##_new(size_t capacity, int (*compare)(V, V)); \ + struct SNAME *PFX##_new_custom(size_t capacity, int (*compare)(V, V), \ + struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_sortedlist *callbacks); \ + void PFX##_clear(struct SNAME *_list_, void (*deallocator)(V)); \ + void PFX##_free(struct SNAME *_list_, void (*deallocator)(V)); \ + /* Customization of Allocation and Callbacks */ \ + void PFX##_customize(struct SNAME *_list_, struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_sortedlist *callbacks); \ + /* Collection Input and Output */ \ + bool PFX##_insert(struct SNAME *_list_, V element); \ + bool PFX##_remove(struct SNAME *_list_, size_t index); \ + /* Element Access */ \ + bool PFX##_max(struct SNAME *_list_, V *result); \ + bool PFX##_min(struct SNAME *_list_, V *result); \ + V PFX##_get(struct SNAME *_list_, size_t index); \ + size_t PFX##_indexof(struct SNAME *_list_, V element, bool from_start); \ + /* Collection State */ \ + bool PFX##_contains(struct SNAME *_list_, V element); \ + bool PFX##_empty(struct SNAME *_list_); \ + bool PFX##_full(struct SNAME *_list_); \ + size_t PFX##_count(struct SNAME *_list_); \ + size_t PFX##_capacity(struct SNAME *_list_); \ + /* Collection Utility */ \ + bool PFX##_resize(struct SNAME *_list_, size_t capacity); \ + void PFX##_sort(struct SNAME *_list_); \ + struct SNAME *PFX##_copy_of(struct SNAME *_list_, V (*copy_func)(V)); \ + bool PFX##_equals(struct SNAME *_list1_, struct SNAME *_list2_); \ + struct cmc_string PFX##_to_string(struct SNAME *_list_); \ + \ + /* Iterator Functions */ \ + /* Iterator Allocation and Deallocation */ \ + struct SNAME##_iter *PFX##_iter_new(struct SNAME *target); \ + void PFX##_iter_free(struct SNAME##_iter *iter); \ + /* Iterator Initialization */ \ + void PFX##_iter_init(struct SNAME##_iter *iter, struct SNAME *target); \ + /* Iterator State */ \ + bool PFX##_iter_start(struct SNAME##_iter *iter); \ + bool PFX##_iter_end(struct SNAME##_iter *iter); \ + /* Iterator Movement */ \ + void PFX##_iter_to_start(struct SNAME##_iter *iter); \ + void PFX##_iter_to_end(struct SNAME##_iter *iter); \ + bool PFX##_iter_next(struct SNAME##_iter *iter); \ + bool PFX##_iter_prev(struct SNAME##_iter *iter); \ + bool PFX##_iter_advance(struct SNAME##_iter *iter, size_t steps); \ + bool PFX##_iter_rewind(struct SNAME##_iter *iter, size_t steps); \ + bool PFX##_iter_go_to(struct SNAME##_iter *iter, size_t index); \ + /* Iterator Access */ \ + V PFX##_iter_value(struct SNAME##_iter *iter); \ + size_t PFX##_iter_index(struct SNAME##_iter *iter); + +/* ------------------------------------------------------------------------------------------------- + * Source + ------------------------------------------------------------------------------------------------ */ #define CMC_GENERATE_SORTEDLIST_SOURCE(PFX, SNAME, V) \ \ /* Implementation Detail Functions */ \ @@ -146,19 +220,21 @@ static const char *cmc_string_fmt_sortedlist = "%s at %p { buffer:%p, capacity:% \ struct SNAME *PFX##_new(size_t capacity, int (*compare)(V, V)) \ { \ + struct cmc_alloc_node *alloc = &cmc_alloc_node_default; \ + \ if (capacity < 1) \ return NULL; \ \ - struct SNAME *_list_ = malloc(sizeof(struct SNAME)); \ + struct SNAME *_list_ = alloc->malloc(sizeof(struct SNAME)); \ \ if (!_list_) \ return NULL; \ \ - _list_->buffer = calloc(capacity, sizeof(V)); \ + _list_->buffer = alloc->calloc(capacity, sizeof(V)); \ \ if (!_list_->buffer) \ { \ - free(_list_); \ + alloc->free(_list_); \ return NULL; \ } \ \ @@ -170,6 +246,46 @@ static const char *cmc_string_fmt_sortedlist = "%s at %p { buffer:%p, capacity:% _list_->it_start = PFX##_impl_it_start; \ _list_->it_end = PFX##_impl_it_end; \ \ + _list_->alloc = alloc; \ + _list_->callbacks = NULL; \ + \ + return _list_; \ + } \ + \ + struct SNAME *PFX##_new_custom(size_t capacity, int (*compare)(V, V), \ + struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_sortedlist *callbacks) \ + { \ + if (capacity < 1) \ + return NULL; \ + \ + if (!alloc) \ + alloc = &cmc_alloc_node_default; \ + \ + struct SNAME *_list_ = alloc->malloc(sizeof(struct SNAME)); \ + \ + if (!_list_) \ + return NULL; \ + \ + _list_->buffer = alloc->calloc(capacity, sizeof(V)); \ + \ + if (!_list_->buffer) \ + { \ + alloc->free(_list_); \ + return NULL; \ + } \ + \ + _list_->capacity = capacity; \ + _list_->count = 0; \ + _list_->cmp = compare; \ + _list_->is_sorted = false; \ + \ + _list_->it_start = PFX##_impl_it_start; \ + _list_->it_end = PFX##_impl_it_end; \ + \ + _list_->alloc = alloc; \ + _list_->callbacks = callbacks; \ + \ return _list_; \ } \ \ @@ -194,8 +310,18 @@ static const char *cmc_string_fmt_sortedlist = "%s at %p { buffer:%p, capacity:% deallocator(_list_->buffer[i]); \ } \ \ - free(_list_->buffer); \ - free(_list_); \ + _list_->alloc->free(_list_->buffer); \ + _list_->alloc->free(_list_); \ + } \ + \ + void PFX##_customize(struct SNAME *_list_, struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_sortedlist *callbacks) \ + { \ + if (alloc) \ + _list_->alloc = alloc; \ + \ + if (callbacks) \ + _list_->callbacks = callbacks; \ } \ \ bool PFX##_insert(struct SNAME *_list_, V element) \ @@ -310,7 +436,7 @@ static const char *cmc_string_fmt_sortedlist = "%s at %p { buffer:%p, capacity:% if (capacity < PFX##_count(_list_)) \ return false; \ \ - V *new_buffer = realloc(_list_->buffer, sizeof(V) * capacity); \ + V *new_buffer = _list_->alloc->realloc(_list_->buffer, sizeof(V) * capacity); \ \ if (!new_buffer) \ return false; \ @@ -372,18 +498,23 @@ static const char *cmc_string_fmt_sortedlist = "%s at %p { buffer:%p, capacity:% { \ struct cmc_string str; \ struct SNAME *l_ = _list_; \ - const char *name = #SNAME; \ \ - snprintf(str.s, cmc_string_len, cmc_string_fmt_sortedlist, \ - name, l_, l_->buffer, l_->capacity, l_->count, \ - l_->is_sorted ? "true" : "false", l_->cmp); \ + int n = snprintf(str.s, cmc_string_len, cmc_string_fmt_sortedlist, \ + #SNAME, #V, l_, l_->buffer, l_->capacity, l_->count, \ + l_->is_sorted ? "true" : "false", l_->cmp, \ + l_->alloc, l_->callbacks); \ + \ + if (n < 0 || n == (int)cmc_string_len) \ + return (struct cmc_string){0}; \ + \ + str.s[n] = '\0'; \ \ return str; \ } \ \ struct SNAME##_iter *PFX##_iter_new(struct SNAME *target) \ { \ - struct SNAME##_iter *iter = malloc(sizeof(struct SNAME##_iter)); \ + struct SNAME##_iter *iter = target->alloc->malloc(sizeof(struct SNAME##_iter)); \ \ if (!iter) \ return NULL; \ @@ -395,7 +526,7 @@ static const char *cmc_string_fmt_sortedlist = "%s at %p { buffer:%p, capacity:% \ void PFX##_iter_free(struct SNAME##_iter *iter) \ { \ - free(iter); \ + iter->target->alloc->free(iter); \ } \ \ void PFX##_iter_init(struct SNAME##_iter *iter, struct SNAME *target) \ diff --git a/src/cmc/stack.h b/src/cmc/stack.h index 3432f52..c0a1a58 100644 --- a/src/cmc/stack.h +++ b/src/cmc/stack.h @@ -33,10 +33,66 @@ #include #include #include -#include "../utl/cmc_string.h" +/* ------------------------------------------------------------------------------------------------- + * Core functionalities of the C Macro Collections Library + ------------------------------------------------------------------------------------------------ */ +#ifndef CMC_CORE_H +#define CMC_CORE_H + +/** + * struct cmc_string + * + * Used by all collections when calling the to_string function. + */ +struct cmc_string +{ + char s[400]; +}; + +static const size_t cmc_string_len = 400; + +/** + * struct cmc_alloc_node + * + * Custom allocation node. Allows collections to use custom allocation functions. + */ +struct cmc_alloc_node +{ + void *(*malloc)(size_t); + void *(*calloc)(size_t, size_t); + void *(*realloc)(void *, size_t); + void (*free)(void *); +} cmc_alloc_node_default = {malloc, calloc, realloc, free}; + +#endif /* CMC_CORE_H */ + +/* ------------------------------------------------------------------------------------------------- + * Stack specific + ------------------------------------------------------------------------------------------------ */ /* to_string format */ -static const char *cmc_string_fmt_stack = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX " }"; +static const char *cmc_string_fmt_stack = "struct %s<%s> " + "at %p { " + "buffer:%p, " + "capacity:%" PRIuMAX ", " + "count:%" PRIuMAX ", " + "alloc:%p, " + "callbacks:%p }"; + +/** + * Custom Stack callbacks. + * + * There are two types of callbacks, 'before' and 'after': + * _ + */ +struct cmc_callbacks_stack +{ + void (*before_clear)(void *); + void (*after_clear)(void *); + void (*before_free)(void *); + void (*after_free)(void *); + // TODO implement all callbacks +}; #define CMC_GENERATE_STACK(PFX, SNAME, V) \ CMC_GENERATE_STACK_HEADER(PFX, SNAME, V) \ @@ -48,7 +104,9 @@ static const char *cmc_string_fmt_stack = "%s at %p { buffer:%p, capacity:%" PRI #define CMC_WRAPGEN_STACK_SOURCE(PFX, SNAME, K, V) \ CMC_GENERATE_STACK_SOURCE(PFX, SNAME, V) -/* HEADER ********************************************************************/ +/* ------------------------------------------------------------------------------------------------- + * Header + ------------------------------------------------------------------------------------------------ */ #define CMC_GENERATE_STACK_HEADER(PFX, SNAME, V) \ \ /* Stack Structure */ \ @@ -68,6 +126,12 @@ static const char *cmc_string_fmt_stack = "%s at %p { buffer:%p, capacity:%" PRI \ /* Function that returns an iterator to the end of the stack */ \ struct SNAME##_iter (*it_end)(struct SNAME *); \ + \ + /* Custom allocation functions */ \ + struct cmc_alloc_node *alloc; \ + \ + /* Custom callback functions */ \ + struct cmc_callbacks_stack *callbacks; \ }; \ \ /* Stack Iterator */ \ @@ -89,8 +153,13 @@ static const char *cmc_string_fmt_stack = "%s at %p { buffer:%p, capacity:%" PRI /* Collection Functions */ \ /* Collection Allocation and Deallocation */ \ struct SNAME *PFX##_new(size_t capacity); \ + struct SNAME *PFX##_new_custom(size_t capacity, struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_stack *callbacks); \ void PFX##_clear(struct SNAME *_stack_, void (*deallocator)(V)); \ void PFX##_free(struct SNAME *_stack_, void (*deallocator)(V)); \ + /* Customization of Allocation and Callbacks */ \ + void PFX##_customize(struct SNAME *_stack_, struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_stack *callbacks); \ /* Collection Input and Output */ \ bool PFX##_push(struct SNAME *_stack_, V element); \ bool PFX##_pop(struct SNAME *_stack_); \ @@ -128,9 +197,11 @@ static const char *cmc_string_fmt_stack = "%s at %p { buffer:%p, capacity:%" PRI /* Iterator Access */ \ V PFX##_iter_value(struct SNAME##_iter *iter); \ V *PFX##_iter_rvalue(struct SNAME##_iter *iter); \ - size_t PFX##_iter_index(struct SNAME##_iter *iter); \ - \ -/* SOURCE ********************************************************************/ + size_t PFX##_iter_index(struct SNAME##_iter *iter); + +/* ------------------------------------------------------------------------------------------------- + * Source + ------------------------------------------------------------------------------------------------ */ #define CMC_GENERATE_STACK_SOURCE(PFX, SNAME, V) \ \ /* Implementation Detail Functions */ \ @@ -139,19 +210,21 @@ static const char *cmc_string_fmt_stack = "%s at %p { buffer:%p, capacity:%" PRI \ struct SNAME *PFX##_new(size_t capacity) \ { \ + struct cmc_alloc_node *alloc = &cmc_alloc_node_default; \ + \ if (capacity < 1) \ return NULL; \ \ - struct SNAME *_stack_ = malloc(sizeof(struct SNAME)); \ + struct SNAME *_stack_ = alloc->malloc(sizeof(struct SNAME)); \ \ if (!_stack_) \ return NULL; \ \ - _stack_->buffer = calloc(capacity, sizeof(V)); \ + _stack_->buffer = alloc->calloc(capacity, sizeof(V)); \ \ if (!_stack_->buffer) \ { \ - free(_stack_); \ + alloc->free(_stack_); \ return NULL; \ } \ \ @@ -161,6 +234,43 @@ static const char *cmc_string_fmt_stack = "%s at %p { buffer:%p, capacity:%" PRI _stack_->it_start = PFX##_impl_it_start; \ _stack_->it_end = PFX##_impl_it_end; \ \ + _stack_->alloc = alloc; \ + _stack_->callbacks = NULL; \ + \ + return _stack_; \ + } \ + \ + struct SNAME *PFX##_new_custom(size_t capacity, struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_stack *callbacks) \ + { \ + if (capacity < 1) \ + return NULL; \ + \ + if (!alloc) \ + alloc = &cmc_alloc_node_default; \ + \ + struct SNAME *_stack_ = alloc->malloc(sizeof(struct SNAME)); \ + \ + if (!_stack_) \ + return NULL; \ + \ + _stack_->buffer = alloc->calloc(capacity, sizeof(V)); \ + \ + if (!_stack_->buffer) \ + { \ + alloc->free(_stack_); \ + return NULL; \ + } \ + \ + _stack_->capacity = capacity; \ + _stack_->count = 0; \ + \ + _stack_->it_start = PFX##_impl_it_start; \ + _stack_->it_end = PFX##_impl_it_end; \ + \ + _stack_->alloc = alloc; \ + _stack_->callbacks = callbacks; \ + \ return _stack_; \ } \ \ @@ -179,14 +289,25 @@ static const char *cmc_string_fmt_stack = "%s at %p { buffer:%p, capacity:%" PRI \ void PFX##_free(struct SNAME *_stack_, void (*deallocator)(V)) \ { \ - free(_stack_->buffer); \ + _stack_->alloc->free(_stack_->buffer); \ + \ if (deallocator) \ { \ for (size_t i = 0; i < _stack_->count; i++) \ deallocator(_stack_->buffer[i]); \ } \ \ - free(_stack_); \ + _stack_->alloc->free(_stack_); \ + } \ + \ + void PFX##_customize(struct SNAME *_stack_, struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_stack *callbacks) \ + { \ + if (alloc) \ + _stack_->alloc = alloc; \ + \ + if (callbacks) \ + _stack_->callbacks = callbacks; \ } \ \ bool PFX##_push(struct SNAME *_stack_, V element) \ @@ -259,7 +380,7 @@ static const char *cmc_string_fmt_stack = "%s at %p { buffer:%p, capacity:%" PRI if (capacity < PFX##_count(_stack_)) \ return false; \ \ - V *new_buffer = realloc(_stack_->buffer, sizeof(V) * capacity); \ + V *new_buffer = _stack_->alloc->realloc(_stack_->buffer, sizeof(V) * capacity); \ \ if (!new_buffer) \ return false; \ @@ -308,17 +429,22 @@ static const char *cmc_string_fmt_stack = "%s at %p { buffer:%p, capacity:%" PRI { \ struct cmc_string str; \ struct SNAME *s_ = _stack_; \ - const char *name = #SNAME; \ \ - snprintf(str.s, cmc_string_len, cmc_string_fmt_stack, \ - name, s_, s_->buffer, s_->capacity, s_->count); \ + int n = snprintf(str.s, cmc_string_len, cmc_string_fmt_stack, \ + #SNAME, #V, s_, s_->buffer, s_->capacity, s_->count, \ + s_->alloc, s_->callbacks); \ + \ + if (n < 0 || n == (int)cmc_string_len) \ + return (struct cmc_string){0}; \ + \ + str.s[n] = '\0'; \ \ return str; \ } \ \ struct SNAME##_iter *PFX##_iter_new(struct SNAME *target) \ { \ - struct SNAME##_iter *iter = malloc(sizeof(struct SNAME##_iter)); \ + struct SNAME##_iter *iter = target->alloc->malloc(sizeof(struct SNAME##_iter)); \ \ if (!iter) \ return NULL; \ @@ -330,7 +456,7 @@ static const char *cmc_string_fmt_stack = "%s at %p { buffer:%p, capacity:%" PRI \ void PFX##_iter_free(struct SNAME##_iter *iter) \ { \ - free(iter); \ + iter->target->alloc->free(iter); \ } \ \ void PFX##_iter_init(struct SNAME##_iter *iter, struct SNAME *target) \ diff --git a/src/cmc/treemap.h b/src/cmc/treemap.h index 2dc13e2..cb936d6 100644 --- a/src/cmc/treemap.h +++ b/src/cmc/treemap.h @@ -24,10 +24,66 @@ #include #include #include -#include "../utl/cmc_string.h" +/* ------------------------------------------------------------------------------------------------- + * Core functionalities of the C Macro Collections Library + ------------------------------------------------------------------------------------------------ */ +#ifndef CMC_CORE_H +#define CMC_CORE_H + +/** + * struct cmc_string + * + * Used by all collections when calling the to_string function. + */ +struct cmc_string +{ + char s[400]; +}; + +static const size_t cmc_string_len = 400; + +/** + * struct cmc_alloc_node + * + * Custom allocation node. Allows collections to use custom allocation functions. + */ +struct cmc_alloc_node +{ + void *(*malloc)(size_t); + void *(*calloc)(size_t, size_t); + void *(*realloc)(void *, size_t); + void (*free)(void *); +} cmc_alloc_node_default = {malloc, calloc, realloc, free}; + +#endif /* CMC_CORE_H */ + +/* ------------------------------------------------------------------------------------------------- + * TreeMap specific + ------------------------------------------------------------------------------------------------ */ /* to_string format */ -static const char *cmc_string_fmt_treemap = "%s at %p { root:%p, count:%" PRIuMAX ", cmp:%p }"; +static const char *cmc_string_fmt_treemap = "struct %s<%s, %s> " + "at %p { " + "root:%p, " + "count:%" PRIuMAX ", " + "cmp:%p, " + "alloc:%p, " + "callbacks:%p }"; + +/** + * Custom TreeMap callbacks. + * + * There are two types of callbacks, 'before' and 'after': + * _ + */ +struct cmc_callbacks_treemap +{ + void (*before_clear)(void *); + void (*after_clear)(void *); + void (*before_free)(void *); + void (*after_free)(void *); + // TODO implement all callbacks +}; #define CMC_GENERATE_TREEMAP(PFX, SNAME, K, V) \ CMC_GENERATE_TREEMAP_HEADER(PFX, SNAME, K, V) \ @@ -39,7 +95,9 @@ static const char *cmc_string_fmt_treemap = "%s at %p { root:%p, count:%" PRIuMA #define CMC_WRAPGEN_TREEMAP_SOURCE(PFX, SNAME, K, V) \ CMC_GENERATE_TREEMAP_SOURCE(PFX, SNAME, K, V) -/* HEADER ********************************************************************/ +/* ------------------------------------------------------------------------------------------------- + * Header + ------------------------------------------------------------------------------------------------ */ #define CMC_GENERATE_TREEMAP_HEADER(PFX, SNAME, K, V) \ \ /* Treemap Structure */ \ @@ -59,6 +117,12 @@ static const char *cmc_string_fmt_treemap = "%s at %p { root:%p, count:%" PRIuMA \ /* Function that returns an iterator to the end of the treemap */ \ struct SNAME##_iter (*it_end)(struct SNAME *); \ + \ + /* Custom allocation functions */ \ + struct cmc_alloc_node *alloc; \ + \ + /* Custom callback functions */ \ + struct cmc_callbacks_treemap *callbacks; \ }; \ \ /* Treemap Node */ \ @@ -111,8 +175,13 @@ static const char *cmc_string_fmt_treemap = "%s at %p { root:%p, count:%" PRIuMA /* Collection Functions */ \ /* Collection Allocation and Deallocation */ \ struct SNAME *PFX##_new(int (*compare)(K, K)); \ + struct SNAME *PFX##_new_custom(int (*compare)(K, K), struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_treemap *callbacks); \ void PFX##_clear(struct SNAME *_map_, void (*deallocator)(K, V)); \ void PFX##_free(struct SNAME *_map_, void (*deallocator)(K, V)); \ + /* Customization of Allocation and Callbacks */ \ + void PFX##_customize(struct SNAME *_map_, struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_treemap *callbacks); \ /* Collection Input and Output */ \ bool PFX##_insert(struct SNAME *_map_, K key, V value); \ bool PFX##_update(struct SNAME *_map_, K key, V new_value, V *old_value); \ @@ -153,9 +222,11 @@ static const char *cmc_string_fmt_treemap = "%s at %p { root:%p, count:%" PRIuMA K PFX##_iter_key(struct SNAME##_iter *iter); \ V PFX##_iter_value(struct SNAME##_iter *iter); \ V *PFX##_iter_rvalue(struct SNAME##_iter *iter); \ - size_t PFX##_iter_index(struct SNAME##_iter *iter); \ - \ -/* SOURCE ********************************************************************/ + size_t PFX##_iter_index(struct SNAME##_iter *iter); + +/* ------------------------------------------------------------------------------------------------- + * Source + ------------------------------------------------------------------------------------------------ */ #define CMC_GENERATE_TREEMAP_SOURCE(PFX, SNAME, K, V) \ \ /* Implementation Detail Functions */ \ @@ -171,7 +242,9 @@ static const char *cmc_string_fmt_treemap = "%s at %p { root:%p, count:%" PRIuMA \ struct SNAME *PFX##_new(int (*compare)(K, K)) \ { \ - struct SNAME *_map_ = malloc(sizeof(struct SNAME)); \ + struct cmc_alloc_node *alloc = &cmc_alloc_node_default; \ + \ + struct SNAME *_map_ = alloc->malloc(sizeof(struct SNAME)); \ \ if (!_map_) \ return NULL; \ @@ -183,6 +256,33 @@ static const char *cmc_string_fmt_treemap = "%s at %p { root:%p, count:%" PRIuMA _map_->it_start = PFX##_impl_it_start; \ _map_->it_end = PFX##_impl_it_end; \ \ + _map_->alloc = alloc; \ + _map_->callbacks = NULL; \ + \ + return _map_; \ + } \ + \ + struct SNAME *PFX##_new_custom(int (*compare)(K, K), struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_treemap *callbacks) \ + { \ + if (!alloc) \ + alloc = &cmc_alloc_node_default; \ + \ + struct SNAME *_map_ = alloc->malloc(sizeof(struct SNAME)); \ + \ + if (!_map_) \ + return NULL; \ + \ + _map_->count = 0; \ + _map_->root = NULL; \ + _map_->cmp = compare; \ + \ + _map_->it_start = PFX##_impl_it_start; \ + _map_->it_end = PFX##_impl_it_end; \ + \ + _map_->alloc = alloc; \ + _map_->callbacks = callbacks; \ + \ return _map_; \ } \ \ @@ -590,10 +690,15 @@ static const char *cmc_string_fmt_treemap = "%s at %p { root:%p, count:%" PRIuMA { \ struct cmc_string str; \ struct SNAME *m_ = _map_; \ - const char *name = #SNAME; \ \ - snprintf(str.s, cmc_string_len, cmc_string_fmt_treemap, \ - name, m_, m_->root, m_->count, m_->cmp); \ + int n = snprintf(str.s, cmc_string_len, cmc_string_fmt_treemap, \ + #SNAME, #K, #V, m_, m_->root, m_->count, m_->cmp, \ + m_->alloc, m_->callbacks); \ + \ + if (n < 0 || n == (int)cmc_string_len) \ + return (struct cmc_string){0}; \ + \ + str.s[n] = '\0'; \ \ return str; \ } \ diff --git a/src/cmc/treeset.h b/src/cmc/treeset.h index a174220..163efda 100644 --- a/src/cmc/treeset.h +++ b/src/cmc/treeset.h @@ -24,10 +24,66 @@ #include #include #include -#include "../utl/cmc_string.h" +/* ------------------------------------------------------------------------------------------------- + * Core functionalities of the C Macro Collections Library + ------------------------------------------------------------------------------------------------ */ +#ifndef CMC_CORE_H +#define CMC_CORE_H + +/** + * struct cmc_string + * + * Used by all collections when calling the to_string function. + */ +struct cmc_string +{ + char s[400]; +}; + +static const size_t cmc_string_len = 400; + +/** + * struct cmc_alloc_node + * + * Custom allocation node. Allows collections to use custom allocation functions. + */ +struct cmc_alloc_node +{ + void *(*malloc)(size_t); + void *(*calloc)(size_t, size_t); + void *(*realloc)(void *, size_t); + void (*free)(void *); +} cmc_alloc_node_default = {malloc, calloc, realloc, free}; + +#endif /* CMC_CORE_H */ + +/* ------------------------------------------------------------------------------------------------- + * TreeSet specific + ------------------------------------------------------------------------------------------------ */ /* to_string format */ -static const char *cmc_string_fmt_treeset = "%s at %p { root:%p, count:%" PRIuMAX ", cmp:%p }"; +static const char *cmc_string_fmt_treeset = "struct %s<%s> " + "at %p { " + "root:%p, " + "count:%" PRIuMAX ", " + "cmp:%p, " + "alloc:%p, " + "callbacks:%p }"; + +/** + * Custom TreeSet callbacks. + * + * There are two types of callbacks, 'before' and 'after': + * _ + */ +struct cmc_callbacks_treeset +{ + void (*before_clear)(void *); + void (*after_clear)(void *); + void (*before_free)(void *); + void (*after_free)(void *); + // TODO implement all callbacks +}; #define CMC_GENERATE_TREESET(PFX, SNAME, V) \ CMC_GENERATE_TREESET_HEADER(PFX, SNAME, V) \ @@ -39,7 +95,9 @@ static const char *cmc_string_fmt_treeset = "%s at %p { root:%p, count:%" PRIuMA #define CMC_WRAPGEN_TREESET_SOURCE(PFX, SNAME, K, V) \ CMC_GENERATE_TREESET_SOURCE(PFX, SNAME, V) -/* HEADER ********************************************************************/ +/* ------------------------------------------------------------------------------------------------- + * Header + ------------------------------------------------------------------------------------------------ */ #define CMC_GENERATE_TREESET_HEADER(PFX, SNAME, V) \ \ /* Treeset Structure */ \ @@ -59,6 +117,12 @@ static const char *cmc_string_fmt_treeset = "%s at %p { root:%p, count:%" PRIuMA \ /* Function that returns an iterator to the end of the treeset */ \ struct SNAME##_iter (*it_end)(struct SNAME *); \ + \ + /* Custom allocation functions */ \ + struct cmc_alloc_node *alloc; \ + \ + /* Custom callback functions */ \ + struct cmc_callbacks_treeset *callbacks; \ }; \ \ /* Treeset Node */ \ @@ -108,8 +172,13 @@ static const char *cmc_string_fmt_treeset = "%s at %p { root:%p, count:%" PRIuMA /* Collection Functions */ \ /* Collection Allocation and Deallocation */ \ struct SNAME *PFX##_new(int (*compare)(V, V)); \ + struct SNAME *PFX##_new_custom(int (*compare)(V, V), struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_treeset *callbacks); \ void PFX##_clear(struct SNAME *_set_, void (*deallocator)(V)); \ void PFX##_free(struct SNAME *_set_, void (*deallocator)(V)); \ + /* Customization of Allocation and Callbacks */ \ + void PFX##_customize(struct SNAME *_set_, struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_treeset *callbacks); \ /* Collection Input and Output */ \ bool PFX##_insert(struct SNAME *_set_, V element); \ bool PFX##_remove(struct SNAME *_set_, V element); \ @@ -165,9 +234,11 @@ static const char *cmc_string_fmt_treeset = "%s at %p { root:%p, count:%" PRIuMA memset(&_empty_value_, 0, sizeof(V)); \ \ return _empty_value_; \ - } \ - \ -/* SOURCE ********************************************************************/ + } + +/* ------------------------------------------------------------------------------------------------- + * Source + ------------------------------------------------------------------------------------------------ */ #define CMC_GENERATE_TREESET_SOURCE(PFX, SNAME, V) \ \ /* Implementation Detail Functions */ \ @@ -183,7 +254,9 @@ static const char *cmc_string_fmt_treeset = "%s at %p { root:%p, count:%" PRIuMA \ struct SNAME *PFX##_new(int (*compare)(V, V)) \ { \ - struct SNAME *_set_ = malloc(sizeof(struct SNAME)); \ + struct cmc_alloc_node *alloc = &cmc_alloc_node_default; \ + \ + struct SNAME *_set_ = alloc->malloc(sizeof(struct SNAME)); \ \ if (!_set_) \ return NULL; \ @@ -195,6 +268,33 @@ static const char *cmc_string_fmt_treeset = "%s at %p { root:%p, count:%" PRIuMA _set_->it_start = PFX##_impl_it_start; \ _set_->it_end = PFX##_impl_it_end; \ \ + _set_->alloc = alloc; \ + _set_->callbacks = NULL; \ + \ + return _set_; \ + } \ + \ + struct SNAME *PFX##_new_custom(int (*compare)(V, V), struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_treeset *callbacks) \ + { \ + if (!alloc) \ + alloc = &cmc_alloc_node_default; \ + \ + struct SNAME *_set_ = alloc->malloc(sizeof(struct SNAME)); \ + \ + if (!_set_) \ + return NULL; \ + \ + _set_->count = 0; \ + _set_->root = NULL; \ + _set_->cmp = compare; \ + \ + _set_->it_start = PFX##_impl_it_start; \ + _set_->it_end = PFX##_impl_it_end; \ + \ + _set_->alloc = alloc; \ + _set_->callbacks = callbacks; \ + \ return _set_; \ } \ \ @@ -546,10 +646,15 @@ static const char *cmc_string_fmt_treeset = "%s at %p { root:%p, count:%" PRIuMA { \ struct cmc_string str; \ struct SNAME *s_ = _set_; \ - const char *name = #SNAME; \ \ - snprintf(str.s, cmc_string_len, cmc_string_fmt_treeset, \ - name, s_, s_->root, s_->count, s_->cmp); \ + int n = snprintf(str.s, cmc_string_len, cmc_string_fmt_treeset, \ + #SNAME, #V, s_, s_->root, s_->count, s_->cmp, \ + s_->alloc, s_->callbacks); \ + \ + if (n < 0 || n == (int)cmc_string_len) \ + return (struct cmc_string){0}; \ + \ + str.s[n] = '\0'; \ \ return str; \ } \