From fdfb81d08ce9412a20b6b17116921c15aa218fbc Mon Sep 17 00:00:00 2001 From: Leonardo Date: Wed, 6 May 2020 14:55:44 -0300 Subject: [PATCH] Updating hashmultimap iterator API --- src/cmc/hashmultimap.h | 174 +++++++------ tests/main/main.c | 1 + tests/main/src/hashmultimap.c | 146 ++++++----- tests/main/unt/hashmultimap.c | 472 +++++++++++++++++++++++++++++++++- 4 files changed, 623 insertions(+), 170 deletions(-) diff --git a/src/cmc/hashmultimap.h b/src/cmc/hashmultimap.h index e5adf9a..be8c95e 100644 --- a/src/cmc/hashmultimap.h +++ b/src/cmc/hashmultimap.h @@ -114,12 +114,6 @@ static const char *cmc_string_fmt_hashmultimap = "struct %s<%s, %s> " \ /* Custom callback functions */ \ struct cmc_callbacks *callbacks; \ - \ - /* Returns an iterator to the start of the hashmultimap */ \ - struct SNAME##_iter (*it_start)(struct SNAME *); \ - \ - /* Returns an iterator to the end of the hashmultimap */ \ - struct SNAME##_iter (*it_end)(struct SNAME *); \ }; \ \ /* HashMultimap Entry */ \ @@ -252,17 +246,15 @@ static const char *cmc_string_fmt_hashmultimap = "struct %s<%s, %s> " bool PFX##_print(struct SNAME *_map_, FILE *fptr); \ \ /* Iterator Functions */ \ - /* Iterator Allocation and Deallocation */ \ - struct SNAME##_iter *PFX##_iter_new(struct SNAME *target); \ - void PFX##_iter_free(struct SNAME##_iter *iter); \ /* Iterator Initialization */ \ - void PFX##_iter_init(struct SNAME##_iter *iter, struct SNAME *target); \ + struct SNAME##_iter PFX##_iter_start(struct SNAME *target); \ + struct SNAME##_iter PFX##_iter_end(struct SNAME *target); \ /* Iterator State */ \ - bool PFX##_iter_start(struct SNAME##_iter *iter); \ - bool PFX##_iter_end(struct SNAME##_iter *iter); \ + bool PFX##_iter_at_start(struct SNAME##_iter *iter); \ + bool PFX##_iter_at_end(struct SNAME##_iter *iter); \ /* Iterator Movement */ \ - void PFX##_iter_to_start(struct SNAME##_iter *iter); \ - void PFX##_iter_to_end(struct SNAME##_iter *iter); \ + bool PFX##_iter_to_start(struct SNAME##_iter *iter); \ + bool PFX##_iter_to_end(struct SNAME##_iter *iter); \ bool PFX##_iter_next(struct SNAME##_iter *iter); \ bool PFX##_iter_prev(struct SNAME##_iter *iter); \ bool PFX##_iter_advance(struct SNAME##_iter *iter, size_t steps); \ @@ -285,8 +277,6 @@ static const char *cmc_string_fmt_hashmultimap = "struct %s<%s, %s> " struct SNAME##_entry *PFX##_impl_get_entry(struct SNAME *_map_, K key); \ size_t PFX##_impl_key_count(struct SNAME *_map_, K key); \ size_t PFX##_impl_calculate_size(size_t required); \ - static struct SNAME##_iter PFX##_impl_it_start(struct SNAME *_map_); \ - static struct SNAME##_iter PFX##_impl_it_end(struct SNAME *_map_); \ \ struct SNAME *PFX##_new(size_t capacity, double load, \ struct SNAME##_fkey *f_key, \ @@ -328,8 +318,6 @@ static const char *cmc_string_fmt_hashmultimap = "struct %s<%s, %s> " _map_->f_val = f_val; \ _map_->alloc = alloc; \ _map_->callbacks = NULL; \ - _map_->it_end = PFX##_impl_it_end; \ - _map_->it_start = PFX##_impl_it_start; \ \ return _map_; \ } \ @@ -376,8 +364,6 @@ static const char *cmc_string_fmt_hashmultimap = "struct %s<%s, %s> " _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_; \ } \ @@ -785,11 +771,10 @@ static const char *cmc_string_fmt_hashmultimap = "struct %s<%s, %s> " K max_key; \ V max_val; \ \ - struct SNAME##_iter iter; \ + struct SNAME##_iter iter = PFX##_iter_start(_map_); \ \ /* TODO Turn this into a normal loop */ \ - for (PFX##_iter_init(&iter, _map_); !PFX##_iter_end(&iter); \ - PFX##_iter_next(&iter)) \ + for (; !PFX##_iter_at_end(&iter); PFX##_iter_next(&iter)) \ { \ K result_key = PFX##_iter_key(&iter); \ V result_value = PFX##_iter_value(&iter); \ @@ -831,11 +816,10 @@ static const char *cmc_string_fmt_hashmultimap = "struct %s<%s, %s> " K min_key; \ V min_val; \ \ - struct SNAME##_iter iter; \ + struct SNAME##_iter iter = PFX##_iter_start(_map_); \ \ /* TODO Turn this into a normal loop */ \ - for (PFX##_iter_init(&iter, _map_); !PFX##_iter_end(&iter); \ - PFX##_iter_next(&iter)) \ + for (; !PFX##_iter_at_end(&iter); PFX##_iter_next(&iter)) \ { \ K result_key = PFX##_iter_key(&iter); \ V result_value = PFX##_iter_value(&iter); \ @@ -999,11 +983,10 @@ static const char *cmc_string_fmt_hashmultimap = "struct %s<%s, %s> " return false; \ } \ \ - struct SNAME##_iter iter; \ + struct SNAME##_iter iter = PFX##_iter_start(_map_); \ \ /* TODO Turn this into a normal loop */ \ - for (PFX##_iter_init(&iter, _map_); !PFX##_iter_end(&iter); \ - PFX##_iter_next(&iter)) \ + for (; !PFX##_iter_at_end(&iter); PFX##_iter_next(&iter)) \ { \ K key = PFX##_iter_key(&iter); \ V value = PFX##_iter_value(&iter); \ @@ -1055,14 +1038,12 @@ static const char *cmc_string_fmt_hashmultimap = "struct %s<%s, %s> " return NULL; \ } \ \ - struct SNAME##_iter iter; \ - PFX##_iter_init(&iter, _map_); \ + struct SNAME##_iter iter = PFX##_iter_start(_map_); \ \ if (!PFX##_empty(_map_)) \ { \ /* TODO Turn this into a normal loop */ \ - for (PFX##_iter_to_start(&iter); !PFX##_iter_end(&iter); \ - PFX##_iter_next(&iter)) \ + for (; !PFX##_iter_at_end(&iter); PFX##_iter_next(&iter)) \ { \ K key = PFX##_iter_key(&iter); \ V value = PFX##_iter_value(&iter); \ @@ -1091,12 +1072,10 @@ static const char *cmc_string_fmt_hashmultimap = "struct %s<%s, %s> " if (_map1_->count != _map2_->count) \ return false; \ \ - struct SNAME##_iter iter; \ - PFX##_iter_init(&iter, _map1_); \ + struct SNAME##_iter iter = PFX##_iter_start(_map1_); \ \ /* TODO Turn this into a normal loop */ \ - for (PFX##_iter_to_start(&iter); !PFX##_iter_end(&iter); \ - PFX##_iter_next(&iter)) \ + for (; !PFX##_iter_at_end(&iter); PFX##_iter_next(&iter)) \ { \ K key = PFX##_iter_key(&iter); \ \ @@ -1140,31 +1119,18 @@ static const char *cmc_string_fmt_hashmultimap = "struct %s<%s, %s> " return true; \ } \ \ - struct SNAME##_iter *PFX##_iter_new(struct SNAME *target) \ + struct SNAME##_iter PFX##_iter_start(struct SNAME *target) \ { \ - struct SNAME##_iter *iter = \ - target->alloc->malloc(sizeof(struct SNAME##_iter)); \ + struct SNAME##_iter 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); \ + iter.target = target; \ + iter.curr_entry = NULL; \ + iter.cursor = 0; \ + iter.index = 0; \ + iter.first = 0; \ + iter.last = 0; \ + iter.start = true; \ + iter.end = PFX##_empty(target); \ \ if (!PFX##_empty(target)) \ { \ @@ -1172,36 +1138,79 @@ static const char *cmc_string_fmt_hashmultimap = "struct %s<%s, %s> " { \ if (target->buffer[i][0] != NULL) \ { \ - iter->curr_entry = target->buffer[i][0]; \ - iter->first = i; \ + iter.curr_entry = target->buffer[i][0]; \ + iter.first = i; \ break; \ } \ } \ \ - iter->cursor = iter->first; \ + iter.cursor = iter.first; \ \ for (size_t i = target->capacity; i > 0; i--) \ { \ - if (target->buffer[i - 1][0] != NULL) \ + if (target->buffer[i - 1][1] != NULL) \ { \ - iter->last = i - 1; \ + iter.last = i - 1; \ break; \ } \ } \ } \ + \ + return iter; \ } \ \ - bool PFX##_iter_start(struct SNAME##_iter *iter) \ + struct SNAME##_iter PFX##_iter_end(struct SNAME *target) \ + { \ + struct SNAME##_iter iter; \ + \ + iter.target = target; \ + iter.curr_entry = NULL; \ + iter.cursor = 0; \ + iter.index = 0; \ + iter.first = 0; \ + iter.last = 0; \ + iter.start = PFX##_empty(target); \ + iter.end = true; \ + \ + if (!PFX##_empty(target)) \ + { \ + for (size_t i = 0; i < target->capacity; i++) \ + { \ + if (target->buffer[i][0] != NULL) \ + { \ + iter.first = i; \ + break; \ + } \ + } \ + \ + for (size_t i = target->capacity; i > 0; i--) \ + { \ + if (target->buffer[i - 1][1] != NULL) \ + { \ + iter.curr_entry = target->buffer[i - 1][1]; \ + iter.last = i - 1; \ + break; \ + } \ + } \ + \ + iter.cursor = iter.last; \ + iter.index = target->count - 1; \ + } \ + \ + return iter; \ + } \ + \ + bool PFX##_iter_at_start(struct SNAME##_iter *iter) \ { \ return PFX##_empty(iter->target) || iter->start; \ } \ \ - bool PFX##_iter_end(struct SNAME##_iter *iter) \ + bool PFX##_iter_at_end(struct SNAME##_iter *iter) \ { \ return PFX##_empty(iter->target) || iter->end; \ } \ \ - void PFX##_iter_to_start(struct SNAME##_iter *iter) \ + bool PFX##_iter_to_start(struct SNAME##_iter *iter) \ { \ if (!PFX##_empty(iter->target)) \ { \ @@ -1210,10 +1219,14 @@ static const char *cmc_string_fmt_hashmultimap = "struct %s<%s, %s> " iter->start = true; \ iter->end = PFX##_empty(iter->target); \ iter->curr_entry = iter->target->buffer[iter->first][0]; \ + \ + return true; \ } \ + \ + return false; \ } \ \ - void PFX##_iter_to_end(struct SNAME##_iter *iter) \ + bool PFX##_iter_to_end(struct SNAME##_iter *iter) \ { \ if (!PFX##_empty(iter->target)) \ { \ @@ -1222,7 +1235,11 @@ static const char *cmc_string_fmt_hashmultimap = "struct %s<%s, %s> " iter->start = PFX##_empty(iter->target); \ iter->end = true; \ iter->curr_entry = iter->target->buffer[iter->last][1]; \ + \ + return true; \ } \ + \ + return false; \ } \ \ bool PFX##_iter_next(struct SNAME##_iter *iter) \ @@ -1448,25 +1465,6 @@ static const char *cmc_string_fmt_hashmultimap = "struct %s<%s, %s> " 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_HASHMULTIMAP_H */ diff --git a/tests/main/main.c b/tests/main/main.c index 85b5410..bdfd234 100644 --- a/tests/main/main.c +++ b/tests/main/main.c @@ -55,6 +55,7 @@ int main(void) cmc_run(HashMap, units, tests); cmc_run(HashMapIter, units, tests); cmc_run(HashMultiMap, units, tests); + cmc_run(HashMultiMapIter, units, tests); cmc_run(HashMultiSet, units, tests); cmc_run(HashSet, units, tests); cmc_run(Heap, units, tests); diff --git a/tests/main/src/hashmultimap.c b/tests/main/src/hashmultimap.c index 2257cab..0163322 100644 --- a/tests/main/src/hashmultimap.c +++ b/tests/main/src/hashmultimap.c @@ -11,8 +11,6 @@ struct hashmultimap struct hashmultimap_fval *f_val; struct cmc_alloc_node *alloc; struct cmc_callbacks *callbacks; - struct hashmultimap_iter (*it_start)(struct hashmultimap *); - struct hashmultimap_iter (*it_end)(struct hashmultimap *); }; struct hashmultimap_entry { @@ -87,13 +85,12 @@ struct hashmultimap *hmm_copy_of(struct hashmultimap *_map_); _Bool hmm_equals(struct hashmultimap *_map1_, struct hashmultimap *_map2_); struct cmc_string hmm_to_string(struct hashmultimap *_map_); _Bool hmm_print(struct hashmultimap *_map_, FILE *fptr); -struct hashmultimap_iter *hmm_iter_new(struct hashmultimap *target); -void hmm_iter_free(struct hashmultimap_iter *iter); -void hmm_iter_init(struct hashmultimap_iter *iter, struct hashmultimap *target); -_Bool hmm_iter_start(struct hashmultimap_iter *iter); -_Bool hmm_iter_end(struct hashmultimap_iter *iter); -void hmm_iter_to_start(struct hashmultimap_iter *iter); -void hmm_iter_to_end(struct hashmultimap_iter *iter); +struct hashmultimap_iter hmm_iter_start(struct hashmultimap *target); +struct hashmultimap_iter hmm_iter_end(struct hashmultimap *target); +_Bool hmm_iter_at_start(struct hashmultimap_iter *iter); +_Bool hmm_iter_at_end(struct hashmultimap_iter *iter); +_Bool hmm_iter_to_start(struct hashmultimap_iter *iter); +_Bool hmm_iter_to_end(struct hashmultimap_iter *iter); _Bool hmm_iter_next(struct hashmultimap_iter *iter); _Bool hmm_iter_prev(struct hashmultimap_iter *iter); _Bool hmm_iter_advance(struct hashmultimap_iter *iter, size_t steps); @@ -109,8 +106,6 @@ struct hashmultimap_entry *hmm_impl_get_entry(struct hashmultimap *_map_, size_t key); size_t hmm_impl_key_count(struct hashmultimap *_map_, size_t key); size_t hmm_impl_calculate_size(size_t required); -static struct hashmultimap_iter hmm_impl_it_start(struct hashmultimap *_map_); -static struct hashmultimap_iter hmm_impl_it_end(struct hashmultimap *_map_); struct hashmultimap *hmm_new(size_t capacity, double load, struct hashmultimap_fkey *f_key, struct hashmultimap_fval *f_val) @@ -141,8 +136,6 @@ struct hashmultimap *hmm_new(size_t capacity, double load, _map_->f_val = f_val; _map_->alloc = alloc; _map_->callbacks = ((void *)0); - _map_->it_end = hmm_impl_it_end; - _map_->it_start = hmm_impl_it_start; return _map_; } struct hashmultimap *hmm_new_custom(size_t capacity, double load, @@ -178,8 +171,6 @@ struct hashmultimap *hmm_new_custom(size_t capacity, double load, _map_->f_val = f_val; _map_->alloc = alloc; _map_->callbacks = callbacks; - _map_->it_start = hmm_impl_it_start; - _map_->it_end = hmm_impl_it_end; return _map_; } void hmm_clear(struct hashmultimap *_map_) @@ -497,9 +488,8 @@ _Bool hmm_max(struct hashmultimap *_map_, size_t *key, size_t *value) } size_t max_key; size_t max_val; - struct hashmultimap_iter iter; - for (hmm_iter_init(&iter, _map_); !hmm_iter_end(&iter); - hmm_iter_next(&iter)) + struct hashmultimap_iter iter = hmm_iter_start(_map_); + for (; !hmm_iter_at_end(&iter); hmm_iter_next(&iter)) { size_t result_key = hmm_iter_key(&iter); size_t result_value = hmm_iter_value(&iter); @@ -533,9 +523,8 @@ _Bool hmm_min(struct hashmultimap *_map_, size_t *key, size_t *value) } size_t min_key; size_t min_val; - struct hashmultimap_iter iter; - for (hmm_iter_init(&iter, _map_); !hmm_iter_end(&iter); - hmm_iter_next(&iter)) + struct hashmultimap_iter iter = hmm_iter_start(_map_); + for (; !hmm_iter_at_end(&iter); hmm_iter_next(&iter)) { size_t result_key = hmm_iter_key(&iter); size_t result_value = hmm_iter_value(&iter); @@ -658,9 +647,8 @@ _Bool hmm_resize(struct hashmultimap *_map_, size_t capacity) _map_->flag = cmc_flags.ALLOC; return 0; } - struct hashmultimap_iter iter; - for (hmm_iter_init(&iter, _map_); !hmm_iter_end(&iter); - hmm_iter_next(&iter)) + struct hashmultimap_iter iter = hmm_iter_start(_map_); + for (; !hmm_iter_at_end(&iter); hmm_iter_next(&iter)) { size_t key = hmm_iter_key(&iter); size_t value = hmm_iter_value(&iter); @@ -696,12 +684,10 @@ struct hashmultimap *hmm_copy_of(struct hashmultimap *_map_) _map_->flag = cmc_flags.ERROR; return ((void *)0); } - struct hashmultimap_iter iter; - hmm_iter_init(&iter, _map_); + struct hashmultimap_iter iter = hmm_iter_start(_map_); if (!hmm_empty(_map_)) { - for (hmm_iter_to_start(&iter); !hmm_iter_end(&iter); - hmm_iter_next(&iter)) + for (; !hmm_iter_at_end(&iter); hmm_iter_next(&iter)) { size_t key = hmm_iter_key(&iter); size_t value = hmm_iter_value(&iter); @@ -722,9 +708,8 @@ _Bool hmm_equals(struct hashmultimap *_map1_, struct hashmultimap *_map2_) _map2_->flag = cmc_flags.OK; if (_map1_->count != _map2_->count) return 0; - struct hashmultimap_iter iter; - hmm_iter_init(&iter, _map1_); - for (hmm_iter_to_start(&iter); !hmm_iter_end(&iter); hmm_iter_next(&iter)) + struct hashmultimap_iter iter = hmm_iter_start(_map1_); + for (; !hmm_iter_at_end(&iter); hmm_iter_next(&iter)) { size_t key = hmm_iter_key(&iter); if (hmm_impl_key_count(_map1_, key) != hmm_impl_key_count(_map2_, key)) @@ -757,56 +742,84 @@ _Bool hmm_print(struct hashmultimap *_map_, FILE *fptr) } return 1; } -struct hashmultimap_iter *hmm_iter_new(struct hashmultimap *target) +struct hashmultimap_iter hmm_iter_start(struct hashmultimap *target) { - struct hashmultimap_iter *iter = - target->alloc->malloc(sizeof(struct hashmultimap_iter)); - if (!iter) - return ((void *)0); - hmm_iter_init(iter, target); - return iter; -} -void hmm_iter_free(struct hashmultimap_iter *iter) -{ - iter->target->alloc->free(iter); -} -void hmm_iter_init(struct hashmultimap_iter *iter, struct hashmultimap *target) -{ - memset(iter, 0, sizeof(struct hashmultimap_iter)); - iter->target = target; - iter->start = 1; - iter->end = hmm_empty(target); + struct hashmultimap_iter iter; + iter.target = target; + iter.curr_entry = ((void *)0); + iter.cursor = 0; + iter.index = 0; + iter.first = 0; + iter.last = 0; + iter.start = 1; + iter.end = hmm_empty(target); if (!hmm_empty(target)) { for (size_t i = 0; i < target->capacity; i++) { if (target->buffer[i][0] != ((void *)0)) { - iter->curr_entry = target->buffer[i][0]; - iter->first = i; + iter.curr_entry = target->buffer[i][0]; + iter.first = i; break; } } - iter->cursor = iter->first; + iter.cursor = iter.first; for (size_t i = target->capacity; i > 0; i--) { - if (target->buffer[i - 1][0] != ((void *)0)) + if (target->buffer[i - 1][1] != ((void *)0)) { - iter->last = i - 1; + iter.last = i - 1; break; } } } + return iter; } -_Bool hmm_iter_start(struct hashmultimap_iter *iter) +struct hashmultimap_iter hmm_iter_end(struct hashmultimap *target) +{ + struct hashmultimap_iter iter; + iter.target = target; + iter.curr_entry = ((void *)0); + iter.cursor = 0; + iter.index = 0; + iter.first = 0; + iter.last = 0; + iter.start = hmm_empty(target); + iter.end = 1; + if (!hmm_empty(target)) + { + for (size_t i = 0; i < target->capacity; i++) + { + if (target->buffer[i][0] != ((void *)0)) + { + iter.first = i; + break; + } + } + for (size_t i = target->capacity; i > 0; i--) + { + if (target->buffer[i - 1][1] != ((void *)0)) + { + iter.curr_entry = target->buffer[i - 1][1]; + iter.last = i - 1; + break; + } + } + iter.cursor = iter.last; + iter.index = target->count - 1; + } + return iter; +} +_Bool hmm_iter_at_start(struct hashmultimap_iter *iter) { return hmm_empty(iter->target) || iter->start; } -_Bool hmm_iter_end(struct hashmultimap_iter *iter) +_Bool hmm_iter_at_end(struct hashmultimap_iter *iter) { return hmm_empty(iter->target) || iter->end; } -void hmm_iter_to_start(struct hashmultimap_iter *iter) +_Bool hmm_iter_to_start(struct hashmultimap_iter *iter) { if (!hmm_empty(iter->target)) { @@ -815,9 +828,11 @@ void hmm_iter_to_start(struct hashmultimap_iter *iter) iter->start = 1; iter->end = hmm_empty(iter->target); iter->curr_entry = iter->target->buffer[iter->first][0]; + return 1; } + return 0; } -void hmm_iter_to_end(struct hashmultimap_iter *iter) +_Bool hmm_iter_to_end(struct hashmultimap_iter *iter) { if (!hmm_empty(iter->target)) { @@ -826,7 +841,9 @@ void hmm_iter_to_end(struct hashmultimap_iter *iter) iter->start = hmm_empty(iter->target); iter->end = 1; iter->curr_entry = iter->target->buffer[iter->last][1]; + return 1; } + return 0; } _Bool hmm_iter_next(struct hashmultimap_iter *iter) { @@ -992,16 +1009,3 @@ size_t hmm_impl_calculate_size(size_t required) i++; return cmc_hashtable_primes[i]; } -static struct hashmultimap_iter hmm_impl_it_start(struct hashmultimap *_map_) -{ - struct hashmultimap_iter iter; - hmm_iter_init(&iter, _map_); - return iter; -} -static struct hashmultimap_iter hmm_impl_it_end(struct hashmultimap *_map_) -{ - struct hashmultimap_iter iter; - hmm_iter_init(&iter, _map_); - hmm_iter_to_end(&iter); - return iter; -} diff --git a/tests/main/unt/hashmultimap.c b/tests/main/unt/hashmultimap.c index 08bf285..237e06c 100644 --- a/tests/main/unt/hashmultimap.c +++ b/tests/main/unt/hashmultimap.c @@ -190,7 +190,7 @@ CMC_CREATE_UNIT(HashMultiMap, true, { hmm_free(map); }); - CMC_CREATE_TEST(remove[count], { + CMC_CREATE_TEST(PFX##_remove(), { struct hashmultimap *map = hmm_new(100, 0.8, hmm_fkey, hmm_fval); cmc_assert_not_equals(ptr, NULL, map); @@ -206,27 +206,21 @@ CMC_CREATE_UNIT(HashMultiMap, true, { cmc_assert_equals(size_t, 140, hmm_count(map)); hmm_free(map); - }); - CMC_CREATE_TEST(remove[count = 0], { - struct hashmultimap *map = hmm_new(100, 0.8, hmm_fkey, hmm_fval); + // count = 0 + map = hmm_new(100, 0.8, hmm_fkey, hmm_fval); cmc_assert_not_equals(ptr, NULL, map); - size_t r; - cmc_assert(!hmm_remove(map, 10, &r)); hmm_free(map); - }); - CMC_CREATE_TEST(remove[count = 1], { - struct hashmultimap *map = hmm_new(100, 0.8, hmm_fkey, hmm_fval); + // count = 1 + map = hmm_new(100, 0.8, hmm_fkey, hmm_fval); cmc_assert_not_equals(ptr, NULL, map); - size_t r; - cmc_assert(hmm_insert(map, 10, 11)); cmc_assert(hmm_remove(map, 10, &r)); @@ -486,3 +480,459 @@ CMC_CREATE_UNIT(HashMultiMap, true, { total_resize = 0; }); }); + +struct hashmultimap_fkey *hmm_fkey_numhash = + &(struct hashmultimap_fkey){ .cmp = cmc_size_cmp, + .cpy = NULL, + .str = cmc_size_str, + .free = NULL, + .hash = numhash, + .pri = cmc_size_cmp }; + +CMC_CREATE_UNIT(HashMultiMapIter, true, { + CMC_CREATE_TEST(PFX##_iter_start(), { + struct hashmultimap *map = + hmm_new(100, 0.6, hmm_fkey_numhash, hmm_fval); + + cmc_assert_not_equals(ptr, NULL, map); + + struct hashmultimap_iter it = hmm_iter_start(map); + + cmc_assert_equals(ptr, map, it.target); + cmc_assert_equals(size_t, 0, it.cursor); + cmc_assert_equals(size_t, 0, it.index); + cmc_assert_equals(size_t, 0, it.first); + cmc_assert_equals(size_t, 0, it.last); + cmc_assert_equals(bool, true, it.start); + cmc_assert_equals(bool, true, it.end); + + cmc_assert(hmm_iter_at_start(&it)); + cmc_assert(hmm_iter_at_end(&it)); + + cmc_assert(hmm_insert(map, 1, 1)); + cmc_assert(hmm_insert(map, 2, 2)); + cmc_assert(hmm_insert(map, 3, 3)); + + it = hmm_iter_start(map); + + cmc_assert_equals(size_t, 0, it.index); + + cmc_assert_equals(size_t, 1, it.cursor); + cmc_assert_equals(size_t, 1, it.first); + cmc_assert_equals(size_t, 3, it.last); + + hmm_free(map); + }); + + CMC_CREATE_TEST(PFX##_iter_end(), { + struct hashmultimap *map = + hmm_new(100, 0.6, hmm_fkey_numhash, hmm_fval); + + cmc_assert_not_equals(ptr, NULL, map); + + struct hashmultimap_iter it = hmm_iter_end(map); + + cmc_assert_equals(ptr, map, it.target); + cmc_assert_equals(size_t, 0, it.cursor); + cmc_assert_equals(size_t, 0, it.index); + cmc_assert_equals(size_t, 0, it.first); + cmc_assert_equals(size_t, 0, it.last); + cmc_assert_equals(bool, true, it.start); + cmc_assert_equals(bool, true, it.end); + + cmc_assert(hmm_iter_at_start(&it)); + cmc_assert(hmm_iter_at_end(&it)); + + cmc_assert(hmm_insert(map, 1, 1)); + cmc_assert(hmm_insert(map, 2, 2)); + cmc_assert(hmm_insert(map, 3, 3)); + + it = hmm_iter_end(map); + + cmc_assert_equals(size_t, map->count - 1, it.index); + + cmc_assert_equals(size_t, 3, it.cursor); + cmc_assert_equals(size_t, 1, it.first); + cmc_assert_equals(size_t, 3, it.last); + + hmm_free(map); + }); + + CMC_CREATE_TEST(PFX##_iter_at_start(), { + struct hashmultimap *map = hmm_new(100, 0.6, hmm_fkey, hmm_fval); + + cmc_assert_not_equals(ptr, NULL, map); + + struct hashmultimap_iter it = hmm_iter_start(map); + + // Empty checks + cmc_assert(hmm_iter_at_start(&it)); + it = hmm_iter_end(map); + cmc_assert(hmm_iter_at_start(&it)); + + // Non-empty checks + cmc_assert(hmm_insert(map, 1, 1)); + cmc_assert(hmm_insert(map, 2, 2)); + it = hmm_iter_end(map); + cmc_assert(!hmm_iter_at_start(&it)); + it = hmm_iter_start(map); + cmc_assert(hmm_iter_at_start(&it)); + + hmm_free(map); + }); + + CMC_CREATE_TEST(PFX##_iter_at_end(), { + struct hashmultimap *map = hmm_new(100, 0.6, hmm_fkey, hmm_fval); + + cmc_assert_not_equals(ptr, NULL, map); + + struct hashmultimap_iter it = hmm_iter_start(map); + + // Empty check + cmc_assert(hmm_iter_at_end(&it)); + it = hmm_iter_end(map); + cmc_assert(hmm_iter_at_end(&it)); + + // Non-empty checks + cmc_assert(hmm_insert(map, 1, 1)); + cmc_assert(hmm_insert(map, 2, 2)); + it = hmm_iter_end(map); + cmc_assert(hmm_iter_at_end(&it)); + it = hmm_iter_start(map); + cmc_assert(!hmm_iter_at_end(&it)); + + hmm_free(map); + }); + + CMC_CREATE_TEST(PFX##_iter_to_start(), { + struct hashmultimap *map = + hmm_new(100, 0.6, hmm_fkey_numhash, hmm_fval); + + cmc_assert_not_equals(ptr, NULL, map); + + struct hashmultimap_iter it = hmm_iter_start(map); + + cmc_assert(!hmm_iter_to_start(&it)); + + for (size_t i = 1; i <= 100; i++) + hmm_insert(map, i, i); + + cmc_assert_equals(size_t, 100, map->count); + + it = hmm_iter_end(map); + + cmc_assert(!hmm_iter_at_start(&it)); + cmc_assert(hmm_iter_at_end(&it)); + + cmc_assert_equals(size_t, 100, hmm_iter_value(&it)); + + cmc_assert(hmm_iter_to_start(&it)); + + cmc_assert(hmm_iter_at_start(&it)); + cmc_assert(!hmm_iter_at_end(&it)); + + cmc_assert_equals(size_t, 1, hmm_iter_value(&it)); + + hmm_free(map); + }); + + CMC_CREATE_TEST(PFX##_iter_to_end(), { + struct hashmultimap *map = + hmm_new(100, 0.6, hmm_fkey_numhash, hmm_fval); + + cmc_assert_not_equals(ptr, NULL, map); + + struct hashmultimap_iter it = hmm_iter_end(map); + + cmc_assert(!hmm_iter_to_end(&it)); + + for (size_t i = 1; i <= 100; i++) + hmm_insert(map, i, i); + + it = hmm_iter_start(map); + + cmc_assert(hmm_iter_at_start(&it)); + cmc_assert(!hmm_iter_at_end(&it)); + + cmc_assert_equals(size_t, 1, hmm_iter_value(&it)); + + cmc_assert(hmm_iter_to_end(&it)); + + cmc_assert(!hmm_iter_at_start(&it)); + cmc_assert(hmm_iter_at_end(&it)); + + cmc_assert_equals(size_t, 100, hmm_iter_value(&it)); + + hmm_free(map); + }); + + CMC_CREATE_TEST(PFX##_iter_next(), { + struct hashmultimap *map = hmm_new(100, 0.6, hmm_fkey, hmm_fval); + + cmc_assert_not_equals(ptr, NULL, map); + + struct hashmultimap_iter it = hmm_iter_start(map); + + cmc_assert(!hmm_iter_next(&it)); + + for (size_t i = 1; i <= 1000; i++) + hmm_insert(map, i, i); + + size_t sum = 0; + for (it = hmm_iter_start(map); !hmm_iter_at_end(&it); + hmm_iter_next(&it)) + { + sum += hmm_iter_value(&it); + } + + cmc_assert_equals(size_t, 500500, sum); + + sum = 0; + + hmm_iter_to_start(&it); + do + { + sum += hmm_iter_value(&it); + } while (hmm_iter_next(&it)); + + cmc_assert_equals(size_t, 500500, sum); + + hmm_free(map); + }); + + CMC_CREATE_TEST(PFX##_iter_prev(), { + struct hashmultimap *map = hmm_new(100, 0.6, hmm_fkey, hmm_fval); + + cmc_assert_not_equals(ptr, NULL, map); + + struct hashmultimap_iter it = hmm_iter_end(map); + + cmc_assert(!hmm_iter_prev(&it)); + + for (size_t i = 1; i <= 1000; i++) + hmm_insert(map, i, i); + + size_t sum = 0; + for (it = hmm_iter_end(map); !hmm_iter_at_start(&it); + hmm_iter_prev(&it)) + { + sum += hmm_iter_value(&it); + } + + cmc_assert_equals(size_t, 500500, sum); + + sum = 0; + + hmm_iter_to_end(&it); + do + { + sum += hmm_iter_value(&it); + } while (hmm_iter_prev(&it)); + + cmc_assert_equals(size_t, 500500, sum); + + hmm_free(map); + }); + + CMC_CREATE_TEST(PFX##_iter_advance(), { + struct hashmultimap *map = + hmm_new(100, 0.6, hmm_fkey_numhash, hmm_fval); + + cmc_assert_not_equals(ptr, NULL, map); + + struct hashmultimap_iter it = hmm_iter_start(map); + + cmc_assert(!hmm_iter_advance(&it, 1)); + + for (size_t i = 0; i <= 1000; i++) + hmm_insert(map, i, i); + + it = hmm_iter_start(map); + + cmc_assert(!hmm_iter_advance(&it, 0)); + cmc_assert(!hmm_iter_advance(&it, map->count)); + + size_t sum = 0; + for (it = hmm_iter_start(map);;) + { + sum += hmm_iter_value(&it); + + if (!hmm_iter_advance(&it, 2)) + break; + } + + cmc_assert_equals(size_t, 250500, sum); + + hmm_iter_to_start(&it); + cmc_assert(hmm_iter_advance(&it, map->count - 1)); + + hmm_free(map); + }); + + CMC_CREATE_TEST(PFX##_iter_rewind(), { + struct hashmultimap *map = + hmm_new(100, 0.6, hmm_fkey_numhash, hmm_fval); + + cmc_assert_not_equals(ptr, NULL, map); + + struct hashmultimap_iter it = hmm_iter_end(map); + + cmc_assert(!hmm_iter_rewind(&it, 1)); + + for (size_t i = 0; i <= 1000; i++) + hmm_insert(map, i, i); + + it = hmm_iter_end(map); + + cmc_assert(!hmm_iter_rewind(&it, 0)); + cmc_assert(!hmm_iter_rewind(&it, map->count)); + + size_t sum = 0; + for (it = hmm_iter_end(map);;) + { + sum += hmm_iter_value(&it); + + if (!hmm_iter_rewind(&it, 2)) + break; + } + + cmc_assert_equals(size_t, 250500, sum); + + hmm_iter_to_end(&it); + cmc_assert(hmm_iter_rewind(&it, map->count - 1)); + + hmm_free(map); + }); + + CMC_CREATE_TEST(PFX##_iter_go_to(), { + struct hashmultimap *map = + hmm_new(100, 0.6, hmm_fkey_numhash, hmm_fval); + + cmc_assert_not_equals(ptr, NULL, map); + + struct hashmultimap_iter it = hmm_iter_end(map); + cmc_assert(!hmm_iter_go_to(&it, 0)); + + it = hmm_iter_start(map); + cmc_assert(!hmm_iter_go_to(&it, 0)); + + for (size_t i = 0; i <= 1000; i++) + hmm_insert(map, i, i); + + it = hmm_iter_start(map); + + size_t sum = 0; + for (size_t i = 0; i < 1001; i++) + { + hmm_iter_go_to(&it, i); + + sum += hmm_iter_value(&it); + } + + cmc_assert_equals(size_t, 500500, sum); + + sum = 0; + for (size_t i = 1001; i > 0; i--) + { + cmc_assert(hmm_iter_go_to(&it, i - 1)); + + sum += hmm_iter_value(&it); + } + + cmc_assert_equals(size_t, 500500, sum); + + sum = 0; + for (size_t i = 0; i < 1001; i += 100) + { + cmc_assert(hmm_iter_go_to(&it, i)); + cmc_assert_equals(size_t, i, hmm_iter_index(&it)); + + sum += hmm_iter_value(&it); + } + + cmc_assert_equals(size_t, 5500, sum); + + hmm_free(map); + }); + + CMC_CREATE_TEST(PFX##_iter_key(), { + struct hashmultimap *map = hmm_new(100, 0.6, hmm_fkey, hmm_fval); + + cmc_assert_not_equals(ptr, NULL, map); + + struct hashmultimap_iter it = hmm_iter_end(map); + + cmc_assert_equals(size_t, (size_t){ 0 }, hmm_iter_key(&it)); + + cmc_assert(hmm_insert(map, 10, 10)); + + it = hmm_iter_start(map); + + cmc_assert_equals(size_t, 10, hmm_iter_key(&it)); + + hmm_free(map); + }); + + CMC_CREATE_TEST(PFX##_iter_value(), { + struct hashmultimap *map = hmm_new(100, 0.6, hmm_fkey, hmm_fval); + + cmc_assert_not_equals(ptr, NULL, map); + + struct hashmultimap_iter it = hmm_iter_end(map); + + cmc_assert_equals(size_t, (size_t){ 0 }, hmm_iter_value(&it)); + + cmc_assert(hmm_insert(map, 10, 10)); + + it = hmm_iter_start(map); + + cmc_assert_equals(size_t, 10, hmm_iter_value(&it)); + + hmm_free(map); + }); + + CMC_CREATE_TEST(PFX##_iter_rvalue(), { + struct hashmultimap *map = hmm_new(100, 0.6, hmm_fkey, hmm_fval); + + cmc_assert_not_equals(ptr, NULL, map); + + struct hashmultimap_iter it = hmm_iter_end(map); + + cmc_assert_equals(ptr, NULL, hmm_iter_rvalue(&it)); + + cmc_assert(hmm_insert(map, 10, 10)); + + it = hmm_iter_start(map); + + cmc_assert_not_equals(ptr, NULL, hmm_iter_rvalue(&it)); + cmc_assert_equals(size_t, 10, *hmm_iter_rvalue(&it)); + + hmm_free(map); + }); + + CMC_CREATE_TEST(PFX##_iter_index(), { + struct hashmultimap *map = hmm_new(100, 0.6, hmm_fkey, hmm_fval); + + cmc_assert_not_equals(ptr, NULL, map); + + for (size_t i = 0; i <= 1000; i++) + hmm_insert(map, i, i); + + struct hashmultimap_iter it = hmm_iter_start(map); + + for (size_t i = 0; i < 1001; i++) + { + cmc_assert_equals(size_t, i, hmm_iter_index(&it)); + hmm_iter_next(&it); + } + + it = hmm_iter_end(map); + for (size_t i = 1001; i > 0; i--) + { + cmc_assert_equals(size_t, i - 1, hmm_iter_index(&it)); + hmm_iter_prev(&it); + } + + hmm_free(map); + }); +});