From 49a37d2e678115719b44c11751b161e74cf843a4 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 14 Jan 2017 12:25:10 +0100 Subject: [PATCH] Rework hashtable iterators; you can now delete items while iterating over them (only the current item, though). --- modules/src/data/hashtable.c | 81 +++++++++++++++++++++++++++++------- modules/src/data/hashtable.h | 5 +++ 2 files changed, 72 insertions(+), 14 deletions(-) diff --git a/modules/src/data/hashtable.c b/modules/src/data/hashtable.c index e39690870..1610347d0 100644 --- a/modules/src/data/hashtable.c +++ b/modules/src/data/hashtable.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "hashtable.h" struct hashnode @@ -208,29 +209,81 @@ void* hashtable_next(struct hashtable* ht, struct hashtable_iterator* it) lazy_init(ht); - while (!it->node) + if (!it->running) { - if (it->bucket == ht->num_buckets) - goto eof; + /* Find the first node and return it; the stored state in the iterator + * is invalid. */ + + while (it->bucket < ht->num_buckets) + { + it->node = ht->buckets[it->bucket]; + if (it->node) + goto found; + it->bucket++; + } + + /* hashtable is empty! */ + } + else + { + /* The iterator is running; the stored state in the iterator points at + * the current node, so find the next one. */ - it->node = ht->buckets[it->bucket]; + if (!it->advanced) + it->node = it->node->next; if (it->node) - break; + goto found; - it->bucket++; - } + for (;;) + { + it->bucket++; + if (it->bucket == ht->num_buckets) + break; - it->key = it->node->key; - it->value = it->node->value; - it->node = it->node->next; - if (!it->node) - it->bucket++; + it->node = ht->buckets[it->bucket]; + if (it->node) + goto found; + } - return it->value; + /* nothing left found! */ + } -eof: + /* EOF: reset the iterator. */ + + it->running = false; + it->advanced = false; it->key = it->value = NULL; it->bucket = 0; it->node = NULL; return NULL; + +found: + it->running = true; + it->advanced = false; + it->key = it->node->key; + it->value = it->node->value; + return it->value; +} + +void hashtable_delete_current(struct hashtable* ht, struct hashtable_iterator* it) +{ + struct hashnode** hnp; + + assert(ht); + assert(it->running); + + hnp = findnodep(ht, it->node->key); + it->node = it->node->next; + ht->freefunction(*hnp); + ht->size--; + *hnp = it->node; + + it->advanced = true; +} + +void hashtable_copy_all(struct hashtable* src, struct hashtable* dest) +{ + struct hashtable_iterator hit = {}; + while (hashtable_next(src, &hit)) + hashtable_put(dest, hit.key, hit.value); } diff --git a/modules/src/data/hashtable.h b/modules/src/data/hashtable.h index 20fb00b15..c158bba1a 100644 --- a/modules/src/data/hashtable.h +++ b/modules/src/data/hashtable.h @@ -35,6 +35,8 @@ struct hashtable_iterator void* value; /* Private */ + bool running; + bool advanced; int bucket; struct hashnode* node; }; @@ -48,5 +50,8 @@ extern void* hashtable_get(struct hashtable* ht, void* key); extern void* hashtable_remove(struct hashtable* ht, void* key); extern void* hashtable_pop(struct hashtable* ht); extern void* hashtable_next(struct hashtable* ht, struct hashtable_iterator* it); +extern void* hashtable_delete_and_next(struct hashtable* ht, struct hashtable_iterator* it); + +extern void hashtable_copy_all(struct hashtable* src, struct hashtable* dest); #endif -- 2.34.1