From 2d3b441d74be0bb01dc5f5502e5db05cd3e85e1d Mon Sep 17 00:00:00 2001 From: Leonardo Date: Wed, 16 Oct 2019 21:34:30 -0300 Subject: [PATCH] Added resize to multimap, multiset and sortedlist --- src/ext/multimap.h | 1766 ++++++++++++++++++----------------- src/ext/multiset.h | 102 +- src/ext/sortedlist.h | 41 +- tests/main/unt/multimap.c | 20 +- tests/main/unt/multiset.c | 73 +- tests/main/unt/sortedlist.c | 2 +- 6 files changed, 1067 insertions(+), 937 deletions(-) diff --git a/src/ext/multimap.h b/src/ext/multimap.h index c758450..07df95e 100644 --- a/src/ext/multimap.h +++ b/src/ext/multimap.h @@ -196,10 +196,13 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, /* Collection State */ \ bool PFX##_contains(SNAME *_map_, K key); \ bool PFX##_empty(SNAME *_map_); \ + bool PFX##_full(SNAME *_map_); \ size_t PFX##_count(SNAME *_map_); \ - bool PFX##_key_count(SNAME *_map_, K key); \ + size_t PFX##_key_count(SNAME *_map_, K key); \ size_t PFX##_capacity(SNAME *_map_); \ + double PFX##_load(SNAME *_map_); \ /* Collection Utility */ \ + bool PFX##_resize(SNAME *_map_, size_t capacity); \ SNAME *PFX##_copy_of(SNAME *_map_, K (*key_copy_func)(K), V (*value_copy_func)(V)); \ bool PFX##_equals(SNAME *_map1_, SNAME *_map2_, bool ignore_key_count); \ cmc_string PFX##_to_string(SNAME *_map_); \ @@ -248,878 +251,895 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, } \ \ /* SOURCE ********************************************************************/ -#define CMC_GENERATE_MULTIMAP_SOURCE(PFX, SNAME, K, V) \ - \ - /* Implementation Detail Functions */ \ - bool PFX##_impl_grow(SNAME *_map_); \ - SNAME##_entry *PFX##_impl_new_entry(K key, V value); \ - SNAME##_entry *PFX##_impl_get_entry(SNAME *_map_, K key); \ - size_t PFX##_impl_calculate_size(size_t required); \ - static SNAME##_iter PFX##_impl_it_start(SNAME *_map_); \ - static SNAME##_iter PFX##_impl_it_end(SNAME *_map_); \ - \ - 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); \ - \ - SNAME *_map_ = malloc(sizeof(SNAME)); \ - \ - if (!_map_) \ - return NULL; \ - \ - _map_->buffer = malloc(sizeof(SNAME##_entry_ptr[2]) * real_capacity); \ - \ - if (!_map_->buffer) \ - { \ - free(_map_); \ - return NULL; \ - } \ - \ - memset(_map_->buffer, 0, sizeof(SNAME##_entry_ptr[2]) * real_capacity); \ - \ - _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(SNAME *_map_, void (*deallocator)(K, V)) \ - { \ - size_t index = 0; \ - 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) \ - { \ - SNAME##_entry *tmp = scan; \ - \ - scan = scan->next; \ - \ - if (deallocator) \ - deallocator(tmp->key, tmp->value); \ - \ - free(tmp); \ - } \ - } \ - } \ - \ - index++; \ - } \ - \ - memset(_map_->buffer, 0, sizeof(SNAME##_entry_ptr[2]) * _map_->capacity); \ - \ - _map_->count = 0; \ - } \ - \ - void PFX##_free(SNAME *_map_, void (*deallocator)(K, V)) \ - { \ - size_t index = 0; \ - 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) \ - { \ - 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(SNAME *_map_, K key, V value) \ - { \ - if ((double)_map_->capacity * _map_->load <= (double)_map_->count) \ - { \ - if (!PFX##_impl_grow(_map_)) \ - return false; \ - } \ - \ - size_t hash = _map_->hash(key); \ - size_t pos = hash % _map_->capacity; \ - \ - 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(SNAME *_map_, K key, V new_value, V *old_value) \ - { \ - 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(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); \ - \ - 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(SNAME *_map_, K key, V *out_value) \ - { \ - size_t hash = _map_->hash(key); \ - \ - SNAME##_entry **head = &(_map_->buffer[hash % _map_->capacity][0]); \ - SNAME##_entry **tail = &(_map_->buffer[hash % _map_->capacity][1]); \ - \ - if (*head == NULL) \ - return false; \ - \ - 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(SNAME *_map_, K key, V **out_values) \ - { \ - size_t hash = _map_->hash(key); \ - \ - SNAME##_entry **head = &(_map_->buffer[hash % _map_->capacity][0]); \ - 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(SNAME##_entry) * total); \ - \ - 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; \ - \ - 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(SNAME *_map_, K *key, V *value) \ - { \ - if (PFX##_empty(_map_)) \ - return false; \ - \ - 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(SNAME *_map_, K *key, V *value) \ - { \ - if (PFX##_empty(_map_)) \ - return false; \ - \ - 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(SNAME *_map_, K key) \ - { \ - SNAME##_entry *entry = PFX##_impl_get_entry(_map_, key); \ - \ - if (!entry) \ - return PFX##_impl_default_value(); \ - \ - return entry->value; \ - } \ - \ - V *PFX##_get_ref(SNAME *_map_, K key) \ - { \ - SNAME##_entry *entry = PFX##_impl_get_entry(_map_, key); \ - \ - if (!entry) \ - return NULL; \ - \ - return &(entry->value); \ - } \ - \ - bool PFX##_contains(SNAME *_map_, K key) \ - { \ - return PFX##_impl_get_entry(_map_, key) != NULL; \ - } \ - \ - bool PFX##_empty(SNAME *_map_) \ - { \ - return _map_->count == 0; \ - } \ - \ - size_t PFX##_count(SNAME *_map_) \ - { \ - return _map_->count; \ - } \ - \ - bool PFX##_key_count(SNAME *_map_, K key) \ - { \ - size_t hash = _map_->hash(key); \ - \ - 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(SNAME *_map_) \ - { \ - return _map_->capacity; \ - } \ - \ - SNAME *PFX##_copy_of(SNAME *_map_, K (*key_copy_func)(K), V (*value_copy_func)(V)) \ - { \ - SNAME *result = PFX##_new(_map_->capacity, _map_->load, _map_->cmp, _map_->hash); \ - \ - if (!result) \ - return NULL; \ - \ - 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(SNAME *_map1_, SNAME *_map2_, bool ignore_key_count) \ - { \ - if (ignore_key_count) \ - { \ - 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; \ - \ - 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; \ - } \ - \ - cmc_string PFX##_to_string(SNAME *_map_) \ - { \ - cmc_string str; \ - 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; \ - } \ - \ - SNAME##_iter *PFX##_iter_new(SNAME *target) \ - { \ - SNAME##_iter *iter = malloc(sizeof(SNAME##_iter)); \ - \ - if (!iter) \ - return NULL; \ - \ - PFX##_iter_init(iter, target); \ - \ - return iter; \ - } \ - \ - void PFX##_iter_free(SNAME##_iter *iter) \ - { \ - free(iter); \ - } \ - \ - void PFX##_iter_init(SNAME##_iter *iter, SNAME *target) \ - { \ - memset(iter, 0, sizeof(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(SNAME##_iter *iter) \ - { \ - return PFX##_empty(iter->target) || iter->start; \ - } \ - \ - bool PFX##_iter_end(SNAME##_iter *iter) \ - { \ - return PFX##_empty(iter->target) || iter->end; \ - } \ - \ - void PFX##_iter_to_start(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(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(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(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(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(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(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(SNAME##_iter *iter) \ - { \ - if (PFX##_empty(iter->target)) \ - return PFX##_impl_default_key(); \ - \ - return iter->curr_entry->key; \ - } \ - \ - V PFX##_iter_value(SNAME##_iter *iter) \ - { \ - if (PFX##_empty(iter->target)) \ - return PFX##_impl_default_value(); \ - \ - return iter->curr_entry->value; \ - } \ - \ - V *PFX##_iter_rvalue(SNAME##_iter *iter) \ - { \ - if (PFX##_empty(iter->target)) \ - return NULL; \ - \ - return &(iter->curr_entry->value); \ - } \ - \ - size_t PFX##_iter_index(SNAME##_iter *iter) \ - { \ - return iter->index; \ - } \ - \ - bool PFX##_impl_grow(SNAME *_map_) \ - { \ - size_t new_capacity = PFX##_impl_calculate_size(_map_->capacity * 1.5); \ - \ - SNAME *_new_map_ = PFX##_new(new_capacity, _map_->load, _map_->cmp, _map_->hash); \ - \ - if (!_new_map_) \ - return false; \ - \ - 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 (_map_->count != _new_map_->count) \ - { \ - PFX##_free(_new_map_, NULL); \ - return false; \ - } \ - \ - if (_map_->count != _new_map_->count) \ - { \ - PFX##_free(_new_map_, NULL); \ - \ - return false; \ - } \ - \ - 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; \ - } \ - \ - SNAME##_entry *PFX##_impl_new_entry(K key, V value) \ - { \ - SNAME##_entry *entry = malloc(sizeof(SNAME##_entry)); \ - \ - if (!entry) \ - return NULL; \ - \ - entry->key = key; \ - entry->value = value; \ - entry->next = NULL; \ - entry->prev = NULL; \ - \ - return entry; \ - } \ - \ - SNAME##_entry *PFX##_impl_get_entry(SNAME *_map_, K key) \ - { \ - size_t hash = _map_->hash(key); \ - \ - 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 SNAME##_iter PFX##_impl_it_start(SNAME *_map_) \ - { \ - SNAME##_iter iter; \ - \ - PFX##_iter_init(&iter, _map_); \ - \ - return iter; \ - } \ - \ - static SNAME##_iter PFX##_impl_it_end(SNAME *_map_) \ - { \ - SNAME##_iter iter; \ - \ - PFX##_iter_init(&iter, _map_); \ - PFX##_iter_to_end(&iter); \ - \ - return iter; \ +#define CMC_GENERATE_MULTIMAP_SOURCE(PFX, SNAME, K, V) \ + \ + /* Implementation Detail Functions */ \ + SNAME##_entry *PFX##_impl_new_entry(K key, V value); \ + SNAME##_entry *PFX##_impl_get_entry(SNAME *_map_, K key); \ + size_t PFX##_impl_calculate_size(size_t required); \ + static SNAME##_iter PFX##_impl_it_start(SNAME *_map_); \ + static SNAME##_iter PFX##_impl_it_end(SNAME *_map_); \ + \ + 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); \ + \ + SNAME *_map_ = malloc(sizeof(SNAME)); \ + \ + if (!_map_) \ + return NULL; \ + \ + _map_->buffer = malloc(sizeof(SNAME##_entry_ptr[2]) * real_capacity); \ + \ + if (!_map_->buffer) \ + { \ + free(_map_); \ + return NULL; \ + } \ + \ + memset(_map_->buffer, 0, sizeof(SNAME##_entry_ptr[2]) * real_capacity); \ + \ + _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(SNAME *_map_, void (*deallocator)(K, V)) \ + { \ + size_t index = 0; \ + 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) \ + { \ + SNAME##_entry *tmp = scan; \ + \ + scan = scan->next; \ + \ + if (deallocator) \ + deallocator(tmp->key, tmp->value); \ + \ + free(tmp); \ + } \ + } \ + } \ + \ + index++; \ + } \ + \ + memset(_map_->buffer, 0, sizeof(SNAME##_entry_ptr[2]) * _map_->capacity); \ + \ + _map_->count = 0; \ + } \ + \ + void PFX##_free(SNAME *_map_, void (*deallocator)(K, V)) \ + { \ + size_t index = 0; \ + 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) \ + { \ + 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(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; \ + \ + 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(SNAME *_map_, K key, V new_value, V *old_value) \ + { \ + 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(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); \ + \ + 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(SNAME *_map_, K key, V *out_value) \ + { \ + size_t hash = _map_->hash(key); \ + \ + SNAME##_entry **head = &(_map_->buffer[hash % _map_->capacity][0]); \ + SNAME##_entry **tail = &(_map_->buffer[hash % _map_->capacity][1]); \ + \ + if (*head == NULL) \ + return false; \ + \ + 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(SNAME *_map_, K key, V **out_values) \ + { \ + size_t hash = _map_->hash(key); \ + \ + SNAME##_entry **head = &(_map_->buffer[hash % _map_->capacity][0]); \ + 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(SNAME##_entry) * total); \ + \ + 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; \ + \ + 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(SNAME *_map_, K *key, V *value) \ + { \ + if (PFX##_empty(_map_)) \ + return false; \ + \ + 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(SNAME *_map_, K *key, V *value) \ + { \ + if (PFX##_empty(_map_)) \ + return false; \ + \ + 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(SNAME *_map_, K key) \ + { \ + SNAME##_entry *entry = PFX##_impl_get_entry(_map_, key); \ + \ + if (!entry) \ + return PFX##_impl_default_value(); \ + \ + return entry->value; \ + } \ + \ + V *PFX##_get_ref(SNAME *_map_, K key) \ + { \ + SNAME##_entry *entry = PFX##_impl_get_entry(_map_, key); \ + \ + if (!entry) \ + return NULL; \ + \ + return &(entry->value); \ + } \ + \ + bool PFX##_contains(SNAME *_map_, K key) \ + { \ + return PFX##_impl_get_entry(_map_, key) != NULL; \ + } \ + \ + bool PFX##_empty(SNAME *_map_) \ + { \ + return _map_->count == 0; \ + } \ + \ + bool PFX##_full(SNAME *_map_) \ + { \ + return (double)PFX##_capacity(_map_) * PFX##_load(_map_) <= (double)PFX##_count(_map_); \ + } \ + \ + size_t PFX##_count(SNAME *_map_) \ + { \ + return _map_->count; \ + } \ + \ + size_t PFX##_key_count(SNAME *_map_, K key) \ + { \ + size_t hash = _map_->hash(key); \ + \ + 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(SNAME *_map_) \ + { \ + return _map_->capacity; \ + } \ + \ + double PFX##_load(SNAME *_map_) \ + { \ + return _map_->load; \ + } \ + \ + bool PFX##_resize(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; \ + \ + SNAME *_new_map_ = PFX##_new(capacity, PFX##_load(_map_), _map_->cmp, _map_->hash); \ + \ + if (!_new_map_) \ + return false; \ + \ + 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; \ + } \ + \ + 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; \ + } \ + \ + SNAME *PFX##_copy_of(SNAME *_map_, K (*key_copy_func)(K), V (*value_copy_func)(V)) \ + { \ + SNAME *result = PFX##_new(_map_->capacity, _map_->load, _map_->cmp, _map_->hash); \ + \ + if (!result) \ + return NULL; \ + \ + 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(SNAME *_map1_, SNAME *_map2_, bool ignore_key_count) \ + { \ + if (ignore_key_count) \ + { \ + 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; \ + \ + 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; \ + } \ + \ + cmc_string PFX##_to_string(SNAME *_map_) \ + { \ + cmc_string str; \ + 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; \ + } \ + \ + SNAME##_iter *PFX##_iter_new(SNAME *target) \ + { \ + SNAME##_iter *iter = malloc(sizeof(SNAME##_iter)); \ + \ + if (!iter) \ + return NULL; \ + \ + PFX##_iter_init(iter, target); \ + \ + return iter; \ + } \ + \ + void PFX##_iter_free(SNAME##_iter *iter) \ + { \ + free(iter); \ + } \ + \ + void PFX##_iter_init(SNAME##_iter *iter, SNAME *target) \ + { \ + memset(iter, 0, sizeof(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(SNAME##_iter *iter) \ + { \ + return PFX##_empty(iter->target) || iter->start; \ + } \ + \ + bool PFX##_iter_end(SNAME##_iter *iter) \ + { \ + return PFX##_empty(iter->target) || iter->end; \ + } \ + \ + void PFX##_iter_to_start(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(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(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(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(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(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(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(SNAME##_iter *iter) \ + { \ + if (PFX##_empty(iter->target)) \ + return PFX##_impl_default_key(); \ + \ + return iter->curr_entry->key; \ + } \ + \ + V PFX##_iter_value(SNAME##_iter *iter) \ + { \ + if (PFX##_empty(iter->target)) \ + return PFX##_impl_default_value(); \ + \ + return iter->curr_entry->value; \ + } \ + \ + V *PFX##_iter_rvalue(SNAME##_iter *iter) \ + { \ + if (PFX##_empty(iter->target)) \ + return NULL; \ + \ + return &(iter->curr_entry->value); \ + } \ + \ + size_t PFX##_iter_index(SNAME##_iter *iter) \ + { \ + return iter->index; \ + } \ + \ + SNAME##_entry *PFX##_impl_new_entry(K key, V value) \ + { \ + SNAME##_entry *entry = malloc(sizeof(SNAME##_entry)); \ + \ + if (!entry) \ + return NULL; \ + \ + entry->key = key; \ + entry->value = value; \ + entry->next = NULL; \ + entry->prev = NULL; \ + \ + return entry; \ + } \ + \ + SNAME##_entry *PFX##_impl_get_entry(SNAME *_map_, K key) \ + { \ + size_t hash = _map_->hash(key); \ + \ + 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 SNAME##_iter PFX##_impl_it_start(SNAME *_map_) \ + { \ + SNAME##_iter iter; \ + \ + PFX##_iter_init(&iter, _map_); \ + \ + return iter; \ + } \ + \ + static SNAME##_iter PFX##_impl_it_end(SNAME *_map_) \ + { \ + SNAME##_iter iter; \ + \ + PFX##_iter_init(&iter, _map_); \ + PFX##_iter_to_end(&iter); \ + \ + return iter; \ } #endif /* CMC_MULTIMAP_H */ diff --git a/src/ext/multiset.h b/src/ext/multiset.h index 9ae2c8c..55154c8 100644 --- a/src/ext/multiset.h +++ b/src/ext/multiset.h @@ -185,10 +185,13 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, /* Collection State */ \ bool PFX##_contains(SNAME *_set_, V element); \ bool PFX##_empty(SNAME *_set_); \ + bool PFX##_full(SNAME *_set_); \ size_t PFX##_count(SNAME *_set_); \ size_t PFX##_cardinality(SNAME *_set_); \ size_t PFX##_capacity(SNAME *_set_); \ + double PFX##_load(SNAME *_set_); \ /* Collection Utility */ \ + bool PFX##_resize(SNAME *_set_, size_t capacity); \ SNAME *PFX##_copy_of(SNAME *_set_, V (*copy_func)(V)); \ bool PFX##_equals(SNAME *_set1_, SNAME *_set2_, bool ignore_multiplicity); \ cmc_string PFX##_to_string(SNAME *_set_); \ @@ -242,7 +245,6 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, \ /* Implementation Detail Functions */ \ static SNAME##_entry *PFX##_impl_insert_and_return(SNAME *_set_, V element, bool *new_node); \ - static bool PFX##_impl_grow(SNAME *_set_); \ static SNAME##_entry *PFX##_impl_get_entry(SNAME *_set_, V element); \ static size_t PFX##_impl_calculate_size(size_t required); \ static SNAME##_iter PFX##_impl_it_start(SNAME *_set_); \ @@ -493,6 +495,11 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, return _set_->count == 0; \ } \ \ + bool PFX##_full(SNAME *_set_) \ + { \ + return (double)PFX##_capacity(_set_) * PFX##_load(_set_) <= (double)PFX##_count(_set_); \ + } \ + \ size_t PFX##_count(SNAME *_set_) \ { \ return _set_->count; \ @@ -508,6 +515,61 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, return _set_->capacity; \ } \ \ + double PFX##_load(SNAME *_set_) \ + { \ + return _set_->load; \ + } \ + \ + bool PFX##_resize(SNAME *_set_, size_t capacity) \ + { \ + if (PFX##_capacity(_set_) == capacity) \ + return true; \ + \ + if (PFX##_capacity(_set_) > capacity / PFX##_load(_set_)) \ + return true; \ + \ + /* Prevent integer overflow */ \ + if (capacity >= UINTMAX_MAX * PFX##_load(_set_)) \ + 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(_set_) / PFX##_load(_set_)) \ + return false; \ + \ + SNAME *_new_set_ = PFX##_new(capacity, PFX##_load(_set_), _set_->cmp, _set_->hash); \ + \ + if (!_new_set_) \ + return false; \ + \ + SNAME##_iter iter; \ + \ + for (PFX##_iter_init(&iter, _set_); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \ + { \ + PFX##_insert_many(_new_set_, PFX##_iter_value(&iter), PFX##_iter_multiplicity(&iter)); \ + } \ + \ + if (PFX##_count(_set_) != PFX##_count(_new_set_)) \ + { \ + PFX##_free(_new_set_, NULL); \ + return false; \ + } \ + \ + SNAME##_entry *tmp_b = _set_->buffer; \ + _set_->buffer = _new_set_->buffer; \ + _new_set_->buffer = tmp_b; \ + \ + size_t tmp_c = _set_->capacity; \ + _set_->capacity = _new_set_->capacity; \ + _new_set_->capacity = tmp_c; \ + \ + PFX##_free(_new_set_, NULL); \ + \ + return true; \ + } \ + \ SNAME *PFX##_copy_of(SNAME *_set_, V (*copy_func)(V)) \ { \ SNAME *result = PFX##_new(_set_->capacity, _set_->load, _set_->cmp, _set_->hash); \ @@ -1063,9 +1125,9 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, \ *new_node = true; \ \ - if ((double)_set_->capacity * _set_->load <= (double)_set_->count) \ + if (PFX##_full(_set_)) \ { \ - if (!PFX##_impl_grow(_set_)) \ + if (!PFX##_resize(_set_, PFX##_capacity(_set_) + 1)) \ return NULL; \ } \ \ @@ -1123,40 +1185,6 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, return target; \ } \ \ - static bool PFX##_impl_grow(SNAME *_set_) \ - { \ - size_t new_size = PFX##_impl_calculate_size(_set_->capacity + _set_->capacity / 2); \ - \ - SNAME *_new_set_ = PFX##_new(new_size, _set_->load, _set_->cmp, _set_->hash); \ - \ - if (!_new_set_) \ - return false; \ - \ - SNAME##_iter iter; \ - \ - for (PFX##_iter_init(&iter, _set_); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \ - { \ - PFX##_insert_many(_new_set_, PFX##_iter_value(&iter), PFX##_iter_multiplicity(&iter)); \ - } \ - \ - if (_set_->count != _new_set_->count) \ - { \ - PFX##_free(_new_set_, NULL); \ - \ - return false; \ - } \ - \ - SNAME##_entry *tmp = _set_->buffer; \ - _set_->buffer = _new_set_->buffer; \ - _new_set_->buffer = tmp; \ - \ - _set_->capacity = _new_set_->capacity; \ - \ - PFX##_free(_new_set_, NULL); \ - \ - return true; \ - } \ - \ static SNAME##_entry *PFX##_impl_get_entry(SNAME *_set_, V element) \ { \ size_t hash = _set_->hash(element); \ diff --git a/src/ext/sortedlist.h b/src/ext/sortedlist.h index 8928972..9c5289e 100644 --- a/src/ext/sortedlist.h +++ b/src/ext/sortedlist.h @@ -109,6 +109,7 @@ static const char *cmc_string_fmt_sortedlist = "%s at %p { buffer:%p, capacity:% size_t PFX##_count(SNAME *_list_); \ size_t PFX##_capacity(SNAME *_list_); \ /* Collection Utility */ \ + bool PFX##_resize(SNAME *_list_, size_t capacity); \ void PFX##_sort(SNAME *_list_); \ SNAME *PFX##_copy_of(SNAME *_list_, V (*copy_func)(V)); \ bool PFX##_equals(SNAME *_list1_, SNAME *_list2_); \ @@ -149,7 +150,6 @@ static const char *cmc_string_fmt_sortedlist = "%s at %p { buffer:%p, capacity:% #define CMC_GENERATE_SORTEDLIST_SOURCE(PFX, SNAME, V) \ \ /* Implementation Detail Functions */ \ - static bool PFX##_impl_grow(SNAME *_list_, size_t required); \ static size_t PFX##_impl_binary_search_first(SNAME *_list_, V value); \ static size_t PFX##_impl_binary_search_last(SNAME *_list_, V value); \ void PFX##_impl_sort_quicksort(V *array, int (*cmp)(V, V), size_t low, size_t high); \ @@ -215,7 +215,7 @@ static const char *cmc_string_fmt_sortedlist = "%s at %p { buffer:%p, capacity:% { \ if (PFX##_full(_list_)) \ { \ - if (!PFX##_impl_grow(_list_, _list_->count + 1)) \ + if (!PFX##_resize(_list_, PFX##_capacity(_list_) * 2)) \ return false; \ } \ \ @@ -315,6 +315,25 @@ static const char *cmc_string_fmt_sortedlist = "%s at %p { buffer:%p, capacity:% return _list_->capacity; \ } \ \ + bool PFX##_resize(SNAME *_list_, size_t capacity) \ + { \ + if (PFX##_capacity(_list_) == capacity) \ + return true; \ + \ + if (capacity < PFX##_count(_list_)) \ + return false; \ + \ + V *new_buffer = realloc(_list_->buffer, sizeof(V) * capacity); \ + \ + if (!new_buffer) \ + return false; \ + \ + _list_->buffer = new_buffer; \ + _list_->capacity = capacity; \ + \ + return true; \ + } \ + \ void PFX##_sort(SNAME *_list_) \ { \ if (!_list_->is_sorted && _list_->count > 1) \ @@ -536,24 +555,6 @@ static const char *cmc_string_fmt_sortedlist = "%s at %p { buffer:%p, capacity:% return iter->cursor; \ } \ \ - static bool PFX##_impl_grow(SNAME *_list_, size_t required) \ - { \ - size_t new_capacity = _list_->capacity * 2; \ - \ - if (new_capacity < required) \ - new_capacity = required; \ - \ - V *new_buffer = realloc(_list_->buffer, sizeof(V) * new_capacity); \ - \ - if (!new_buffer) \ - return false; \ - \ - _list_->buffer = new_buffer; \ - _list_->capacity = new_capacity; \ - \ - return true; \ - } \ - \ static size_t PFX##_impl_binary_search_first(SNAME *_list_, V value) \ { \ if (PFX##_empty(_list_)) \ diff --git a/tests/main/unt/multimap.c b/tests/main/unt/multimap.c index 1581953..45661dd 100644 --- a/tests/main/unt/multimap.c +++ b/tests/main/unt/multimap.c @@ -53,10 +53,10 @@ CMC_CREATE_UNIT(multimap_test, true, { cmc_assert_not_equals(ptr, NULL, map); - for (size_t i = 0; i < 200; i++) + for (size_t i = 0; i < 100; i++) cmc_assert(mm_insert(map, i % 20, i % 20)); - cmc_assert_equals(size_t, 200, mm_count(map)); + cmc_assert_equals(size_t, 100, mm_count(map)); mm_free(map, NULL); }); @@ -119,4 +119,20 @@ CMC_CREATE_UNIT(multimap_test, true, { mm_free(map, NULL); }); + + CMC_CREATE_TEST(key_count, { + multimap *map = mm_new(50, 0.8, cmp, hash); + + cmc_assert_not_equals(ptr, NULL, map); + + for (size_t i = 0; i < 1000; i++) + cmc_assert(mm_insert(map, i % 20, i % 20)); + + cmc_assert_equals(size_t, 1000, mm_count(map)); + + for (size_t i = 0; i < 20; i++) + cmc_assert_equals(size_t, 50, mm_key_count(map, i)); + + mm_free(map, NULL); + }); }); diff --git a/tests/main/unt/multiset.c b/tests/main/unt/multiset.c index 262ce69..e0cdd52 100644 --- a/tests/main/unt/multiset.c +++ b/tests/main/unt/multiset.c @@ -69,19 +69,84 @@ CMC_CREATE_UNIT(multiset_test, true, { ms_free(set, NULL); }); - CMC_CREATE_TEST(multiplicity, { + CMC_CREATE_TEST(remove[count cardinality multiplicity], { multiset *set = ms_new(100, 0.6, cmp, hash); cmc_assert_not_equals(ptr, NULL, set); - for (size_t i = 0; i < 100; i++) + cmc_assert(ms_insert(set, 1)); + cmc_assert(ms_insert(set, 2)); + cmc_assert(ms_insert(set, 2)); + cmc_assert(ms_insert(set, 3)); + cmc_assert(ms_insert(set, 3)); + cmc_assert(ms_insert(set, 3)); + + cmc_assert_equals(size_t, 3, ms_count(set)); + cmc_assert_equals(size_t, 6, ms_cardinality(set)); + + for (size_t i = 0; i <= 3; i++) + cmc_assert_equals(size_t, i, ms_multiplicity_of(set, i)); + + cmc_assert(ms_remove(set, 1)); + cmc_assert(ms_remove(set, 2)); + cmc_assert(ms_remove(set, 3)); + + cmc_assert_equals(size_t, 2, ms_count(set)); + cmc_assert_equals(size_t, 3, ms_cardinality(set)); + + cmc_assert_equals(size_t, 0, ms_multiplicity_of(set, 0)); + cmc_assert_equals(size_t, 0, ms_multiplicity_of(set, 1)); + cmc_assert_equals(size_t, 1, ms_multiplicity_of(set, 2)); + cmc_assert_equals(size_t, 2, ms_multiplicity_of(set, 3)); + + ms_free(set, NULL); + }); + + CMC_CREATE_TEST(remove_all[count cardinality multiplicity], { + multiset *set = ms_new(100, 0.6, cmp, hash); + + cmc_assert_not_equals(ptr, NULL, set); + + cmc_assert(ms_insert(set, 1)); + cmc_assert(ms_insert(set, 2)); + cmc_assert(ms_insert(set, 2)); + cmc_assert(ms_insert(set, 3)); + cmc_assert(ms_insert(set, 3)); + cmc_assert(ms_insert(set, 3)); + + cmc_assert_equals(size_t, 3, ms_count(set)); + cmc_assert_equals(size_t, 6, ms_cardinality(set)); + + for (size_t i = 0; i <= 3; i++) + cmc_assert_equals(size_t, i, ms_multiplicity_of(set, i)); + + cmc_assert(ms_remove_all(set, 1)); + cmc_assert(ms_remove_all(set, 3)); + + cmc_assert_equals(size_t, 1, ms_count(set)); + cmc_assert_equals(size_t, 2, ms_cardinality(set)); + + cmc_assert_equals(size_t, 0, ms_multiplicity_of(set, 0)); + cmc_assert_equals(size_t, 0, ms_multiplicity_of(set, 1)); + cmc_assert_equals(size_t, 2, ms_multiplicity_of(set, 2)); + cmc_assert_equals(size_t, 0, ms_multiplicity_of(set, 3)); + + ms_free(set, NULL); + }); + + CMC_CREATE_TEST(multiplicity, { + multiset *set = ms_new(50, 0.6, cmp, hash); + + cmc_assert_not_equals(ptr, NULL, set); + + for (size_t i = 0; i < 1000; i++) cmc_assert(ms_insert(set, i % 20)); cmc_assert_equals(size_t, 20, ms_count(set)); - cmc_assert_equals(size_t, 100, ms_cardinality(set)); + cmc_assert_equals(size_t, 1000, ms_cardinality(set)); for (size_t i = 0; i < 20; i++) - cmc_assert_equals(size_t, 5, ms_multiplicity_of(set, i)); + cmc_assert_equals(size_t, 50, ms_multiplicity_of(set, i)); ms_free(set, NULL); }); diff --git a/tests/main/unt/sortedlist.c b/tests/main/unt/sortedlist.c index 7c0d691..d9a9897 100644 --- a/tests/main/unt/sortedlist.c +++ b/tests/main/unt/sortedlist.c @@ -51,7 +51,7 @@ CMC_CREATE_UNIT(sortedlist_test, true, { }); CMC_CREATE_TEST(buffer_growth[capacity = 1], { - sortedlist *sl = sl_new(100, cmp); + sortedlist *sl = sl_new(1, cmp); cmc_assert_not_equals(ptr, NULL, sl);