From 7dd621801793767c7f7615d965af4a25ee500c13 Mon Sep 17 00:00:00 2001 From: Leonardo Date: Thu, 6 Feb 2020 01:04:25 -0300 Subject: [PATCH] Adding functions table to hashmap and some fixes in bidimap and queue --- src/cmc/bidimap.h | 5 +- src/cmc/hashmap.h | 1679 ++++++++++++++++++++------------------ src/cmc/queue.h | 2 + tests/main/unt/hashmap.c | 166 ++-- 4 files changed, 971 insertions(+), 881 deletions(-) diff --git a/src/cmc/bidimap.h b/src/cmc/bidimap.h index 2d07b9f..d15c412 100644 --- a/src/cmc/bidimap.h +++ b/src/cmc/bidimap.h @@ -412,7 +412,7 @@ struct cmc_callbacks_bidimap if (capacity >= UINTMAX_MAX * load) \ return NULL; \ \ - if (!f_val) \ + if (!f_key || !f_val) \ return NULL; \ \ size_t real_capacity = PFX##_impl_calculate_size(capacity / load); \ @@ -461,6 +461,9 @@ struct cmc_callbacks_bidimap if (capacity >= UINTMAX_MAX * load) \ return NULL; \ \ + if (!f_key || !f_val) \ + return NULL; \ + \ size_t real_capacity = PFX##_impl_calculate_size(capacity / load); \ \ if (!alloc) \ diff --git a/src/cmc/hashmap.h b/src/cmc/hashmap.h index 4a0f712..85a1dde 100644 --- a/src/cmc/hashmap.h +++ b/src/cmc/hashmap.h @@ -148,8 +148,9 @@ static const char *cmc_string_fmt_hashmap = "struct %s<%s, %s> " "capacity:%" PRIuMAX ", " "count:%" PRIuMAX ", " "load:%lf, " - "cmp:%p, " - "hash:%p, " + "flag:%d, " + "f_key:%p, " + "f_val:%p, " "alloc:%p, " "callbacks:%p }"; @@ -198,23 +199,26 @@ struct cmc_callbacks_hashmap /* Load factor in range (0.0, 1.0) */ \ double load; \ \ - /* Key comparison function */ \ - int (*cmp)(K, K); \ + /* Flags indicating errors or success */ \ + int flag; \ \ - /* Key hash function */ \ - size_t (*hash)(K); \ + /* Key function table */ \ + struct SNAME##_ftab_key *f_key; \ \ - /* Function that returns an iterator to the start of the hashmap */ \ - struct SNAME##_iter (*it_start)(struct SNAME *); \ - \ - /* Function that returns an iterator to the end of the hashmap */ \ - struct SNAME##_iter (*it_end)(struct SNAME *); \ + /* Value function table */ \ + struct SNAME##_ftab_val *f_val; \ \ /* Custom allocation functions */ \ struct cmc_alloc_node *alloc; \ \ /* Custom callback functions */ \ struct cmc_callbacks_hashmap *callbacks; \ + \ + /* Function that returns an iterator to the start of the hashmap */ \ + struct SNAME##_iter (*it_start)(struct SNAME *); \ + \ + /* Function that returns an iterator to the end of the hashmap */ \ + struct SNAME##_iter (*it_end)(struct SNAME *); \ }; \ \ /* Hashmap Entry */ \ @@ -234,6 +238,50 @@ struct cmc_callbacks_hashmap enum cmc_entry_state state; \ }; \ \ + /* Key struct function table */ \ + struct SNAME##_ftab_key \ + { \ + /* Comparator function */ \ + int (*cmp)(K, K); \ + \ + /* Copy function */ \ + K (*cpy)(K); \ + \ + /* To string function */ \ + bool (*str)(FILE *, K); \ + \ + /* Free from memory function */ \ + void (*free)(K); \ + \ + /* Hash function */ \ + size_t (*hash)(K); \ + \ + /* Priority function */ \ + int (*pri)(K, K); \ + }; \ + \ + /* Value struct function table */ \ + struct SNAME##_ftab_val \ + { \ + /* Comparator function */ \ + int (*cmp)(V, V); \ + \ + /* Copy function */ \ + V (*cpy)(V); \ + \ + /* To string function */ \ + bool (*str)(FILE *, V); \ + \ + /* Free from memory function */ \ + void (*free)(V); \ + \ + /* Hash function */ \ + size_t (*hash)(V); \ + \ + /* Priority function */ \ + int (*pri)(V, V); \ + }; \ + \ /* Hashmap Iterator */ \ struct SNAME##_iter \ { \ @@ -262,13 +310,14 @@ struct cmc_callbacks_hashmap /* 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_hashmap *callbacks); \ - void PFX##_clear(struct SNAME *_map_, void (*deallocator)(K, V)); \ - void PFX##_free(struct SNAME *_map_, void (*deallocator)(K, V)); \ + struct SNAME##_ftab_key *f_key, \ + struct SNAME##_ftab_val *f_val); \ + struct SNAME *PFX##_new_custom( \ + size_t capacity, double load, struct SNAME##_ftab_key *f_key, \ + struct SNAME##_ftab_val *f_val, struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_hashmap *callbacks); \ + void PFX##_clear(struct SNAME *_map_); \ + void PFX##_free(struct SNAME *_map_); \ /* Customization of Allocation and Callbacks */ \ void PFX##_customize(struct SNAME *_map_, struct cmc_alloc_node *alloc, \ struct cmc_callbacks_hashmap *callbacks); \ @@ -290,10 +339,8 @@ struct cmc_callbacks_hashmap 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_, \ - int (*value_comparator)(V, V)); \ + struct SNAME *PFX##_copy_of(struct SNAME *_map_); \ + bool PFX##_equals(struct SNAME *_map1_, struct SNAME *_map2_); \ struct cmc_string PFX##_to_string(struct SNAME *_map_); \ \ /* Iterator Functions */ \ @@ -322,799 +369,801 @@ struct cmc_callbacks_hashmap /* ------------------------------------------------------------------------- * Source * ------------------------------------------------------------------------- */ -#define CMC_GENERATE_HASHMAP_SOURCE(PFX, SNAME, K, V) \ - \ - /* Implementation Detail Functions */ \ - static struct SNAME##_entry *PFX##_impl_get_entry(struct SNAME *_map_, \ - K key); \ - static 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 || load >= 1) \ - 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)); \ - \ - 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_hashmap *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 *_map_ = alloc->malloc(sizeof(struct SNAME)); \ - \ - if (!_map_) \ - return NULL; \ - \ - _map_->buffer = \ - alloc->calloc(real_capacity, sizeof(struct SNAME##_entry)); \ - \ - 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)) \ - { \ - if (deallocator) \ - { \ - for (size_t i = 0; i < _map_->capacity; i++) \ - { \ - struct SNAME##_entry *entry = &(_map_->buffer[i]); \ - \ - if (entry->state == CMC_ES_FILLED) \ - { \ - deallocator(entry->key, entry->value); \ - } \ - } \ - } \ - \ - memset(_map_->buffer, 0, \ - sizeof(struct SNAME##_entry) * _map_->capacity); \ - \ - _map_->count = 0; \ - } \ - \ - void PFX##_free(struct SNAME *_map_, void (*deallocator)(K, V)) \ - { \ - if (deallocator) \ - { \ - for (size_t i = 0; i < _map_->capacity; i++) \ - { \ - struct SNAME##_entry *entry = &(_map_->buffer[i]); \ - \ - if (entry->state == CMC_ES_FILLED) \ - { \ - deallocator(entry->key, entry->value); \ - } \ - } \ - } \ - \ - _map_->alloc->free(_map_->buffer); \ - _map_->alloc->free(_map_); \ - } \ - \ - void PFX##_customize(struct SNAME *_map_, struct cmc_alloc_node *alloc, \ - struct cmc_callbacks_hashmap *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 original_pos = hash % _map_->capacity; \ - size_t pos = original_pos; \ - \ - struct SNAME##_entry *target = &(_map_->buffer[pos]); \ - \ - if (PFX##_impl_get_entry(_map_, key) != NULL) \ - return false; \ - \ - if (target->state == CMC_ES_EMPTY || target->state == CMC_ES_DELETED) \ - { \ - target->key = key; \ - target->value = value; \ - target->dist = 0; \ - target->state = CMC_ES_FILLED; \ - } \ - else \ - { \ - while (true) \ - { \ - pos++; \ - target = &(_map_->buffer[pos % _map_->capacity]); \ - \ - if (target->state == CMC_ES_EMPTY || \ - target->state == CMC_ES_DELETED) \ - { \ - target->key = key; \ - target->value = value; \ - target->dist = pos - original_pos; \ - target->state = CMC_ES_FILLED; \ - \ - break; \ - } \ - else if (target->dist < pos - original_pos) \ - { \ - K tmp_k = target->key; \ - V tmp_v = target->value; \ - size_t tmp_dist = target->dist; \ - \ - target->key = key; \ - target->value = value; \ - target->dist = pos - original_pos; \ - \ - key = tmp_k; \ - value = tmp_v; \ - original_pos = pos - tmp_dist; \ - } \ - } \ - } \ - \ - _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 true; \ - } \ - \ - bool PFX##_remove(struct SNAME *_map_, K key, V *out_value) \ - { \ - struct SNAME##_entry *result = PFX##_impl_get_entry(_map_, key); \ - \ - if (result == NULL) \ - return false; \ - \ - if (out_value) \ - *out_value = result->value; \ - \ - result->key = (K){ 0 }; \ - result->value = (V){ 0 }; \ - result->dist = 0; \ - result->state = CMC_ES_DELETED; \ - \ - _map_->count--; \ - \ - return true; \ - } \ - \ - bool PFX##_max(struct SNAME *_map_, K *key, V *value) \ - { \ - if (PFX##_empty(_map_)) \ - return false; \ - \ - struct SNAME##_iter iter; \ - PFX##_iter_init(&iter, _map_); \ - \ - K max_key = PFX##_iter_key(&iter); \ - V max_val = PFX##_iter_value(&iter); \ - \ - PFX##_iter_next(&iter); \ - \ - for (; !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \ - { \ - K iter_key = PFX##_iter_key(&iter); \ - V iter_val = PFX##_iter_value(&iter); \ - \ - if (_map_->cmp(iter_key, max_key) > 0) \ - { \ - max_key = iter_key; \ - max_val = iter_val; \ - } \ - } \ - \ - if (key) \ - *key = max_key; \ - if (value) \ - *value = max_val; \ - \ - return true; \ - } \ - \ - bool PFX##_min(struct SNAME *_map_, K *key, V *value) \ - { \ - if (PFX##_empty(_map_)) \ - return false; \ - \ - struct SNAME##_iter iter; \ - PFX##_iter_init(&iter, _map_); \ - \ - K min_key = PFX##_iter_key(&iter); \ - V min_val = PFX##_iter_value(&iter); \ - \ - PFX##_iter_next(&iter); \ - \ - for (; !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \ - { \ - K iter_key = PFX##_iter_key(&iter); \ - V iter_val = PFX##_iter_value(&iter); \ - \ - if (_map_->cmp(iter_key, min_key) < 0) \ - { \ - min_key = iter_key; \ - min_val = iter_val; \ - } \ - } \ - \ - if (key) \ - *key = min_key; \ - if (value) \ - *value = min_val; \ - \ - 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##_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 / _map_->load) \ - return true; \ - \ - /* Prevent integer overflow */ \ - if (capacity >= UINTMAX_MAX * _map_->load) \ - 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 < _map_->count / _map_->load) \ - return false; \ - \ - struct SNAME *_new_map_ = \ - PFX##_new_custom(capacity, _map_->load, _map_->cmp, _map_->hash, \ - _map_->alloc, _map_->callbacks); \ - \ - 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 = _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_custom(_map_->capacity, _map_->load, _map_->cmp, \ - _map_->hash, _map_->alloc, _map_->callbacks); \ - \ - if (!result) \ - return NULL; \ - \ - if (key_copy_func || value_copy_func) \ - { \ - for (size_t i = 0; i < _map_->capacity; i++) \ - { \ - struct SNAME##_entry *scan = &(_map_->buffer[i]); \ - \ - if (scan->state != CMC_ES_EMPTY) \ - { \ - struct SNAME##_entry *target = &(result->buffer[i]); \ - \ - if (scan->state == CMC_ES_DELETED) \ - target->state = CMC_ES_DELETED; \ - else \ - { \ - target->state = scan->state; \ - target->dist = scan->dist; \ - \ - if (key_copy_func) \ - target->key = key_copy_func(scan->key); \ - else \ - target->key = scan->key; \ - \ - if (value_copy_func) \ - target->value = value_copy_func(scan->value); \ - else \ - target->value = scan->value; \ - } \ - } \ - } \ - } \ - else \ - memcpy(result->buffer, _map_->buffer, \ - sizeof(struct SNAME##_entry) * _map_->capacity); \ - \ - result->count = _map_->count; \ - \ - return result; \ - } \ - \ - bool PFX##_equals(struct SNAME *_map1_, struct SNAME *_map2_, \ - int (*value_comparator)(V, V)) \ - { \ - 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)) \ - { \ - struct SNAME##_entry *entry = \ - PFX##_impl_get_entry(_map2_, PFX##_iter_key(&iter)); \ - \ - if (entry == NULL) \ - return false; \ - \ - if (value_comparator) \ - { \ - if (value_comparator(entry->value, PFX##_iter_value(&iter)) != \ - 0) \ - 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_hashmap, #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 = \ - 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) \ - { \ - 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].state == CMC_ES_FILLED) \ - { \ - iter->first = i; \ - break; \ - } \ - } \ - \ - iter->cursor = iter->first; \ - \ - for (size_t i = target->capacity; i > 0; i--) \ - { \ - if (target->buffer[i - 1].state == CMC_ES_FILLED) \ - { \ - 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); \ - } \ - } \ - \ - void PFX##_iter_to_end(struct SNAME##_iter *iter) \ - { \ - if (!PFX##_empty(iter->target)) \ - { \ - iter->cursor = iter->last; \ - iter->index = PFX##_count(iter->target) - 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->index + 1 == PFX##_count(iter->target)) \ - { \ - iter->end = true; \ - return false; \ - } \ - \ - iter->start = PFX##_empty(iter->target); \ - \ - struct SNAME##_entry *scan = &(iter->target->buffer[iter->cursor]); \ - \ - iter->index++; \ - \ - while (1) \ - { \ - iter->cursor++; \ - scan = &(iter->target->buffer[iter->cursor]); \ - \ - if (scan->state == CMC_ES_FILLED) \ - break; \ - } \ - \ - return true; \ - } \ - \ - bool PFX##_iter_prev(struct SNAME##_iter *iter) \ - { \ - if (iter->start) \ - return false; \ - \ - if (iter->index == 0) \ - { \ - iter->start = true; \ - return false; \ - } \ - \ - iter->end = PFX##_empty(iter->target); \ - \ - struct SNAME##_entry *scan = &(iter->target->buffer[iter->cursor]); \ - \ - iter->index--; \ - \ - while (1) \ - { \ - iter->cursor--; \ - scan = &(iter->target->buffer[iter->cursor]); \ - \ - if (scan->state == CMC_ES_FILLED) \ - break; \ - } \ - \ - 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->target->buffer[iter->cursor].key; \ - } \ - \ - V PFX##_iter_value(struct SNAME##_iter *iter) \ - { \ - if (PFX##_empty(iter->target)) \ - return (V){ 0 }; \ - \ - return iter->target->buffer[iter->cursor].value; \ - } \ - \ - V *PFX##_iter_rvalue(struct SNAME##_iter *iter) \ - { \ - if (PFX##_empty(iter->target)) \ - return NULL; \ - \ - return &(iter->target->buffer[iter->cursor].value); \ - } \ - \ - size_t PFX##_iter_index(struct SNAME##_iter *iter) \ - { \ - return iter->index; \ - } \ - \ - static struct SNAME##_entry *PFX##_impl_get_entry(struct SNAME *_map_, \ - K key) \ - { \ - size_t hash = _map_->hash(key); \ - size_t pos = hash % _map_->capacity; \ - \ - struct SNAME##_entry *target = &(_map_->buffer[pos]); \ - \ - while (target->state == CMC_ES_FILLED || \ - target->state == CMC_ES_DELETED) \ - { \ - if (_map_->cmp(target->key, key) == 0) \ - return target; \ - \ - pos++; \ - target = &(_map_->buffer[pos % _map_->capacity]); \ - } \ - \ - return NULL; \ - } \ - \ - static 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; \ +#define CMC_GENERATE_HASHMAP_SOURCE(PFX, SNAME, K, V) \ + \ + /* Implementation Detail Functions */ \ + static struct SNAME##_entry *PFX##_impl_get_entry(struct SNAME *_map_, \ + K key); \ + static 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, \ + struct SNAME##_ftab_key *f_key, \ + struct SNAME##_ftab_val *f_val) \ + { \ + struct cmc_alloc_node *alloc = &cmc_alloc_node_default; \ + \ + if (capacity == 0 || load <= 0 || load >= 1) \ + return NULL; \ + \ + /* Prevent integer overflow */ \ + if (capacity >= UINTMAX_MAX * load) \ + return NULL; \ + \ + if (!f_key || !f_val) \ + 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)); \ + \ + if (!_map_->buffer) \ + { \ + alloc->free(_map_); \ + return NULL; \ + } \ + \ + _map_->count = 0; \ + _map_->capacity = real_capacity; \ + _map_->load = load; \ + _map_->flag = cmc_flags.OK; \ + _map_->f_key = f_key; \ + _map_->f_val = f_val; \ + _map_->alloc = alloc; \ + _map_->callbacks = NULL; \ + _map_->it_start = PFX##_impl_it_start; \ + _map_->it_end = PFX##_impl_it_end; \ + \ + return _map_; \ + } \ + \ + struct SNAME *PFX##_new_custom( \ + size_t capacity, double load, struct SNAME##_ftab_key *f_key, \ + struct SNAME##_ftab_val *f_val, struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_hashmap *callbacks) \ + { \ + if (capacity == 0 || load <= 0 || load >= 1) \ + return NULL; \ + \ + /* Prevent integer overflow */ \ + if (capacity >= UINTMAX_MAX * load) \ + return NULL; \ + \ + if (!f_key || !f_val) \ + return NULL; \ + \ + size_t real_capacity = PFX##_impl_calculate_size(capacity / load); \ + \ + if (!alloc) \ + alloc = &cmc_alloc_node_default; \ + \ + struct SNAME *_map_ = alloc->malloc(sizeof(struct SNAME)); \ + \ + if (!_map_) \ + return NULL; \ + \ + _map_->buffer = \ + alloc->calloc(real_capacity, sizeof(struct SNAME##_entry)); \ + \ + if (!_map_->buffer) \ + { \ + alloc->free(_map_); \ + return NULL; \ + } \ + \ + _map_->count = 0; \ + _map_->capacity = real_capacity; \ + _map_->load = load; \ + _map_->flag = cmc_flags.OK; \ + _map_->f_key = f_key; \ + _map_->f_val = f_val; \ + _map_->alloc = alloc; \ + _map_->callbacks = callbacks; \ + _map_->it_start = PFX##_impl_it_start; \ + _map_->it_end = PFX##_impl_it_end; \ + \ + return _map_; \ + } \ + \ + void PFX##_clear(struct SNAME *_map_) \ + { \ + if (_map_->f_key->free || _map_->f_val->free) \ + { \ + for (size_t i = 0; i < _map_->capacity; i++) \ + { \ + struct SNAME##_entry *entry = &(_map_->buffer[i]); \ + \ + if (entry->state == CMC_ES_FILLED) \ + { \ + if (_map_->f_key->free) \ + _map_->f_key->free(entry->key); \ + if (_map_->f_val->free) \ + _map_->f_val->free(entry->value); \ + } \ + } \ + } \ + \ + memset(_map_->buffer, 0, \ + sizeof(struct SNAME##_entry) * _map_->capacity); \ + \ + _map_->count = 0; \ + } \ + \ + void PFX##_free(struct SNAME *_map_) \ + { \ + if (_map_->f_key->free || _map_->f_val->free) \ + { \ + for (size_t i = 0; i < _map_->capacity; i++) \ + { \ + struct SNAME##_entry *entry = &(_map_->buffer[i]); \ + \ + if (entry->state == CMC_ES_FILLED) \ + { \ + if (_map_->f_key->free) \ + _map_->f_key->free(entry->key); \ + if (_map_->f_val->free) \ + _map_->f_val->free(entry->value); \ + } \ + } \ + } \ + \ + _map_->alloc->free(_map_->buffer); \ + _map_->alloc->free(_map_); \ + } \ + \ + void PFX##_customize(struct SNAME *_map_, struct cmc_alloc_node *alloc, \ + struct cmc_callbacks_hashmap *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_->f_key->hash(key); \ + size_t original_pos = hash % _map_->capacity; \ + size_t pos = original_pos; \ + \ + struct SNAME##_entry *target = &(_map_->buffer[pos]); \ + \ + if (PFX##_impl_get_entry(_map_, key) != NULL) \ + return false; \ + \ + if (target->state == CMC_ES_EMPTY || target->state == CMC_ES_DELETED) \ + { \ + target->key = key; \ + target->value = value; \ + target->dist = 0; \ + target->state = CMC_ES_FILLED; \ + } \ + else \ + { \ + while (true) \ + { \ + pos++; \ + target = &(_map_->buffer[pos % _map_->capacity]); \ + \ + if (target->state == CMC_ES_EMPTY || \ + target->state == CMC_ES_DELETED) \ + { \ + target->key = key; \ + target->value = value; \ + target->dist = pos - original_pos; \ + target->state = CMC_ES_FILLED; \ + \ + break; \ + } \ + else if (target->dist < pos - original_pos) \ + { \ + K tmp_k = target->key; \ + V tmp_v = target->value; \ + size_t tmp_dist = target->dist; \ + \ + target->key = key; \ + target->value = value; \ + target->dist = pos - original_pos; \ + \ + key = tmp_k; \ + value = tmp_v; \ + original_pos = pos - tmp_dist; \ + } \ + } \ + } \ + \ + _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 true; \ + } \ + \ + bool PFX##_remove(struct SNAME *_map_, K key, V *out_value) \ + { \ + struct SNAME##_entry *result = PFX##_impl_get_entry(_map_, key); \ + \ + if (result == NULL) \ + return false; \ + \ + if (out_value) \ + *out_value = result->value; \ + \ + result->key = (K){ 0 }; \ + result->value = (V){ 0 }; \ + result->dist = 0; \ + result->state = CMC_ES_DELETED; \ + \ + _map_->count--; \ + \ + return true; \ + } \ + \ + bool PFX##_max(struct SNAME *_map_, K *key, V *value) \ + { \ + if (PFX##_empty(_map_)) \ + return false; \ + \ + struct SNAME##_iter iter; \ + PFX##_iter_init(&iter, _map_); \ + \ + K max_key = PFX##_iter_key(&iter); \ + V max_val = PFX##_iter_value(&iter); \ + \ + PFX##_iter_next(&iter); \ + \ + for (; !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \ + { \ + K iter_key = PFX##_iter_key(&iter); \ + V iter_val = PFX##_iter_value(&iter); \ + \ + if (_map_->f_key->cmp(iter_key, max_key) > 0) \ + { \ + max_key = iter_key; \ + max_val = iter_val; \ + } \ + } \ + \ + if (key) \ + *key = max_key; \ + if (value) \ + *value = max_val; \ + \ + return true; \ + } \ + \ + bool PFX##_min(struct SNAME *_map_, K *key, V *value) \ + { \ + if (PFX##_empty(_map_)) \ + return false; \ + \ + struct SNAME##_iter iter; \ + PFX##_iter_init(&iter, _map_); \ + \ + K min_key = PFX##_iter_key(&iter); \ + V min_val = PFX##_iter_value(&iter); \ + \ + PFX##_iter_next(&iter); \ + \ + for (; !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \ + { \ + K iter_key = PFX##_iter_key(&iter); \ + V iter_val = PFX##_iter_value(&iter); \ + \ + if (_map_->f_key->cmp(iter_key, min_key) < 0) \ + { \ + min_key = iter_key; \ + min_val = iter_val; \ + } \ + } \ + \ + if (key) \ + *key = min_key; \ + if (value) \ + *value = min_val; \ + \ + 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##_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 / _map_->load) \ + return true; \ + \ + /* Prevent integer overflow */ \ + if (capacity >= UINTMAX_MAX * _map_->load) \ + 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 < _map_->count / _map_->load) \ + return false; \ + \ + struct SNAME *_new_map_ = \ + PFX##_new_custom(capacity, _map_->load, _map_->f_key, \ + _map_->f_val, _map_->alloc, _map_->callbacks); \ + \ + 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_); \ + return false; \ + } \ + \ + struct SNAME##_entry *tmp_b = _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_); \ + \ + return true; \ + } \ + \ + struct SNAME *PFX##_copy_of(struct SNAME *_map_) \ + { \ + struct SNAME *result = \ + PFX##_new_custom(_map_->capacity, _map_->load, _map_->f_key, \ + _map_->f_val, _map_->alloc, _map_->callbacks); \ + \ + if (!result) \ + return NULL; \ + \ + if (_map_->f_key->cpy || _map_->f_val->cpy) \ + { \ + for (size_t i = 0; i < _map_->capacity; i++) \ + { \ + struct SNAME##_entry *scan = &(_map_->buffer[i]); \ + \ + if (scan->state != CMC_ES_EMPTY) \ + { \ + struct SNAME##_entry *target = &(result->buffer[i]); \ + \ + if (scan->state == CMC_ES_DELETED) \ + target->state = CMC_ES_DELETED; \ + else \ + { \ + target->state = scan->state; \ + target->dist = scan->dist; \ + \ + if (_map_->f_key->cpy) \ + target->key = _map_->f_key->cpy(scan->key); \ + else \ + target->key = scan->key; \ + \ + if (_map_->f_val->cpy) \ + target->value = _map_->f_val->cpy(scan->value); \ + else \ + target->value = scan->value; \ + } \ + } \ + } \ + } \ + else \ + memcpy(result->buffer, _map_->buffer, \ + sizeof(struct SNAME##_entry) * _map_->capacity); \ + \ + result->count = _map_->count; \ + \ + return result; \ + } \ + \ + bool PFX##_equals(struct SNAME *_map1_, struct SNAME *_map2_) \ + { \ + 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)) \ + { \ + struct SNAME##_entry *entry = \ + PFX##_impl_get_entry(_map2_, PFX##_iter_key(&iter)); \ + \ + if (entry == NULL) \ + return false; \ + \ + if (_map1_->f_val->cmp(entry->value, PFX##_iter_value(&iter)) != \ + 0) \ + 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_hashmap, \ + #SNAME, #K, #V, m_, m_->buffer, m_->capacity, \ + m_->count, m_->load, m_->flag, m_->f_key, m_->f_val, \ + m_->alloc, m_->callbacks); \ + \ + return n >= 0 ? str : (struct cmc_string){ 0 }; \ + } \ + \ + 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) \ + { \ + 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].state == CMC_ES_FILLED) \ + { \ + iter->first = i; \ + break; \ + } \ + } \ + \ + iter->cursor = iter->first; \ + \ + for (size_t i = target->capacity; i > 0; i--) \ + { \ + if (target->buffer[i - 1].state == CMC_ES_FILLED) \ + { \ + 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); \ + } \ + } \ + \ + void PFX##_iter_to_end(struct SNAME##_iter *iter) \ + { \ + if (!PFX##_empty(iter->target)) \ + { \ + iter->cursor = iter->last; \ + iter->index = PFX##_count(iter->target) - 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->index + 1 == PFX##_count(iter->target)) \ + { \ + iter->end = true; \ + return false; \ + } \ + \ + iter->start = PFX##_empty(iter->target); \ + \ + struct SNAME##_entry *scan = &(iter->target->buffer[iter->cursor]); \ + \ + iter->index++; \ + \ + while (1) \ + { \ + iter->cursor++; \ + scan = &(iter->target->buffer[iter->cursor]); \ + \ + if (scan->state == CMC_ES_FILLED) \ + break; \ + } \ + \ + return true; \ + } \ + \ + bool PFX##_iter_prev(struct SNAME##_iter *iter) \ + { \ + if (iter->start) \ + return false; \ + \ + if (iter->index == 0) \ + { \ + iter->start = true; \ + return false; \ + } \ + \ + iter->end = PFX##_empty(iter->target); \ + \ + struct SNAME##_entry *scan = &(iter->target->buffer[iter->cursor]); \ + \ + iter->index--; \ + \ + while (1) \ + { \ + iter->cursor--; \ + scan = &(iter->target->buffer[iter->cursor]); \ + \ + if (scan->state == CMC_ES_FILLED) \ + break; \ + } \ + \ + 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->target->buffer[iter->cursor].key; \ + } \ + \ + V PFX##_iter_value(struct SNAME##_iter *iter) \ + { \ + if (PFX##_empty(iter->target)) \ + return (V){ 0 }; \ + \ + return iter->target->buffer[iter->cursor].value; \ + } \ + \ + V *PFX##_iter_rvalue(struct SNAME##_iter *iter) \ + { \ + if (PFX##_empty(iter->target)) \ + return NULL; \ + \ + return &(iter->target->buffer[iter->cursor].value); \ + } \ + \ + size_t PFX##_iter_index(struct SNAME##_iter *iter) \ + { \ + return iter->index; \ + } \ + \ + static struct SNAME##_entry *PFX##_impl_get_entry(struct SNAME *_map_, \ + K key) \ + { \ + size_t hash = _map_->f_key->hash(key); \ + size_t pos = hash % _map_->capacity; \ + \ + struct SNAME##_entry *target = &(_map_->buffer[pos]); \ + \ + while (target->state == CMC_ES_FILLED || \ + target->state == CMC_ES_DELETED) \ + { \ + if (_map_->f_key->cmp(target->key, key) == 0) \ + return target; \ + \ + pos++; \ + target = &(_map_->buffer[pos % _map_->capacity]); \ + } \ + \ + return NULL; \ + } \ + \ + static 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_HASHMAP_H */ diff --git a/src/cmc/queue.h b/src/cmc/queue.h index aeef0fa..77a20b5 100644 --- a/src/cmc/queue.h +++ b/src/cmc/queue.h @@ -504,6 +504,8 @@ struct cmc_callbacks_queue } \ \ result->count = _queue_->count; \ + result->front = 0; \ + result->back = _queue_->count; \ \ return result; \ } \ diff --git a/tests/main/unt/hashmap.c b/tests/main/unt/hashmap.c index 98ebf9e..3adc809 100644 --- a/tests/main/unt/hashmap.c +++ b/tests/main/unt/hashmap.c @@ -7,32 +7,48 @@ CMC_GENERATE_HASHMAP(hm, hashmap, size_t, size_t) +struct hashmap_ftab_key *hm_ftab_key = + &(struct hashmap_ftab_key){ .cmp = cmp, + .cpy = copy, + .str = str, + .free = custom_free, + .hash = hash, + .pri = pri }; + +struct hashmap_ftab_val *hm_ftab_val = + &(struct hashmap_ftab_val){ .cmp = cmp, + .cpy = copy, + .str = str, + .free = custom_free, + .hash = hash, + .pri = pri }; + CMC_CREATE_UNIT(hashmap_test, true, { CMC_CREATE_TEST(new, { - struct hashmap *map = hm_new(943722, 0.6, cmp, hash); + struct hashmap *map = hm_new(943722, 0.6, hm_ftab_key, hm_ftab_val); cmc_assert_not_equals(ptr, NULL, map); cmc_assert_not_equals(ptr, NULL, map->buffer); cmc_assert_equals(size_t, 0, hm_count(map)); cmc_assert_greater_equals(size_t, (943722 / 0.6), hm_capacity(map)); - hm_free(map, NULL); + hm_free(map); }); CMC_CREATE_TEST(new[capacity = 0], { - struct hashmap *map = hm_new(0, 0.6, cmp, hash); + struct hashmap *map = hm_new(0, 0.6, hm_ftab_key, hm_ftab_val); cmc_assert_equals(ptr, NULL, map); }); CMC_CREATE_TEST(new[capacity = UINT64_MAX], { - struct hashmap *map = hm_new(UINT64_MAX, 0.99, cmp, hash); + struct hashmap *map = hm_new(UINT64_MAX, 0.99, hm_ftab_key, hm_ftab_val); cmc_assert_equals(ptr, NULL, map); }); CMC_CREATE_TEST(clear[count capacity], { - struct hashmap *map = hm_new(100, 0.6, cmp, hash); + struct hashmap *map = hm_new(100, 0.6, hm_ftab_key, hm_ftab_val); cmc_assert_not_equals(ptr, NULL, map); @@ -41,38 +57,41 @@ CMC_CREATE_UNIT(hashmap_test, true, { cmc_assert_equals(size_t, 50, hm_count(map)); - hm_clear(map, NULL); + hm_clear(map); cmc_assert_equals(size_t, 0, hm_count(map)); - hm_free(map, NULL); + hm_free(map); }); CMC_CREATE_TEST(insert, { - struct hashmap *map = hm_new(100, 0.6, cmp, hash); + struct hashmap *map = hm_new(100, 0.6, hm_ftab_key, hm_ftab_val); cmc_assert_not_equals(ptr, NULL, map); cmc_assert(hm_insert(map, 1, 1)); cmc_assert_equals(size_t, 1, hm_count(map)); - hm_free(map, NULL); + hm_free(map); }); CMC_CREATE_TEST(insert[smallest capacity], { - struct hashmap *map = hm_new(1, 0.99, cmp, hash); + struct hashmap *map = hm_new(1, 0.99, hm_ftab_key, hm_ftab_val); cmc_assert_not_equals(ptr, NULL, map); cmc_assert_equals(size_t, cmc_hashtable_primes[0], hm_capacity(map)); cmc_assert(hm_insert(map, 1, 1)); - hm_free(map, NULL); + hm_free(map); }); CMC_CREATE_TEST(insert[element position], { + struct hashmap *map = hm_new(1, 0.99, hm_ftab_key, hm_ftab_val); + + // Temporary change // Using the numhash the key is the hash itself - struct hashmap *map = hm_new(1, 0.99, cmp, numhash); + hm_ftab_key->hash = numhash; cmc_assert_not_equals(ptr, NULL, map); @@ -86,11 +105,16 @@ CMC_CREATE_UNIT(hashmap_test, true, { cmc_assert_equals(size_t, capacity - 1, map->buffer[capacity - 1].key); cmc_assert_equals(size_t, capacity, map->buffer[0].key); - hm_free(map, NULL); + hm_ftab_key->hash = hash; + + hm_free(map); }); CMC_CREATE_TEST(insert[distance], { - struct hashmap *map = hm_new(500, 0.6, cmp, hash0); + struct hashmap *map = hm_new(500, 0.6, hm_ftab_key, hm_ftab_val); + + // Temporary change + hm_ftab_key->hash = hash0; cmc_assert_not_equals(ptr, NULL, map); @@ -102,11 +126,16 @@ CMC_CREATE_UNIT(hashmap_test, true, { for (size_t i = 0; i < 200; i++) cmc_assert_equals(size_t, i, map->buffer[i].dist); - hm_free(map, NULL); + hm_ftab_key->hash = hash; + + hm_free(map); }); CMC_CREATE_TEST(insert[distance wrap], { - struct hashmap *map = hm_new(1, 0.99, cmp, hashcapminus1); + struct hashmap *map = hm_new(1, 0.99, hm_ftab_key, hm_ftab_val); + + // Temporary change + hm_ftab_key->hash = hashcapminus1; cmc_assert_not_equals(ptr, NULL, map); @@ -123,11 +152,16 @@ CMC_CREATE_UNIT(hashmap_test, true, { cmc_assert_equals(size_t, 0, map->buffer[capacity - 1].dist); cmc_assert_equals(size_t, 1, map->buffer[0].dist); - hm_free(map, NULL); + hm_ftab_key->hash = hash; + + hm_free(map); }); CMC_CREATE_TEST(insert[distances], { - struct hashmap *map = hm_new(1, 0.99, cmp, hashcapminus4); + struct hashmap *map = hm_new(1, 0.99, hm_ftab_key, hm_ftab_val); + + // Temporary change + hm_ftab_key->hash = hashcapminus4; cmc_assert_not_equals(ptr, NULL, map); @@ -139,11 +173,13 @@ CMC_CREATE_UNIT(hashmap_test, true, { for (size_t i = 0; i < 6; i++) cmc_assert_equals(size_t, i, hm_impl_get_entry(map, i)->dist); - hm_free(map, NULL); + hm_ftab_key->hash = hash; + + hm_free(map); }); CMC_CREATE_TEST(insert[buffer growth and item preservation], { - struct hashmap *map = hm_new(1, 0.99, cmp, hash); + struct hashmap *map = hm_new(1, 0.99, hm_ftab_key, hm_ftab_val); cmc_assert_not_equals(ptr, NULL, map); @@ -163,11 +199,11 @@ CMC_CREATE_UNIT(hashmap_test, true, { for (size_t i = 0; i < 100000; i++) cmc_assert(hm_contains(map, i)); - hm_free(map, NULL); + hm_free(map); }); CMC_CREATE_TEST(update, { - struct hashmap *map = hm_new(100, 0.6, cmp, hash); + struct hashmap *map = hm_new(100, 0.6, hm_ftab_key, hm_ftab_val); cmc_assert_not_equals(ptr, NULL, map); @@ -178,11 +214,11 @@ CMC_CREATE_UNIT(hashmap_test, true, { cmc_assert_equals(size_t, 1, old); - hm_free(map, NULL); + hm_free(map); }); CMC_CREATE_TEST(update[key not found], { - struct hashmap *map = hm_new(100, 0.6, cmp, hash); + struct hashmap *map = hm_new(100, 0.6, hm_ftab_key, hm_ftab_val); cmc_assert_not_equals(ptr, NULL, map); @@ -191,11 +227,11 @@ CMC_CREATE_UNIT(hashmap_test, true, { cmc_assert(!hm_update(map, 120, 120, NULL)); - hm_free(map, NULL); + hm_free(map); }); CMC_CREATE_TEST(remove, { - struct hashmap *map = hm_new(100, 0.6, cmp, hash); + struct hashmap *map = hm_new(100, 0.6, hm_ftab_key, hm_ftab_val); cmc_assert_not_equals(ptr, NULL, map); @@ -205,22 +241,22 @@ CMC_CREATE_UNIT(hashmap_test, true, { for (size_t i = 0; i < 100; i++) cmc_assert(hm_remove(map, i, NULL)); - hm_free(map, NULL); + hm_free(map); }); CMC_CREATE_TEST(remove[count = 0], { - struct hashmap *map = hm_new(100, 0.6, cmp, hash); + struct hashmap *map = hm_new(100, 0.6, hm_ftab_key, hm_ftab_val); cmc_assert_not_equals(ptr, NULL, map); for (size_t i = 100; i < 200; i++) cmc_assert(!hm_remove(map, i, NULL)); - hm_free(map, NULL); + hm_free(map); }); CMC_CREATE_TEST(remove[key not found], { - struct hashmap *map = hm_new(100, 0.6, cmp, hash); + struct hashmap *map = hm_new(100, 0.6, hm_ftab_key, hm_ftab_val); cmc_assert_not_equals(ptr, NULL, map); @@ -230,11 +266,11 @@ CMC_CREATE_UNIT(hashmap_test, true, { for (size_t i = 100; i < 200; i++) cmc_assert(!hm_remove(map, i, NULL)); - hm_free(map, NULL); + hm_free(map); }); CMC_CREATE_TEST(max, { - struct hashmap *map = hm_new(100, 0.6, cmp, hash); + struct hashmap *map = hm_new(100, 0.6, hm_ftab_key, hm_ftab_val); cmc_assert_not_equals(ptr, NULL, map); @@ -248,21 +284,21 @@ CMC_CREATE_UNIT(hashmap_test, true, { cmc_assert_equals(size_t, 100, key); cmc_assert_equals(size_t, 100, val); - hm_free(map, NULL); + hm_free(map); }); CMC_CREATE_TEST(max[count = 0], { - struct hashmap *map = hm_new(100, 0.6, cmp, hash); + struct hashmap *map = hm_new(100, 0.6, hm_ftab_key, hm_ftab_val); cmc_assert_not_equals(ptr, NULL, map); cmc_assert(!hm_min(map, NULL, NULL)); - hm_free(map, NULL); + hm_free(map); }); CMC_CREATE_TEST(min, { - struct hashmap *map = hm_new(100, 0.6, cmp, hash); + struct hashmap *map = hm_new(100, 0.6, hm_ftab_key, hm_ftab_val); cmc_assert_not_equals(ptr, NULL, map); @@ -276,21 +312,21 @@ CMC_CREATE_UNIT(hashmap_test, true, { cmc_assert_equals(size_t, 1, key); cmc_assert_equals(size_t, 1, val); - hm_free(map, NULL); + hm_free(map); }); CMC_CREATE_TEST(min[count = 0], { - struct hashmap *map = hm_new(100, 0.6, cmp, hash); + struct hashmap *map = hm_new(100, 0.6, hm_ftab_key, hm_ftab_val); cmc_assert_not_equals(ptr, NULL, map); cmc_assert(!hm_min(map, NULL, NULL)); - hm_free(map, NULL); + hm_free(map); }); CMC_CREATE_TEST(get, { - struct hashmap *map = hm_new(100, 0.6, cmp, hash); + struct hashmap *map = hm_new(100, 0.6, hm_ftab_key, hm_ftab_val); cmc_assert_not_equals(ptr, NULL, map); @@ -298,21 +334,21 @@ CMC_CREATE_UNIT(hashmap_test, true, { cmc_assert_equals(size_t, 1234, hm_get(map, 4321)); - hm_free(map, NULL); + hm_free(map); }); CMC_CREATE_TEST(get[count = 0], { - struct hashmap *map = hm_new(100, 0.6, cmp, hash); + struct hashmap *map = hm_new(100, 0.6, hm_ftab_key, hm_ftab_val); cmc_assert_not_equals(ptr, NULL, map); cmc_assert_equals(size_t, (size_t){ 0 }, hm_get(map, 4321)); - hm_free(map, NULL); + hm_free(map); }); CMC_CREATE_TEST(get_ref, { - struct hashmap *map = hm_new(100, 0.6, cmp, hash); + struct hashmap *map = hm_new(100, 0.6, hm_ftab_key, hm_ftab_val); cmc_assert_not_equals(ptr, NULL, map); @@ -323,21 +359,21 @@ CMC_CREATE_UNIT(hashmap_test, true, { cmc_assert_not_equals(ptr, NULL, result); cmc_assert_equals(size_t, 1234, *result); - hm_free(map, NULL); + hm_free(map); }); CMC_CREATE_TEST(get_ref[count = 0], { - struct hashmap *map = hm_new(100, 0.6, cmp, hash); + struct hashmap *map = hm_new(100, 0.6, hm_ftab_key, hm_ftab_val); cmc_assert_not_equals(ptr, NULL, map); cmc_assert_equals(ptr, NULL, hm_get_ref(map, 4321)); - hm_free(map, NULL); + hm_free(map); }); CMC_CREATE_TEST(contains, { - struct hashmap *map = hm_new(100, 0.6, cmp, hash); + struct hashmap *map = hm_new(100, 0.6, hm_ftab_key, hm_ftab_val); cmc_assert_not_equals(ptr, NULL, map); @@ -345,21 +381,21 @@ CMC_CREATE_UNIT(hashmap_test, true, { cmc_assert(hm_contains(map, 987654321)); - hm_free(map, NULL); + hm_free(map); }); CMC_CREATE_TEST(contains[count = 0], { - struct hashmap *map = hm_new(100, 0.6, cmp, hash); + struct hashmap *map = hm_new(100, 0.6, hm_ftab_key, hm_ftab_val); cmc_assert_not_equals(ptr, NULL, map); cmc_assert(!hm_contains(map, 987654321)); - hm_free(map, NULL); + hm_free(map); }); CMC_CREATE_TEST(contains[sum], { - struct hashmap *map = hm_new(100, 0.6, cmp, hash); + struct hashmap *map = hm_new(100, 0.6, hm_ftab_key, hm_ftab_val); cmc_assert_not_equals(ptr, NULL, map); @@ -373,11 +409,11 @@ CMC_CREATE_UNIT(hashmap_test, true, { cmc_assert_equals(size_t, 15050, sum); - hm_free(map, NULL); + hm_free(map); }); CMC_CREATE_TEST(empty, { - struct hashmap *map = hm_new(100, 0.6, cmp, hash); + struct hashmap *map = hm_new(100, 0.6, hm_ftab_key, hm_ftab_val); cmc_assert_not_equals(ptr, NULL, map); @@ -387,12 +423,12 @@ CMC_CREATE_UNIT(hashmap_test, true, { cmc_assert(!hm_empty(map)); - hm_free(map, NULL); + hm_free(map); }); CMC_CREATE_TEST(full, { struct hashmap *map = - hm_new(cmc_hashtable_primes[0], 0.99999, cmp, hash); + hm_new(cmc_hashtable_primes[0], 0.99999, hm_ftab_key, hm_ftab_val); cmc_assert_not_equals(ptr, NULL, map); @@ -409,11 +445,11 @@ CMC_CREATE_UNIT(hashmap_test, true, { cmc_assert(!hm_full(map)); - hm_free(map, NULL); + hm_free(map); }); CMC_CREATE_TEST(count, { - struct hashmap *map = hm_new(100, 0.6, cmp, hash); + struct hashmap *map = hm_new(100, 0.6, hm_ftab_key, hm_ftab_val); cmc_assert_not_equals(ptr, NULL, map); @@ -423,37 +459,37 @@ CMC_CREATE_UNIT(hashmap_test, true, { cmc_assert_equals(size_t, i, hm_count(map)); } - hm_free(map, NULL); + hm_free(map); }); CMC_CREATE_TEST(capacity, { - struct hashmap *map = hm_new(2500, 0.6, cmp, hash); + struct hashmap *map = hm_new(2500, 0.6, hm_ftab_key, hm_ftab_val); cmc_assert_not_equals(ptr, NULL, map); cmc_assert_greater_equals(size_t, (size_t)(2500 / 0.6), hm_capacity(map)); - hm_free(map, NULL); + hm_free(map); }); CMC_CREATE_TEST(capacity[small], { - struct hashmap *map = hm_new(1, 0.99, cmp, hash); + struct hashmap *map = hm_new(1, 0.99, hm_ftab_key, hm_ftab_val); cmc_assert_not_equals(ptr, NULL, map); cmc_assert_equals(size_t, cmc_hashtable_primes[0], hm_capacity(map)); - hm_free(map, NULL); + hm_free(map); }); CMC_CREATE_TEST(load, { - struct hashmap *map = hm_new(1, 0.99, cmp, hash); + struct hashmap *map = hm_new(1, 0.99, hm_ftab_key, hm_ftab_val); cmc_assert_not_equals(ptr, NULL, map); cmc_assert_in_range(double, 0.99 - 0.0001, 0.99 + 0.0001, hm_load(map)); - hm_free(map, NULL); + hm_free(map); }); });