diff --git a/examples/hashmap/README.md b/examples/hashmap/README.md index 0010373..835454d 100644 --- a/examples/hashmap/README.md +++ b/examples/hashmap/README.md @@ -1,3 +1,4 @@ # Hashmap examples * countries - Uses a hashmap to map the country name to its population +* iterator.c - A complete example of the hashmap iterator diff --git a/examples/hashmap/iterator.c b/examples/hashmap/iterator.c new file mode 100644 index 0000000..2520c6e --- /dev/null +++ b/examples/hashmap/iterator.c @@ -0,0 +1,230 @@ +/** + * iterator.c + * + * Creation Date: 14/05/2019 + * + * Authors: + * Leonardo Vencovsky (https://github.com/LeoVen) + * + * Iterator Example + */ +#include "hashmap.h" +#include +#include + +// Int hash function +size_t inthash(int t) +{ + size_t a = t; + a += ~(a << 15); + a ^= (a >> 10); + a += (a << 3); + a ^= (a >> 6); + a += ~(a << 11); + a ^= (a >> 16); + return a; +} + +// Int compare function +int intcmp(int a, int b) +{ + return a - b; +} + +// Creates a hashmap of integers +HASHMAP_GENERATE(hm, hashmap, /* FMOD */, int, double) + +int main(int argc, char const *argv[]) +{ + // Create a new hashmap with an initial capacity of 100 + hashmap *my_map = hm_new(100, 0.6, intcmp, inthash); + + // Add pairs to the hashmap + for (int i = 0; i < 20; i++) + { + // Map integers to doubles + hm_insert(my_map, i, (double)i / 10.0); + } + + // Iterate from the start (index 0) to the end (index count - 1) of the hashmap + for (hashmap_iter it = my_map->it_start(my_map); // Initialize iterator 'it' to the start of the hashmap + !hm_iter_end(&it); // Conditional stop (until it is not at the end) + hm_iter_next(&it)) // Iterator goes one position forward + { + // Access the current key + int k = hm_iter_key(&it); + + // Access the current value + double v = hm_iter_value(&it); + + // Access the current index (index is relative to all the pairs in the iteration) + size_t i = hm_iter_index(&it); + + // Print hashmap + + // Index is useful in situations like this + // If it is the first pair + if (i == 0) + printf("[ {%d:%.2lf}, ", k, v); + // If it is the last pair + else if (i == hm_count(my_map) - 1) + printf("{%d:%.2lf} ]\n", k, v); + // For pairs at the middle + else + printf("{%d:%.2lf}, ", k, v); + } + + // Index can also be used to iterate over a certain portion of a collection + size_t limit = hm_count(my_map) / 2; + for (hashmap_iter it = my_map->it_start(my_map); !hm_iter_end(&it); hm_iter_next(&it)) + { + // Access the current key + int k = hm_iter_key(&it); + + // Access the current value + double v = hm_iter_value(&it); + + // Access the current index (index is relative to all the pairs in the iteration) + size_t i = hm_iter_index(&it); + + // Print hashmap up until limit + + // If it is the first pair + if (i == 0) + printf("[ {%d:%.2lf}, ", k, v); + // If it is the last pair + else if (i == limit - 1) // -1 because index is 0 based and we want half of the hashmap + { + printf("{%d:%.2lf} ]\n", k, v); + break; + } + // For pairs at the middle + else + printf("{%d:%.2lf}, ", k, v); + } + + // Going backwards + for (hashmap_iter it = my_map->it_end(my_map); // Initialize iterator 'it' to the end of the hashmap + !hm_iter_start(&it); // Conditional stop (until it is not at the start) + hm_iter_prev(&it)) // Iterator goes one position backwards + { + // Access the current key + int k = hm_iter_key(&it); + + // Access the current value + double v = hm_iter_value(&it); + + // Access the current index (index is relative to all the pairs in the iteration) + size_t i = hm_iter_index(&it); + + // Print hashmap + // Note how the conditions for the first and last pairs are simply swapped + // Because iterating backwards make the first pair be the index count - 1 + // and the last one be the index 0 + + // If it is the first pair + if (i == hm_count(my_map) - 1) + printf("[ {%d:%.2lf}, ", k, v); + // If it is the last pair + else if (i == 0) + printf("{%d:%.2lf} ]\n", k, v); + // For pairs at the middle + else + printf("{%d:%.2lf}, ", k, v); + } + + // You can also use iterators in a while loop + // But to do so you must declare the iterator struct outside the loop first + hashmap_iter it; + + // You have three options: + // - Initialize it using the functions provided by the hashmap [ my_map->it_start() and my_map->it_end() ] + // - Initialize it using the init() function (when the iterator is already allocated) + // - Initialize it using the new() function (allocates on the heap, pointers only) + + it = my_map->it_start(my_map); + it = my_map->it_end(my_map); + + // This is equivalent to it_start() + hm_iter_init(&it, my_map); + + // For pointers + // Also equivalent to it_start() + hashmap_iter *iter = hm_iter_new(my_map); + + // The actual while loop + while (!hm_iter_end(iter)) + { + // Accessing pairs + int k = hm_iter_key(iter); + double v = hm_iter_value(iter); + size_t i = hm_iter_index(iter); + + // Print index and key value pair + printf("hashmap[%2" PRIuMAX "] = { %2d : %.2lf }\n", i, k, v); + + // Move iterator forwards + hm_iter_next(iter); + } + + // Send the iterator to the start of the hashmap + hm_iter_to_start(iter); + + // Send the iterator to the end of the hashmap + hm_iter_to_end(iter); + + // Backwards loop + while (!hm_iter_start(iter)) + { + // Accessing pairs + int k = hm_iter_key(iter); + double v = hm_iter_value(iter); + size_t i = hm_iter_index(iter); + + // Print index and the key value pair + printf("hashmap[%2" PRIuMAX "] = { %2d : %.2lf }\n", i, k, v); + + // Move iterator backwards + hm_iter_prev(iter); + } + + // Certain iterators also allow you to modify the contents it is iterating over + // Exceptions are collections that depend of the current state of the pair + // like tree-based collections and heap (collections that have some kind of ordering). + // You also can't change the keys of an associative collection + + // Change every value where its key is divisible by 3 to the number 7 + for (hm_iter_to_start(&it); !hm_iter_end(&it); hm_iter_next(&it)) + { + // Get current key + int k = hm_iter_key(&it); + + // Get a reference to the current value + double *v = hm_iter_rvalue(&it); + + if (k % 3 == 0) + *v = 7; + } + + // Now print it to see the difference + for (hashmap_iter it = my_map->it_start(my_map); !hm_iter_end(&it); hm_iter_next(&it)) + { + int k = hm_iter_key(&it); + double v = hm_iter_value(&it); + size_t i = hm_iter_index(&it); + + if (i == 0) + printf("[ {%d:%.2lf}, ", k, v); + else if (i == hm_count(my_map) - 1) + printf("{%d:%.2lf} ]\n", k, v); + else + printf("{%d:%.2lf}, ", k, v); + } + + // Dispose the iterator called by hm_iter_new() + hm_iter_free(iter); + // Dispose the hashmap created + hm_free(my_map); + + return 0; +} diff --git a/examples/iterators/hashmap.c b/examples/iterators/hashmap.c index b327d0f..86f855e 100644 --- a/examples/iterators/hashmap.c +++ b/examples/iterators/hashmap.c @@ -45,29 +45,32 @@ int main(int argc, char const *argv[]) hmap_iter iter; hm_iter_init(&iter, hm); - // Make the iterator go back and forward for (int j = 0; j < 4; j++) { - while (hm_iter_next(&iter, &k, &v, &i)) - printf("S[%2d] = { %2d : %2.2lf }\n", i, k, v); + while (!hm_iter_end(&iter)) + { + printf("C[%2d] = { %2d : %2.2lf }\n", hm_iter_index(&iter), hm_iter_key(&iter), hm_iter_value(&iter)); + hm_iter_next(&iter); + } printf("\n"); - while (hm_iter_prev(&iter, &k, &v, &i)) - printf("S[%2d] = { %2d : %2.2lf }\n", i, k, v); + while (!hm_iter_start(&iter)) + { + printf("C[%2d] = { %2d : %2.2lf }\n", hm_iter_index(&iter), hm_iter_key(&iter), hm_iter_value(&iter)); + hm_iter_prev(&iter); + } printf("\n\n"); } - for (hm_iter_tostart(&iter); !hm_iter_end(&iter); /**/) + for (hm_iter_to_start(&iter); !hm_iter_end(&iter); hm_iter_next(&iter)) { - hm_iter_next(&iter, &k, &v, &i); - printf("M[%2d] = { %2d : %2.2lf }\n", i, k, v); + printf("M[%2d] = { %2d : %2.2lf }\n", hm_iter_index(&iter), hm_iter_key(&iter), hm_iter_value(&iter)); } printf("\n"); - for (hm_iter_toend(&iter); !hm_iter_start(&iter); /**/) + for (hm_iter_to_end(&iter); !hm_iter_start(&iter); hm_iter_prev(&iter)) { - hm_iter_prev(&iter, &k, &v, &i); - printf("M[%2d] = { %2d : %2.2lf }\n", i, k, v); + printf("M[%2d] = { %2d : %2.2lf }\n", hm_iter_index(&iter), hm_iter_key(&iter), hm_iter_value(&iter)); } hm_free(hm); diff --git a/src/deque.h b/src/deque.h index 2a03d57..996e00d 100644 --- a/src/deque.h +++ b/src/deque.h @@ -42,6 +42,7 @@ /* HEADER ********************************************************************/ #define DEQUE_GENERATE_HEADER(PFX, SNAME, FMOD, V) \ \ + /* Deque Structure */ \ typedef struct SNAME##_s \ { \ /* Dynamic circular array of elements */ \ @@ -67,6 +68,7 @@ \ } SNAME, *SNAME##_ptr; \ \ + /* Deque Structure */ \ typedef struct SNAME##_iter_s \ { \ /* Target deque */ \ @@ -385,7 +387,7 @@ if (iter->end) \ return false; \ \ - iter->start = false; \ + iter->start = PFX##_empty(iter->target); \ \ if (iter->index == iter->target->count - 1) \ iter->end = true; \ @@ -403,7 +405,7 @@ if (iter->start) \ return false; \ \ - iter->end = false; \ + iter->end = PFX##_empty(iter->target); \ \ if (iter->index == 0) \ iter->start = true; \ diff --git a/src/hashmap.h b/src/hashmap.h index fe0c6af..375fcb4 100644 --- a/src/hashmap.h +++ b/src/hashmap.h @@ -81,82 +81,139 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, #define HASHMAP_GENERATE_SOURCE_PUBLIC(PFX, SNAME, FMOD, K, V) \ HASHMAP_GENERATE_SOURCE(PFX, SNAME, FMOD, K, V) /* STRUCT ********************************************************************/ -#define HASHMAP_GENERATE_STRUCT(PFX, SNAME, FMOD, K, V) \ - \ - struct SNAME##_s \ - { \ - struct SNAME##_entry_s *buffer; \ - size_t capacity; \ - size_t count; \ - double load; \ - int (*cmp)(K, K); \ - size_t (*hash)(K); \ - }; \ - \ - struct SNAME##_entry_s \ - { \ - K key; \ - V value; \ - size_t dist; \ - enum EntryState_e state; \ - }; \ - \ - struct SNAME##_iter_s \ - { \ - struct SNAME##_s *target; \ - size_t cursor; \ - size_t index; \ - size_t first; \ - size_t last; \ - bool start; \ - bool end; \ - }; \ - \ +#define HASHMAP_GENERATE_STRUCT(PFX, SNAME, FMOD, K, V) + /* HEADER ********************************************************************/ #define HASHMAP_GENERATE_HEADER(PFX, SNAME, FMOD, K, V) \ \ - typedef struct SNAME##_s SNAME; \ - typedef struct SNAME##_entry_s SNAME##_entry; \ - typedef struct SNAME##_iter_s SNAME##_iter; \ + /* Hashmap Structure */ \ + typedef struct SNAME##_s \ + { \ + /* Array of buckets */ \ + struct SNAME##_entry_s *buffer; \ \ + /* Current array capacity */ \ + size_t capacity; \ + \ + /* Current amount of keys */ \ + size_t count; \ + \ + /* Load factor in range (0.0, 1.0) */ \ + double load; \ + \ + /* Key comparison function */ \ + int (*cmp)(K, K); \ + \ + /* Key hash function */ \ + size_t (*hash)(K); \ + \ + /* Function that returns an iterator to the start of the hashmap */ \ + struct SNAME##_iter_s (*it_start)(struct SNAME##_s *); \ + \ + /* Function that returns an iterator to the end of the hashmap */ \ + struct SNAME##_iter_s (*it_end)(struct SNAME##_s *); \ + \ + } SNAME, *SNAME##_ptr; \ + \ + /* Hashmap Entry */ \ + typedef struct SNAME##_entry_s \ + { \ + /* Key */ \ + K key; \ + \ + /* Value */ \ + V value; \ + \ + /* The distance of this node to its original position, used by robin-hood hashing */ \ + size_t dist; \ + \ + /* The sate of this node (DELETED, EMPTY, FILLED) */ \ + enum EntryState_e state; \ + \ + } SNAME##_entry, *SNAME##_entry_ptr; \ + \ + /* Hashmap Iterator */ \ + typedef struct SNAME##_iter_s \ + { \ + /* Target hashmap */ \ + struct SNAME##_s *target; \ + \ + /* Cursor's position (index) */ \ + size_t cursor; \ + \ + /* Keeps track of relative index to the iteration of elements */ \ + size_t index; \ + \ + /* The index of the first element */ \ + size_t first; \ + \ + /* The index of the last element */ \ + size_t last; \ + \ + /* If the iterator has reached the start of the iteration */ \ + bool start; \ + \ + /* If the iterator has reached the end of the iteration */ \ + bool end; \ + \ + } SNAME##_iter, *SNAME##_iter_ptr; \ + \ + /* Collection Functions */ \ + /* Collection Allocation and Deallocation */ \ FMOD SNAME *PFX##_new(size_t size, double load, int (*compare)(K, K), size_t (*hash)(K)); \ FMOD void PFX##_clear(SNAME *_map_); \ FMOD void PFX##_free(SNAME *_map_); \ + /* Collection Input and Output */ \ FMOD bool PFX##_insert(SNAME *_map_, K key, V value); \ FMOD bool PFX##_remove(SNAME *_map_, K key, V *value); \ + /* Conditional Input and Output */ \ FMOD bool PFX##_insert_if(SNAME *_map_, K key, V value, bool condition); \ FMOD bool PFX##_remove_if(SNAME *_map_, K key, V *value, bool condition); \ + /* Element Access */ \ FMOD bool PFX##_max(SNAME *_map_, K *key, V *value); \ FMOD bool PFX##_min(SNAME *_map_, K *key, V *value); \ - FMOD bool PFX##_contains(SNAME *_map_, K key); \ FMOD V PFX##_get(SNAME *_map_, K key); \ FMOD V *PFX##_get_ref(SNAME *_map_, K key); \ + /* Collection State */ \ + FMOD bool PFX##_contains(SNAME *_map_, K key); \ FMOD bool PFX##_empty(SNAME *_map_); \ FMOD size_t PFX##_count(SNAME *_map_); \ \ + /* Iterator Functions */ \ + /* Iterator Allocation and Deallocation */ \ FMOD SNAME##_iter *PFX##_iter_new(SNAME *target); \ FMOD void PFX##_iter_free(SNAME##_iter *iter); \ + /* Iterator Initialization */ \ FMOD void PFX##_iter_init(SNAME##_iter *iter, SNAME *target); \ + /* Iterator State */ \ FMOD bool PFX##_iter_start(SNAME##_iter *iter); \ FMOD bool PFX##_iter_end(SNAME##_iter *iter); \ + /* Iterator Movement */ \ FMOD void PFX##_iter_tostart(SNAME##_iter *iter); \ FMOD void PFX##_iter_toend(SNAME##_iter *iter); \ - FMOD bool PFX##_iter_next(SNAME##_iter *iter, K *key, V *value, size_t *index); \ - FMOD bool PFX##_iter_prev(SNAME##_iter *iter, K *key, V *value, size_t *index); \ + FMOD bool PFX##_iter_next(SNAME##_iter *iter); \ + FMOD bool PFX##_iter_prev(SNAME##_iter *iter); \ + /* Iterator Access */ \ + FMOD K PFX##_iter_key(SNAME##_iter *iter); \ + FMOD V PFX##_iter_value(SNAME##_iter *iter); \ + FMOD V *PFX##_iter_rvalue(SNAME##_iter *iter); \ + FMOD size_t PFX##_iter_index(SNAME##_iter *iter); \ \ /* SOURCE ********************************************************************/ #define HASHMAP_GENERATE_SOURCE(PFX, SNAME, FMOD, K, V) \ \ - FMOD bool PFX##_grow(SNAME *_map_); \ - FMOD SNAME##_entry *PFX##_get_entry(SNAME *_map_, K key); \ - FMOD size_t PFX##_calculate_size(size_t required); \ + FMOD bool PFX##_impl_grow(SNAME *_map_); \ + FMOD SNAME##_entry *PFX##_impl_get_entry(SNAME *_map_, K key); \ + FMOD size_t PFX##_impl_calculate_size(size_t required); \ + SNAME##_iter PFX##_impl_it_start(SNAME *_map_); \ + SNAME##_iter PFX##_impl_it_end(SNAME *_map_); \ \ FMOD SNAME *PFX##_new(size_t size, double load, int (*compare)(K, K), size_t (*hash)(K)) \ { \ if (size == 0 || load <= 0 || load >= 1) \ return NULL; \ \ - size_t real_size = PFX##_calculate_size(size); \ + size_t real_size = PFX##_impl_calculate_size(size); \ \ SNAME *_map_ = malloc(sizeof(SNAME)); \ \ @@ -179,6 +236,9 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, _map_->cmp = compare; \ _map_->hash = hash; \ \ + _map_->it_start = PFX##_impl_it_start; \ + _map_->it_end = PFX##_impl_it_end; \ + \ return _map_; \ } \ \ @@ -199,7 +259,7 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, { \ if ((double)_map_->capacity * _map_->load <= (double)_map_->count) \ { \ - if (!PFX##_grow(_map_)) \ + if (!PFX##_impl_grow(_map_)) \ return false; \ } \ \ @@ -209,7 +269,7 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, \ SNAME##_entry *target = &(_map_->buffer[pos]); \ \ - if (PFX##_get_entry(_map_, key) != NULL) \ + if (PFX##_impl_get_entry(_map_, key) != NULL) \ return false; \ \ if (target->state == ES_EMPTY || target->state == ES_DELETED) \ @@ -259,7 +319,7 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, \ FMOD bool PFX##_remove(SNAME *_map_, K key, V *value) \ { \ - SNAME##_entry *result = PFX##_get_entry(_map_, key); \ + SNAME##_entry *result = PFX##_impl_get_entry(_map_, key); \ \ if (result == NULL) \ return false; \ @@ -297,14 +357,13 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, return false; \ \ SNAME##_iter iter; \ - K result_key; \ K max_key; \ - V result_value; \ - size_t index; \ \ - for (PFX##_iter_init(&iter, _map_); !PFX##_iter_end(&iter);) \ + for (PFX##_iter_init(&iter, _map_); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \ { \ - PFX##_iter_next(&iter, &result_key, &result_value, &index); \ + K result_key = PFX##_iter_key(&iter); \ + V result_value = PFX##_iter_value(&iter); \ + size_t index = PFX##_iter_index(&iter); \ \ if (index == 0) \ { \ @@ -315,7 +374,7 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, else if (_map_->cmp(result_key, max_key) > 0) \ { \ max_key = result_key; \ - *key = result_key; \ + *key = max_key; \ *value = result_value; \ } \ } \ @@ -329,14 +388,13 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, return false; \ \ SNAME##_iter iter; \ - K result_key; \ K min_key; \ - V result_value; \ - size_t index; \ \ - for (PFX##_iter_init(&iter, _map_); !PFX##_iter_end(&iter);) \ + for (PFX##_iter_init(&iter, _map_); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \ { \ - PFX##_iter_next(&iter, &result_key, &result_value, &index); \ + K result_key = PFX##_iter_key(&iter); \ + V result_value = PFX##_iter_value(&iter); \ + size_t index = PFX##_iter_index(&iter); \ \ if (index == 0) \ { \ @@ -355,14 +413,9 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, return true; \ } \ \ - FMOD bool PFX##_contains(SNAME *_map_, K key) \ - { \ - return PFX##_get_entry(_map_, key) != NULL; \ - } \ - \ FMOD V PFX##_get(SNAME *_map_, K key) \ { \ - SNAME##_entry *entry = PFX##_get_entry(_map_, key); \ + SNAME##_entry *entry = PFX##_impl_get_entry(_map_, key); \ \ if (!entry) \ return 0; \ @@ -372,7 +425,7 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, \ FMOD V *PFX##_get_ref(SNAME *_map_, K key) \ { \ - SNAME##_entry *entry = PFX##_get_entry(_map_, key); \ + SNAME##_entry *entry = PFX##_impl_get_entry(_map_, key); \ \ if (!entry) \ return NULL; \ @@ -380,6 +433,11 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, return &(entry->value); \ } \ \ + FMOD bool PFX##_contains(SNAME *_map_, K key) \ + { \ + return PFX##_impl_get_entry(_map_, key) != NULL; \ + } \ + \ FMOD bool PFX##_empty(SNAME *_map_) \ { \ return _map_->count == 0; \ @@ -449,7 +507,7 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, return PFX##_empty(iter->target) || iter->end; \ } \ \ - FMOD void PFX##_iter_tostart(SNAME##_iter *iter) \ + FMOD void PFX##_iter_to_start(SNAME##_iter *iter) \ { \ iter->cursor = iter->first; \ iter->index = 0; \ @@ -457,7 +515,7 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, iter->end = PFX##_empty(iter->target); \ } \ \ - FMOD void PFX##_iter_toend(SNAME##_iter *iter) \ + FMOD void PFX##_iter_to_end(SNAME##_iter *iter) \ { \ iter->cursor = iter->last; \ iter->index = iter->target->count - 1; \ @@ -465,31 +523,29 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, iter->end = true; \ } \ \ - FMOD bool PFX##_iter_next(SNAME##_iter *iter, K *key, V *value, size_t *index) \ + FMOD bool PFX##_iter_next(SNAME##_iter *iter) \ { \ if (iter->end) \ return false; \ \ SNAME##_entry *scan = &(iter->target->buffer[iter->cursor]); \ \ - *key = scan->key; \ - *value = scan->value; \ - *index = iter->index; \ - \ if (iter->cursor == iter->last) \ - iter->end = true; \ - else \ { \ - iter->index++; \ + iter->end = true; \ \ - while (1) \ - { \ - iter->cursor++; \ - scan = &(iter->target->buffer[iter->cursor]); \ + return false; \ + } \ \ - if (scan->state == ES_FILLED) \ - break; \ - } \ + iter->index++; \ + \ + while (1) \ + { \ + iter->cursor++; \ + scan = &(iter->target->buffer[iter->cursor]); \ + \ + if (scan->state == ES_FILLED) \ + break; \ } \ \ iter->start = PFX##_empty(iter->target); \ @@ -497,31 +553,29 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, return true; \ } \ \ - FMOD bool PFX##_iter_prev(SNAME##_iter *iter, K *key, V *value, size_t *index) \ + FMOD bool PFX##_iter_prev(SNAME##_iter *iter) \ { \ if (iter->start) \ return false; \ \ SNAME##_entry *scan = &(iter->target->buffer[iter->cursor]); \ \ - *key = scan->key; \ - *value = scan->value; \ - *index = iter->index; \ - \ if (iter->cursor == iter->first) \ - iter->start = true; \ - else \ { \ - iter->index--; \ + iter->start = true; \ \ - while (1) \ - { \ - iter->cursor--; \ - scan = &(iter->target->buffer[iter->cursor]); \ + return false; \ + } \ \ - if (scan->state == ES_FILLED) \ - break; \ - } \ + iter->index--; \ + \ + while (1) \ + { \ + iter->cursor--; \ + scan = &(iter->target->buffer[iter->cursor]); \ + \ + if (scan->state == ES_FILLED) \ + break; \ } \ \ iter->end = PFX##_empty(iter->target); \ @@ -529,23 +583,42 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, return true; \ } \ \ - FMOD bool PFX##_grow(SNAME *_map_) \ + FMOD K PFX##_iter_key(SNAME##_iter *iter) \ { \ - size_t new_size = PFX##_calculate_size(_map_->capacity + _map_->capacity / 2); \ + return iter->target->buffer[iter->cursor].key; \ + } \ + \ + FMOD V PFX##_iter_value(SNAME##_iter *iter) \ + { \ + return iter->target->buffer[iter->cursor].value; \ + } \ + \ + FMOD V *PFX##_iter_rvalue(SNAME##_iter *iter) \ + { \ + return &(iter->target->buffer[iter->cursor].value); \ + } \ + \ + FMOD size_t PFX##_iter_index(SNAME##_iter *iter) \ + { \ + return iter->index; \ + } \ + \ + FMOD bool PFX##_impl_grow(SNAME *_map_) \ + { \ + size_t new_size = PFX##_impl_calculate_size(_map_->capacity + _map_->capacity / 2); \ \ SNAME *_new_map_ = PFX##_new(new_size, _map_->load, _map_->cmp, _map_->hash); \ \ if (!_new_map_) \ return false; \ \ - K key; \ - V value; \ - size_t index; \ SNAME##_iter iter; \ \ - for (PFX##_iter_init(&iter, _map_); !PFX##_iter_end(&iter);) \ + for (PFX##_iter_init(&iter, _map_); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \ { \ - PFX##_iter_next(&iter, &key, &value, &index); \ + K key = PFX##_iter_key(&iter); \ + V value = PFX##_iter_value(&iter); \ + \ PFX##_insert(_new_map_, key, value); \ } \ \ @@ -566,7 +639,7 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, return true; \ } \ \ - FMOD SNAME##_entry *PFX##_get_entry(SNAME *_map_, K key) \ + FMOD SNAME##_entry *PFX##_impl_get_entry(SNAME *_map_, K key) \ { \ size_t hash = _map_->hash(key); \ size_t pos = hash % _map_->capacity; \ @@ -585,7 +658,7 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, return NULL; \ } \ \ - FMOD size_t PFX##_calculate_size(size_t required) \ + FMOD size_t PFX##_impl_calculate_size(size_t required) \ { \ const size_t count = sizeof(cmc_hashtable_primes) / sizeof(cmc_hashtable_primes[0]); \ \ @@ -597,6 +670,25 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, i++; \ \ return cmc_hashtable_primes[i]; \ + } \ + \ + SNAME##_iter PFX##_impl_it_start(SNAME *_map_) \ + { \ + SNAME##_iter iter; \ + \ + PFX##_iter_init(&iter, _map_); \ + \ + return iter; \ + } \ + \ + 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_HASHMAP_H */ diff --git a/src/list.h b/src/list.h index 27e4b47..5b83cec 100644 --- a/src/list.h +++ b/src/list.h @@ -42,9 +42,10 @@ /* HEADER ********************************************************************/ #define LIST_GENERATE_HEADER(PFX, SNAME, FMOD, V) \ \ + /* List Structure */ \ typedef struct SNAME##_s \ { \ - /* Dynamic array of elements*/ \ + /* Dynamic array of elements */ \ V *buffer; \ \ /* Current array capacity */ \ @@ -61,12 +62,13 @@ \ } SNAME, *SNAME##_ptr; \ \ + /* List Iterator */ \ typedef struct SNAME##_iter_s \ { \ /* Target list */ \ struct SNAME##_s *target; \ \ - /* Cursor's position */ \ + /* Cursor's position (index) */ \ size_t cursor; \ \ /* If the iterator has reached the start of the iteration */ \ @@ -575,7 +577,7 @@ if (iter->end) \ return false; \ \ - iter->start = false; \ + iter->start = PFX##_empty(iter->target); \ \ if (iter->cursor == iter->target->count - 1) \ iter->end = true; \ @@ -590,7 +592,7 @@ if (iter->start) \ return false; \ \ - iter->end = false; \ + iter->end = PFX##_empty(iter->target); \ \ if (iter->cursor == 0) \ iter->start = true; \