diff --git a/include/ucore/htable.h b/include/ucore/htable.h index 3ae18f6..3fea240 100644 --- a/include/ucore/htable.h +++ b/include/ucore/htable.h @@ -39,6 +39,15 @@ struct UHTable { struct UHNode **buckets; }; +/** Iterator for the iterator API */ +struct UHIter { + //internal fields + struct UHNode **it; + struct UHNode **next; + size_t cur_bucket; + size_t cur_hash; +}; + /** * Initialize a hash table. * @param table hash table to initialize @@ -246,4 +255,32 @@ void uc_htable_remove(struct UHTable *table, struct UHNode *node); int uc_htable_resize(struct UHTable *table, size_t buckets); +/** Get the first node with the given hash. + * + * @param table table + * @param iter opaque iterator + * @param hash hash to find + * @return the first node found or NULL + */ +struct UHNode *uc_htable_iter_first_hash(struct UHTable *table, + struct UHIter *iter, size_t hash); +/** Get the next node with the given hash, the iterator + * must previously have been passed to uc_htable_iter_first_hash + * which returned a non-NULL value + * + * @param iter opaque iterator + * @return the next node found or NULL + */ +struct UHNode *uc_htable_iter_next_hash(struct UHIter *iter); + +/** Remove the node pointed to by the current iterator, + * uc_htable_iter_first_hash or uc_htable_iter_next_hash + * must previously have returned non-NULL. The node + * returned by the previous call is the one removed. + * It is safe to continue iterating after this + * + * @param iter indicated node to remove + */ +void uc_htable_iter_remove(struct UHIter *iter); + #endif diff --git a/src/htable.c b/src/htable.c index 02fc876..839d50f 100644 --- a/src/htable.c +++ b/src/htable.c @@ -171,3 +171,47 @@ int uc_htable_resize(struct UHTable *table, size_t buckets) } +struct UHNode *uc_htable_iter_first_hash(struct UHTable *table, + struct UHIter *iter, size_t hash) +{ + size_t bucket = uc_htable_bucket(table, hash); + struct UHNode **it= &table->buckets[bucket]; + + while (*it) { + if ((*it)->hash == hash) { + iter->it = it; + iter->cur_bucket = bucket; + iter->cur_hash = (*it)->hash; + iter->next = &(*it)->next; + return *it; + } + + it = &(*it)->next; + } + + return NULL; +} + +struct UHNode *uc_htable_iter_next_hash(struct UHIter *iter) +{ + struct UHNode **it = iter->next; + + while (*it) { + if ((*it)->hash == iter->cur_hash) { + iter->it = it; + iter->next = &(*it)->next; + return *it; + } + it = &(*it)->next; + } + + return NULL; +} + +void uc_htable_iter_remove(struct UHIter *iter) +{ + if (*iter->it) { + *iter->it = *iter->next; + iter->it = NULL; + } +}