diff --git a/src/cmc/hashmap.h b/src/cmc/hashmap.h index 52ba203..33bafb3 100644 --- a/src/cmc/hashmap.h +++ b/src/cmc/hashmap.h @@ -224,17 +224,15 @@ static const char *cmc_string_fmt_hashmap = "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); \ @@ -576,8 +574,7 @@ static const char *cmc_string_fmt_hashmap = "struct %s<%s, %s> " return false; \ } \ \ - struct SNAME##_iter iter; \ - PFX##_iter_init(&iter, _map_); \ + struct SNAME##_iter iter = PFX##_iter_start(_map_); \ \ K max_key = PFX##_iter_key(&iter); \ V max_val = PFX##_iter_value(&iter); \ @@ -585,7 +582,7 @@ static const char *cmc_string_fmt_hashmap = "struct %s<%s, %s> " PFX##_iter_next(&iter); \ \ /* TODO Turn this into a normal loop */ \ - for (; !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \ + for (; !PFX##_iter_at_end(&iter); PFX##_iter_next(&iter)) \ { \ K iter_key = PFX##_iter_key(&iter); \ V iter_val = PFX##_iter_value(&iter); \ @@ -616,8 +613,7 @@ static const char *cmc_string_fmt_hashmap = "struct %s<%s, %s> " return false; \ } \ \ - struct SNAME##_iter iter; \ - PFX##_iter_init(&iter, _map_); \ + struct SNAME##_iter iter = PFX##_iter_start(_map_); \ \ K min_key = PFX##_iter_key(&iter); \ V min_val = PFX##_iter_value(&iter); \ @@ -625,7 +621,7 @@ static const char *cmc_string_fmt_hashmap = "struct %s<%s, %s> " PFX##_iter_next(&iter); \ \ /* TODO Turn this into a normal loop */ \ - for (; !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \ + for (; !PFX##_iter_at_end(&iter); PFX##_iter_next(&iter)) \ { \ K iter_key = PFX##_iter_key(&iter); \ V iter_val = PFX##_iter_value(&iter); \ @@ -776,11 +772,10 @@ static const char *cmc_string_fmt_hashmap = "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); \ @@ -880,12 +875,10 @@ static const char *cmc_string_fmt_hashmap = "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 optimize this 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)) \ { \ struct SNAME##_entry *entry = \ PFX##_impl_get_entry(_map2_, PFX##_iter_key(&iter)); \ @@ -931,31 +924,17 @@ static const char *cmc_string_fmt_hashmap = "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.cursor = 0; \ + iter.index = 0; \ + iter.first = 0; \ + iter.last = 0; \ + iter.start = true; \ + iter.end = PFX##_empty(target); \ \ if (!PFX##_empty(target)) \ { \ @@ -963,35 +942,76 @@ static const char *cmc_string_fmt_hashmap = "struct %s<%s, %s> " { \ if (target->buffer[i].state == CMC_ES_FILLED) \ { \ - iter->first = i; \ + 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].state == CMC_ES_FILLED) \ { \ - 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.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].state == CMC_ES_FILLED) \ + { \ + iter.first = i; \ + break; \ + } \ + } \ + \ + for (size_t i = target->capacity; i > 0; i--) \ + { \ + if (target->buffer[i - 1].state == CMC_ES_FILLED) \ + { \ + 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)) \ { \ @@ -999,10 +1019,14 @@ static const char *cmc_string_fmt_hashmap = "struct %s<%s, %s> " iter->index = 0; \ iter->start = true; \ iter->end = PFX##_empty(iter->target); \ + \ + 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)) \ { \ @@ -1010,7 +1034,11 @@ static const char *cmc_string_fmt_hashmap = "struct %s<%s, %s> " iter->index = iter->target->count - 1; \ iter->start = PFX##_empty(iter->target); \ iter->end = true; \ + \ + return true; \ } \ + \ + return false; \ } \ \ bool PFX##_iter_next(struct SNAME##_iter *iter) \ diff --git a/tests/main/main.c b/tests/main/main.c index 92b5c49..08f149c 100644 --- a/tests/main/main.c +++ b/tests/main/main.c @@ -44,12 +44,13 @@ int main(void) struct cmc_timer timer; cmc_timer_start(timer); - uintmax_t tests = 0, units = 0, f; + uintmax_t tests = 0, units = 0; cmc_run(BidiMap, units, tests); cmc_run(Deque, units, tests); cmc_run(DequeIter, units, tests); cmc_run(HashMap, units, tests); + cmc_run(HashMapIter, units, tests); cmc_run(HashSet, units, tests); cmc_run(Heap, units, tests); cmc_run(IntervalHeap, units, tests); @@ -71,7 +72,7 @@ int main(void) " | SUMMARY |\n"); printf( " +---------------------------------------------------------------+\n"); - printf(" | Total Units Failed : %25" PRIuMAX " units |\n", tests); + printf(" | Total Units Failed : %25" PRIuMAX " units |\n", units); printf(" | Total Tests Failed : %25" PRIuMAX " tests |\n", tests); printf(" | Total Asserts Failed : %25" PRIuMAX " asserts |\n", cmc_assert_failed); diff --git a/tests/main/src/hashmap.c b/tests/main/src/hashmap.c index b7490c1..462ca88 100644 --- a/tests/main/src/hashmap.c +++ b/tests/main/src/hashmap.c @@ -86,13 +86,12 @@ struct hashmap *hm_copy_of(struct hashmap *_map_); _Bool hm_equals(struct hashmap *_map1_, struct hashmap *_map2_); struct cmc_string hm_to_string(struct hashmap *_map_); _Bool hm_print(struct hashmap *_map_, FILE *fptr); -struct hashmap_iter *hm_iter_new(struct hashmap *target); -void hm_iter_free(struct hashmap_iter *iter); -void hm_iter_init(struct hashmap_iter *iter, struct hashmap *target); -_Bool hm_iter_start(struct hashmap_iter *iter); -_Bool hm_iter_end(struct hashmap_iter *iter); -void hm_iter_to_start(struct hashmap_iter *iter); -void hm_iter_to_end(struct hashmap_iter *iter); +struct hashmap_iter hm_iter_start(struct hashmap *target); +struct hashmap_iter hm_iter_end(struct hashmap *target); +_Bool hm_iter_at_start(struct hashmap_iter *iter); +_Bool hm_iter_at_end(struct hashmap_iter *iter); +_Bool hm_iter_to_start(struct hashmap_iter *iter); +_Bool hm_iter_to_end(struct hashmap_iter *iter); _Bool hm_iter_next(struct hashmap_iter *iter); _Bool hm_iter_prev(struct hashmap_iter *iter); _Bool hm_iter_advance(struct hashmap_iter *iter, size_t steps); @@ -359,12 +358,11 @@ _Bool hm_max(struct hashmap *_map_, size_t *key, size_t *value) _map_->flag = cmc_flags.EMPTY; return 0; } - struct hashmap_iter iter; - hm_iter_init(&iter, _map_); + struct hashmap_iter iter = hm_iter_start(_map_); size_t max_key = hm_iter_key(&iter); size_t max_val = hm_iter_value(&iter); hm_iter_next(&iter); - for (; !hm_iter_end(&iter); hm_iter_next(&iter)) + for (; !hm_iter_at_end(&iter); hm_iter_next(&iter)) { size_t iter_key = hm_iter_key(&iter); size_t iter_val = hm_iter_value(&iter); @@ -389,12 +387,11 @@ _Bool hm_min(struct hashmap *_map_, size_t *key, size_t *value) _map_->flag = cmc_flags.EMPTY; return 0; } - struct hashmap_iter iter; - hm_iter_init(&iter, _map_); + struct hashmap_iter iter = hm_iter_start(_map_); size_t min_key = hm_iter_key(&iter); size_t min_val = hm_iter_value(&iter); hm_iter_next(&iter); - for (; !hm_iter_end(&iter); hm_iter_next(&iter)) + for (; !hm_iter_at_end(&iter); hm_iter_next(&iter)) { size_t iter_key = hm_iter_key(&iter); size_t iter_val = hm_iter_value(&iter); @@ -506,8 +503,8 @@ _Bool hm_resize(struct hashmap *_map_, size_t capacity) _map_->flag = cmc_flags.ALLOC; return 0; } - struct hashmap_iter iter; - for (hm_iter_init(&iter, _map_); !hm_iter_end(&iter); hm_iter_next(&iter)) + struct hashmap_iter iter = hm_iter_start(_map_); + for (; !hm_iter_at_end(&iter); hm_iter_next(&iter)) { size_t key = hm_iter_key(&iter); size_t value = hm_iter_value(&iter); @@ -582,9 +579,8 @@ _Bool hm_equals(struct hashmap *_map1_, struct hashmap *_map2_) _map2_->flag = cmc_flags.OK; if (_map1_->count != _map2_->count) return 0; - struct hashmap_iter iter; - hm_iter_init(&iter, _map1_); - for (hm_iter_to_start(&iter); !hm_iter_end(&iter); hm_iter_next(&iter)) + struct hashmap_iter iter = hm_iter_start(_map1_); + for (; !hm_iter_at_end(&iter); hm_iter_next(&iter)) { struct hashmap_entry *entry = hm_impl_get_entry(_map2_, hm_iter_key(&iter)); @@ -619,55 +615,80 @@ _Bool hm_print(struct hashmap *_map_, FILE *fptr) } return 1; } -struct hashmap_iter *hm_iter_new(struct hashmap *target) +struct hashmap_iter hm_iter_start(struct hashmap *target) { - struct hashmap_iter *iter = - target->alloc->malloc(sizeof(struct hashmap_iter)); - if (!iter) - return ((void *)0); - hm_iter_init(iter, target); - return iter; -} -void hm_iter_free(struct hashmap_iter *iter) -{ - iter->target->alloc->free(iter); -} -void hm_iter_init(struct hashmap_iter *iter, struct hashmap *target) -{ - memset(iter, 0, sizeof(struct hashmap_iter)); - iter->target = target; - iter->start = 1; - iter->end = hm_empty(target); + struct hashmap_iter iter; + iter.target = target; + iter.cursor = 0; + iter.index = 0; + iter.first = 0; + iter.last = 0; + iter.start = 1; + iter.end = hm_empty(target); if (!hm_empty(target)) { for (size_t i = 0; i < target->capacity; i++) { if (target->buffer[i].state == CMC_ES_FILLED) { - iter->first = i; + 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].state == CMC_ES_FILLED) { - iter->last = i - 1; + iter.last = i - 1; break; } } } + return iter; } -_Bool hm_iter_start(struct hashmap_iter *iter) +struct hashmap_iter hm_iter_end(struct hashmap *target) +{ + struct hashmap_iter iter; + iter.target = target; + iter.cursor = 0; + iter.index = 0; + iter.first = 0; + iter.last = 0; + iter.start = hm_empty(target); + iter.end = 1; + if (!hm_empty(target)) + { + for (size_t i = 0; i < target->capacity; i++) + { + if (target->buffer[i].state == CMC_ES_FILLED) + { + iter.first = i; + break; + } + } + for (size_t i = target->capacity; i > 0; i--) + { + if (target->buffer[i - 1].state == CMC_ES_FILLED) + { + iter.last = i - 1; + break; + } + } + iter.cursor = iter.last; + iter.index = target->count - 1; + } + return iter; +} +_Bool hm_iter_at_start(struct hashmap_iter *iter) { return hm_empty(iter->target) || iter->start; } -_Bool hm_iter_end(struct hashmap_iter *iter) +_Bool hm_iter_at_end(struct hashmap_iter *iter) { return hm_empty(iter->target) || iter->end; } -void hm_iter_to_start(struct hashmap_iter *iter) +_Bool hm_iter_to_start(struct hashmap_iter *iter) { if (!hm_empty(iter->target)) { @@ -675,9 +696,11 @@ void hm_iter_to_start(struct hashmap_iter *iter) iter->index = 0; iter->start = 1; iter->end = hm_empty(iter->target); + return 1; } + return 0; } -void hm_iter_to_end(struct hashmap_iter *iter) +_Bool hm_iter_to_end(struct hashmap_iter *iter) { if (!hm_empty(iter->target)) { @@ -685,7 +708,9 @@ void hm_iter_to_end(struct hashmap_iter *iter) iter->index = iter->target->count - 1; iter->start = hm_empty(iter->target); iter->end = 1; + return 1; } + return 0; } _Bool hm_iter_next(struct hashmap_iter *iter) { diff --git a/tests/main/unt/deque.c b/tests/main/unt/deque.c index e960c0c..49571d5 100644 --- a/tests/main/unt/deque.c +++ b/tests/main/unt/deque.c @@ -1542,12 +1542,12 @@ CMC_CREATE_UNIT(DequeIter, true, { cmc_assert(!d_iter_advance(&it, 1)); - for (size_t i = 1; i <= 1000; i++) + for (size_t i = 0; i <= 1000; i++) { - if (i % 2 != 0) - d_push_back(d, i); + if (i % 2 == 0) + d_push_back(d, i); // will sum all even numbers else - d_push_back(d, 0); // will sum all odd numbers + d_push_back(d, 0); } it = d_iter_start(d); @@ -1564,7 +1564,7 @@ CMC_CREATE_UNIT(DequeIter, true, { break; } - cmc_assert_equals(size_t, 250000, sum); + cmc_assert_equals(size_t, 250500, sum); d_iter_to_start(&it); cmc_assert(d_iter_advance(&it, d->count - 1)); @@ -1581,12 +1581,12 @@ CMC_CREATE_UNIT(DequeIter, true, { cmc_assert(!d_iter_rewind(&it, 1)); - for (size_t i = 1; i <= 1000; i++) + for (size_t i = 0; i <= 1000; i++) { - if (i % 2 != 0) - d_push_front(d, i); + if (i % 2 == 0) + d_push_front(d, i); // will sum all even numbers else - d_push_front(d, 0); // will sum all odd numbers + d_push_front(d, 0); } it = d_iter_end(d); @@ -1603,7 +1603,7 @@ CMC_CREATE_UNIT(DequeIter, true, { break; } - cmc_assert_equals(size_t, 250000, sum); + cmc_assert_equals(size_t, 250500, sum); d_iter_to_end(&it); cmc_assert(d_iter_rewind(&it, d->count - 1)); diff --git a/tests/main/unt/hashmap.c b/tests/main/unt/hashmap.c index b26be10..5c0382a 100644 --- a/tests/main/unt/hashmap.c +++ b/tests/main/unt/hashmap.c @@ -263,19 +263,41 @@ CMC_CREATE_UNIT(HashMap, true, { v_total_free = 0; }); - CMC_CREATE_TEST(insert, { + CMC_CREATE_TEST(PFX##_customize(), { struct hashmap *map = hm_new(100, 0.6, hm_fkey, hm_fval); cmc_assert_not_equals(ptr, NULL, map); - cmc_assert(hm_insert(map, 1, 1)); - cmc_assert_equals(size_t, 1, hm_count(map)); + map->flag = cmc_flags.ERROR; + hm_customize(map, hm_alloc_node, callbacks); + + cmc_assert_equals(ptr, hm_alloc_node, map->alloc); + cmc_assert_equals(ptr, callbacks, map->callbacks); + cmc_assert_equals(int32_t, cmc_flags.OK, map->flag); + + map->flag = cmc_flags.ERROR; + hm_customize(map, NULL, NULL); + + cmc_assert_equals(ptr, &cmc_alloc_node_default, map->alloc); + cmc_assert_equals(ptr, NULL, map->callbacks); + cmc_assert_equals(int32_t, cmc_flags.OK, map->flag); hm_free(map); }); - CMC_CREATE_TEST(insert[smallest capacity], { - struct hashmap *map = hm_new(1, 0.99, hm_fkey, hm_fval); + CMC_CREATE_TEST(PFX##_insert(), { + struct hashmap *map = hm_new(100, 0.6, hm_fkey, hm_fval); + + cmc_assert_not_equals(ptr, NULL, map); + + map->flag = cmc_flags.ERROR; + cmc_assert(hm_insert(map, 1, 1)); + cmc_assert_equals(int32_t, cmc_flags.OK, map->flag); + cmc_assert_equals(size_t, 1, hm_count(map)); + + hm_free(map); + + map = hm_new(1, 0.99, hm_fkey, hm_fval); cmc_assert_not_equals(ptr, NULL, map); @@ -283,10 +305,9 @@ CMC_CREATE_UNIT(HashMap, true, { cmc_assert(hm_insert(map, 1, 1)); hm_free(map); - }); - CMC_CREATE_TEST(insert[element position], { - struct hashmap *map = hm_new(1, 0.99, hm_fkey, hm_fval); + // element position + map = hm_new(1, 0.99, hm_fkey, hm_fval); // Temporary change // Using the numhash the key is the hash itself @@ -307,10 +328,9 @@ CMC_CREATE_UNIT(HashMap, true, { hm_fkey->hash = cmc_size_hash; hm_free(map); - }); - CMC_CREATE_TEST(insert[distance], { - struct hashmap *map = hm_new(500, 0.6, hm_fkey, hm_fval); + // distance + map = hm_new(500, 0.6, hm_fkey, hm_fval); // Temporary change hm_fkey->hash = hash0; @@ -328,17 +348,16 @@ CMC_CREATE_UNIT(HashMap, true, { hm_fkey->hash = cmc_size_hash; hm_free(map); - }); - CMC_CREATE_TEST(insert[distance wrap], { - struct hashmap *map = hm_new(1, 0.99, hm_fkey, hm_fval); + // distance wrap + map = hm_new(1, 0.99, hm_fkey, hm_fval); // Temporary change hm_fkey->hash = hashcapminus1; cmc_assert_not_equals(ptr, NULL, map); - size_t capacity = hm_capacity(map); + capacity = hm_capacity(map); // Just to be sure, not part of the test cmc_assert_equals(size_t, cmc_hashtable_primes[0] - 1, @@ -354,10 +373,9 @@ CMC_CREATE_UNIT(HashMap, true, { hm_fkey->hash = cmc_size_hash; hm_free(map); - }); - CMC_CREATE_TEST(insert[distances], { - struct hashmap *map = hm_new(1, 0.99, hm_fkey, hm_fval); + // distances + map = hm_new(1, 0.99, hm_fkey, hm_fval); // Temporary change hm_fkey->hash = hashcapminus4; @@ -375,10 +393,9 @@ CMC_CREATE_UNIT(HashMap, true, { hm_fkey->hash = cmc_size_hash; hm_free(map); - }); - CMC_CREATE_TEST(insert[buffer growth and item preservation], { - struct hashmap *map = hm_new(1, 0.99, hm_fkey, hm_fval); + // buffer growth and item preservation + map = hm_new(1, 0.99, hm_fkey, hm_fval); cmc_assert_not_equals(ptr, NULL, map); @@ -401,7 +418,7 @@ CMC_CREATE_UNIT(HashMap, true, { hm_free(map); }); - CMC_CREATE_TEST(update, { + CMC_CREATE_TEST(PFX##_update(), { struct hashmap *map = hm_new(100, 0.6, hm_fkey, hm_fval); cmc_assert_not_equals(ptr, NULL, map); @@ -414,37 +431,35 @@ CMC_CREATE_UNIT(HashMap, true, { cmc_assert_equals(size_t, 1, old); hm_free(map); - }); - CMC_CREATE_TEST(update[key not found], { - struct hashmap *map = hm_new(100, 0.6, hm_fkey, hm_fval); + // key not found + map = hm_new(100, 0.6, hm_fkey, hm_fval); cmc_assert_not_equals(ptr, NULL, map); for (size_t i = 0; i < 100; i++) - cmc_assert(hm_insert(map, i, i)); + hm_insert(map, i, i); cmc_assert(!hm_update(map, 120, 120, NULL)); hm_free(map); }); - CMC_CREATE_TEST(remove, { + CMC_CREATE_TEST(PFX##_remove(), { struct hashmap *map = hm_new(100, 0.6, hm_fkey, hm_fval); cmc_assert_not_equals(ptr, NULL, map); for (size_t i = 0; i < 100; i++) - cmc_assert(hm_insert(map, i, i)); + hm_insert(map, i, i); for (size_t i = 0; i < 100; i++) cmc_assert(hm_remove(map, i, NULL)); hm_free(map); - }); - CMC_CREATE_TEST(remove[count = 0], { - struct hashmap *map = hm_new(100, 0.6, hm_fkey, hm_fval); + // count = 0 + map = hm_new(100, 0.6, hm_fkey, hm_fval); cmc_assert_not_equals(ptr, NULL, map); @@ -452,15 +467,16 @@ CMC_CREATE_UNIT(HashMap, true, { cmc_assert(!hm_remove(map, i, NULL)); hm_free(map); - }); - CMC_CREATE_TEST(remove[key not found], { - struct hashmap *map = hm_new(100, 0.6, hm_fkey, hm_fval); + // key not found + map = hm_new(100, 0.6, hm_fkey, hm_fval); cmc_assert_not_equals(ptr, NULL, map); for (size_t i = 0; i < 100; i++) - cmc_assert(hm_insert(map, i, i)); + hm_insert(map, i, i); + + cmc_assert_equals(size_t, 100, map->count); for (size_t i = 100; i < 200; i++) cmc_assert(!hm_remove(map, i, NULL)); @@ -468,7 +484,7 @@ CMC_CREATE_UNIT(HashMap, true, { hm_free(map); }); - CMC_CREATE_TEST(max, { + CMC_CREATE_TEST(PFX##_max(), { struct hashmap *map = hm_new(100, 0.6, hm_fkey, hm_fval); cmc_assert_not_equals(ptr, NULL, map); @@ -484,10 +500,9 @@ CMC_CREATE_UNIT(HashMap, true, { cmc_assert_equals(size_t, 100, val); hm_free(map); - }); - CMC_CREATE_TEST(max[count = 0], { - struct hashmap *map = hm_new(100, 0.6, hm_fkey, hm_fval); + // count = 0 + map = hm_new(100, 0.6, hm_fkey, hm_fval); cmc_assert_not_equals(ptr, NULL, map); @@ -496,7 +511,7 @@ CMC_CREATE_UNIT(HashMap, true, { hm_free(map); }); - CMC_CREATE_TEST(min, { + CMC_CREATE_TEST(PFX##_min(), { struct hashmap *map = hm_new(100, 0.6, hm_fkey, hm_fval); cmc_assert_not_equals(ptr, NULL, map); @@ -512,10 +527,9 @@ CMC_CREATE_UNIT(HashMap, true, { cmc_assert_equals(size_t, 1, val); hm_free(map); - }); - CMC_CREATE_TEST(min[count = 0], { - struct hashmap *map = hm_new(100, 0.6, hm_fkey, hm_fval); + // count = 0 + map = hm_new(100, 0.6, hm_fkey, hm_fval); cmc_assert_not_equals(ptr, NULL, map); @@ -524,7 +538,7 @@ CMC_CREATE_UNIT(HashMap, true, { hm_free(map); }); - CMC_CREATE_TEST(get, { + CMC_CREATE_TEST(PFX##_get(), { struct hashmap *map = hm_new(100, 0.6, hm_fkey, hm_fval); cmc_assert_not_equals(ptr, NULL, map); @@ -534,10 +548,9 @@ CMC_CREATE_UNIT(HashMap, true, { cmc_assert_equals(size_t, 1234, hm_get(map, 4321)); hm_free(map); - }); - CMC_CREATE_TEST(get[count = 0], { - struct hashmap *map = hm_new(100, 0.6, hm_fkey, hm_fval); + // count = 0 + map = hm_new(100, 0.6, hm_fkey, hm_fval); cmc_assert_not_equals(ptr, NULL, map); @@ -546,7 +559,7 @@ CMC_CREATE_UNIT(HashMap, true, { hm_free(map); }); - CMC_CREATE_TEST(get_ref, { + CMC_CREATE_TEST(PFX##_get_ref(), { struct hashmap *map = hm_new(100, 0.6, hm_fkey, hm_fval); cmc_assert_not_equals(ptr, NULL, map); @@ -559,10 +572,9 @@ CMC_CREATE_UNIT(HashMap, true, { cmc_assert_equals(size_t, 1234, *result); hm_free(map); - }); - CMC_CREATE_TEST(get_ref[count = 0], { - struct hashmap *map = hm_new(100, 0.6, hm_fkey, hm_fval); + // count = 0 + map = hm_new(100, 0.6, hm_fkey, hm_fval); cmc_assert_not_equals(ptr, NULL, map); @@ -571,7 +583,7 @@ CMC_CREATE_UNIT(HashMap, true, { hm_free(map); }); - CMC_CREATE_TEST(contains, { + CMC_CREATE_TEST(PFX##_contains(), { struct hashmap *map = hm_new(100, 0.6, hm_fkey, hm_fval); cmc_assert_not_equals(ptr, NULL, map); @@ -581,20 +593,18 @@ CMC_CREATE_UNIT(HashMap, true, { cmc_assert(hm_contains(map, 987654321)); hm_free(map); - }); - CMC_CREATE_TEST(contains[count = 0], { - struct hashmap *map = hm_new(100, 0.6, hm_fkey, hm_fval); + // count = 0 + map = hm_new(100, 0.6, hm_fkey, hm_fval); cmc_assert_not_equals(ptr, NULL, map); cmc_assert(!hm_contains(map, 987654321)); hm_free(map); - }); - CMC_CREATE_TEST(contains[sum], { - struct hashmap *map = hm_new(100, 0.6, hm_fkey, hm_fval); + // sum + map = hm_new(100, 0.6, hm_fkey, hm_fval); cmc_assert_not_equals(ptr, NULL, map); @@ -611,7 +621,7 @@ CMC_CREATE_UNIT(HashMap, true, { hm_free(map); }); - CMC_CREATE_TEST(empty, { + CMC_CREATE_TEST(PFX##_empty(), { struct hashmap *map = hm_new(100, 0.6, hm_fkey, hm_fval); cmc_assert_not_equals(ptr, NULL, map); @@ -625,7 +635,7 @@ CMC_CREATE_UNIT(HashMap, true, { hm_free(map); }); - CMC_CREATE_TEST(full, { + CMC_CREATE_TEST(PFX##_full(), { struct hashmap *map = hm_new(cmc_hashtable_primes[0], 0.99999, hm_fkey, hm_fval); @@ -647,7 +657,7 @@ CMC_CREATE_UNIT(HashMap, true, { hm_free(map); }); - CMC_CREATE_TEST(count, { + CMC_CREATE_TEST(PFX##_count(), { struct hashmap *map = hm_new(100, 0.6, hm_fkey, hm_fval); cmc_assert_not_equals(ptr, NULL, map); @@ -661,7 +671,7 @@ CMC_CREATE_UNIT(HashMap, true, { hm_free(map); }); - CMC_CREATE_TEST(capacity, { + CMC_CREATE_TEST(PFX##_capacity(), { struct hashmap *map = hm_new(2500, 0.6, hm_fkey, hm_fval); cmc_assert_not_equals(ptr, NULL, map); @@ -670,10 +680,9 @@ CMC_CREATE_UNIT(HashMap, true, { hm_capacity(map)); hm_free(map); - }); - CMC_CREATE_TEST(capacity[small], { - struct hashmap *map = hm_new(1, 0.99, hm_fkey, hm_fval); + // small capacity + map = hm_new(1, 0.99, hm_fkey, hm_fval); cmc_assert_not_equals(ptr, NULL, map); @@ -682,7 +691,7 @@ CMC_CREATE_UNIT(HashMap, true, { hm_free(map); }); - CMC_CREATE_TEST(load, { + CMC_CREATE_TEST(PFX##_load(), { struct hashmap *map = hm_new(1, 0.99, hm_fkey, hm_fval); cmc_assert_not_equals(ptr, NULL, map); @@ -880,3 +889,450 @@ CMC_CREATE_UNIT(HashMap, true, { total_resize = 0; }); }); + +struct hashmap_fkey *hm_fkey_numhash = + &(struct hashmap_fkey){ .cmp = cmc_size_cmp, + .cpy = NULL, + .str = cmc_size_str, + .free = NULL, + .hash = numhash, + .pri = cmc_size_cmp }; + +CMC_CREATE_UNIT(HashMapIter, true, { + CMC_CREATE_TEST(PFX##_iter_start(), { + struct hashmap *map = hm_new(100, 0.6, hm_fkey_numhash, hm_fval); + + cmc_assert_not_equals(ptr, NULL, map); + + struct hashmap_iter it = hm_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(hm_iter_at_start(&it)); + cmc_assert(hm_iter_at_end(&it)); + + cmc_assert(hm_insert(map, 1, 1)); + cmc_assert(hm_insert(map, 2, 2)); + cmc_assert(hm_insert(map, 3, 3)); + + it = hm_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); + + hm_free(map); + }); + + CMC_CREATE_TEST(PFX##_iter_end(), { + struct hashmap *map = hm_new(100, 0.6, hm_fkey_numhash, hm_fval); + + cmc_assert_not_equals(ptr, NULL, map); + + struct hashmap_iter it = hm_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(hm_iter_at_start(&it)); + cmc_assert(hm_iter_at_end(&it)); + + cmc_assert(hm_insert(map, 1, 1)); + cmc_assert(hm_insert(map, 2, 2)); + cmc_assert(hm_insert(map, 3, 3)); + + it = hm_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); + + hm_free(map); + }); + + CMC_CREATE_TEST(PFX##_iter_at_start(), { + struct hashmap *map = hm_new(100, 0.6, hm_fkey, hm_fval); + + cmc_assert_not_equals(ptr, NULL, map); + + struct hashmap_iter it = hm_iter_start(map); + + // Empty checks + cmc_assert(hm_iter_at_start(&it)); + it = hm_iter_end(map); + cmc_assert(hm_iter_at_start(&it)); + + // Non-empty checks + cmc_assert(hm_insert(map, 1, 1)); + cmc_assert(hm_insert(map, 2, 2)); + it = hm_iter_end(map); + cmc_assert(!hm_iter_at_start(&it)); + it = hm_iter_start(map); + cmc_assert(hm_iter_at_start(&it)); + + hm_free(map); + }); + + CMC_CREATE_TEST(PFX##_iter_at_end(), { + struct hashmap *map = hm_new(100, 0.6, hm_fkey, hm_fval); + + cmc_assert_not_equals(ptr, NULL, map); + + struct hashmap_iter it = hm_iter_start(map); + + // Empty check + cmc_assert(hm_iter_at_end(&it)); + it = hm_iter_end(map); + cmc_assert(hm_iter_at_end(&it)); + + // Non-empty checks + cmc_assert(hm_insert(map, 1, 1)); + cmc_assert(hm_insert(map, 2, 2)); + it = hm_iter_end(map); + cmc_assert(hm_iter_at_end(&it)); + it = hm_iter_start(map); + cmc_assert(!hm_iter_at_end(&it)); + + hm_free(map); + }); + + CMC_CREATE_TEST(PFX##_iter_to_start(), { + struct hashmap *map = hm_new(100, 0.6, hm_fkey_numhash, hm_fval); + + cmc_assert_not_equals(ptr, NULL, map); + + struct hashmap_iter it = hm_iter_start(map); + + cmc_assert(!hm_iter_to_start(&it)); + + for (size_t i = 1; i <= 100; i++) + hm_insert(map, i, i); + + cmc_assert_equals(size_t, 100, map->count); + + it = hm_iter_end(map); + + cmc_assert(!hm_iter_at_start(&it)); + cmc_assert(hm_iter_at_end(&it)); + + cmc_assert_equals(size_t, 100, hm_iter_value(&it)); + + cmc_assert(hm_iter_to_start(&it)); + + cmc_assert(hm_iter_at_start(&it)); + cmc_assert(!hm_iter_at_end(&it)); + + cmc_assert_equals(size_t, 1, hm_iter_value(&it)); + + hm_free(map); + }); + + CMC_CREATE_TEST(PFX##_iter_to_end(), { + struct hashmap *map = hm_new(100, 0.6, hm_fkey_numhash, hm_fval); + + cmc_assert_not_equals(ptr, NULL, map); + + struct hashmap_iter it = hm_iter_end(map); + + cmc_assert(!hm_iter_to_end(&it)); + + for (size_t i = 1; i <= 100; i++) + hm_insert(map, i, i); + + it = hm_iter_start(map); + + cmc_assert(hm_iter_at_start(&it)); + cmc_assert(!hm_iter_at_end(&it)); + + cmc_assert_equals(size_t, 1, hm_iter_value(&it)); + + cmc_assert(hm_iter_to_end(&it)); + + cmc_assert(!hm_iter_at_start(&it)); + cmc_assert(hm_iter_at_end(&it)); + + cmc_assert_equals(size_t, 100, hm_iter_value(&it)); + + hm_free(map); + }); + + CMC_CREATE_TEST(PFX##_iter_next(), { + struct hashmap *map = hm_new(100, 0.6, hm_fkey, hm_fval); + + cmc_assert_not_equals(ptr, NULL, map); + + struct hashmap_iter it = hm_iter_start(map); + + cmc_assert(!hm_iter_next(&it)); + + for (size_t i = 1; i <= 1000; i++) + hm_insert(map, i, i); + + size_t sum = 0; + for (it = hm_iter_start(map); !hm_iter_at_end(&it); hm_iter_next(&it)) + { + sum += hm_iter_value(&it); + } + + cmc_assert_equals(size_t, 500500, sum); + + sum = 0; + + hm_iter_to_start(&it); + do + { + sum += hm_iter_value(&it); + } while (hm_iter_next(&it)); + + cmc_assert_equals(size_t, 500500, sum); + + hm_free(map); + }); + + CMC_CREATE_TEST(PFX##_iter_prev(), { + struct hashmap *map = hm_new(100, 0.6, hm_fkey, hm_fval); + + cmc_assert_not_equals(ptr, NULL, map); + + struct hashmap_iter it = hm_iter_end(map); + + cmc_assert(!hm_iter_prev(&it)); + + for (size_t i = 1; i <= 1000; i++) + hm_insert(map, i, i); + + size_t sum = 0; + for (it = hm_iter_end(map); !hm_iter_at_start(&it); hm_iter_prev(&it)) + { + sum += hm_iter_value(&it); + } + + cmc_assert_equals(size_t, 500500, sum); + + sum = 0; + + hm_iter_to_end(&it); + do + { + sum += hm_iter_value(&it); + } while (hm_iter_prev(&it)); + + cmc_assert_equals(size_t, 500500, sum); + + hm_free(map); + }); + + CMC_CREATE_TEST(PFX##_iter_advance(), { + struct hashmap *map = hm_new(100, 0.6, hm_fkey_numhash, hm_fval); + + cmc_assert_not_equals(ptr, NULL, map); + + struct hashmap_iter it = hm_iter_start(map); + + cmc_assert(!hm_iter_advance(&it, 1)); + + for (size_t i = 0; i <= 1000; i++) + hm_insert(map, i, i); + + it = hm_iter_start(map); + + cmc_assert(!hm_iter_advance(&it, 0)); + cmc_assert(!hm_iter_advance(&it, map->count)); + + size_t sum = 0; + for (it = hm_iter_start(map);;) + { + sum += hm_iter_value(&it); + + if (!hm_iter_advance(&it, 2)) + break; + } + + cmc_assert_equals(size_t, 250500, sum); + + hm_iter_to_start(&it); + cmc_assert(hm_iter_advance(&it, map->count - 1)); + + hm_free(map); + }); + + CMC_CREATE_TEST(PFX##_iter_rewind(), { + struct hashmap *map = hm_new(100, 0.6, hm_fkey_numhash, hm_fval); + + cmc_assert_not_equals(ptr, NULL, map); + + struct hashmap_iter it = hm_iter_end(map); + + cmc_assert(!hm_iter_rewind(&it, 1)); + + for (size_t i = 0; i <= 1000; i++) + hm_insert(map, i, i); + + it = hm_iter_end(map); + + cmc_assert(!hm_iter_rewind(&it, 0)); + cmc_assert(!hm_iter_rewind(&it, map->count)); + + size_t sum = 0; + for (it = hm_iter_end(map);;) + { + sum += hm_iter_value(&it); + + if (!hm_iter_rewind(&it, 2)) + break; + } + + cmc_assert_equals(size_t, 250500, sum); + + hm_iter_to_end(&it); + cmc_assert(hm_iter_rewind(&it, map->count - 1)); + + hm_free(map); + }); + + CMC_CREATE_TEST(PFX##_iter_go_to(), { + struct hashmap *map = hm_new(100, 0.6, hm_fkey_numhash, hm_fval); + + cmc_assert_not_equals(ptr, NULL, map); + + struct hashmap_iter it = hm_iter_end(map); + cmc_assert(!hm_iter_go_to(&it, 0)); + + it = hm_iter_start(map); + cmc_assert(!hm_iter_go_to(&it, 0)); + + for (size_t i = 0; i <= 1000; i++) + hm_insert(map, i, i); + + it = hm_iter_start(map); + + size_t sum = 0; + for (size_t i = 0; i < 1001; i++) + { + hm_iter_go_to(&it, i); + + sum += hm_iter_value(&it); + } + + cmc_assert_equals(size_t, 500500, sum); + + sum = 0; + for (size_t i = 1001; i > 0; i--) + { + cmc_assert(hm_iter_go_to(&it, i - 1)); + + sum += hm_iter_value(&it); + } + + cmc_assert_equals(size_t, 500500, sum); + + sum = 0; + for (size_t i = 0; i < 1001; i += 100) + { + cmc_assert(hm_iter_go_to(&it, i)); + cmc_assert_equals(size_t, i, hm_iter_index(&it)); + + sum += hm_iter_value(&it); + } + + cmc_assert_equals(size_t, 5500, sum); + + hm_free(map); + }); + + CMC_CREATE_TEST(PFX##_iter_key(), { + struct hashmap *map = hm_new(100, 0.6, hm_fkey, hm_fval); + + cmc_assert_not_equals(ptr, NULL, map); + + struct hashmap_iter it = hm_iter_end(map); + + cmc_assert_equals(size_t, (size_t){ 0 }, hm_iter_key(&it)); + + cmc_assert(hm_insert(map, 10, 10)); + + it = hm_iter_start(map); + + cmc_assert_equals(size_t, 10, hm_iter_key(&it)); + + hm_free(map); + }); + + CMC_CREATE_TEST(PFX##_iter_value(), { + struct hashmap *map = hm_new(100, 0.6, hm_fkey, hm_fval); + + cmc_assert_not_equals(ptr, NULL, map); + + struct hashmap_iter it = hm_iter_end(map); + + cmc_assert_equals(size_t, (size_t){ 0 }, hm_iter_value(&it)); + + cmc_assert(hm_insert(map, 10, 10)); + + it = hm_iter_start(map); + + cmc_assert_equals(size_t, 10, hm_iter_value(&it)); + + hm_free(map); + }); + + CMC_CREATE_TEST(PFX##_iter_rvalue(), { + struct hashmap *map = hm_new(100, 0.6, hm_fkey, hm_fval); + + cmc_assert_not_equals(ptr, NULL, map); + + struct hashmap_iter it = hm_iter_end(map); + + cmc_assert_equals(ptr, NULL, hm_iter_rvalue(&it)); + + cmc_assert(hm_insert(map, 10, 10)); + + it = hm_iter_start(map); + + cmc_assert_not_equals(ptr, NULL, hm_iter_rvalue(&it)); + cmc_assert_equals(size_t, 10, *hm_iter_rvalue(&it)); + + hm_free(map); + }); + + CMC_CREATE_TEST(PFX##_iter_index(), { + struct hashmap *map = hm_new(100, 0.6, hm_fkey, hm_fval); + + cmc_assert_not_equals(ptr, NULL, map); + + for (size_t i = 0; i <= 1000; i++) + hm_insert(map, i, i); + + struct hashmap_iter it = hm_iter_start(map); + + for (size_t i = 0; i < 1001; i++) + { + cmc_assert_equals(size_t, i, hm_iter_index(&it)); + hm_iter_next(&it); + } + + it = hm_iter_end(map); + for (size_t i = 1001; i > 0; i--) + { + cmc_assert_equals(size_t, i - 1, hm_iter_index(&it)); + hm_iter_prev(&it); + } + + hm_free(map); + }); +});