diff --git a/ds/hashmap.c b/ds/hashmap.c index f9d76a6..5da6739 100644 --- a/ds/hashmap.c +++ b/ds/hashmap.c @@ -23,11 +23,22 @@ struct b_hashmap_bucket { }; struct b_hashmap_p { + size_t h_count; struct b_btree h_buckets; b_hashmap_key_destructor h_key_dtor; b_hashmap_value_destructor h_value_dtor; }; +struct b_hashmap_iterator_p { + size_t i; + b_hashmap_item item; + + b_hashmap *_h; + struct b_hashmap_p *_h_p; + b_btree_node *_cbn; + b_queue_entry *_cqe; +}; + /*** PRIVATE FUNCTIONS ********************************************************/ static B_BTREE_DEFINE_SIMPLE_GET( @@ -174,15 +185,17 @@ static b_status hashmap_put( put_bucket(&hashmap->h_buckets, bucket); } - b_queue_iterator it; - b_queue_foreach (&it, &bucket->bk_items) { - struct b_hashmap_bucket_item *item = b_unbox( - struct b_hashmap_bucket_item, it.entry, bi_entry); + struct b_queue_entry *entry = b_queue_first(&bucket->bk_items); + while (entry) { + struct b_hashmap_bucket_item *item + = b_unbox(struct b_hashmap_bucket_item, entry, bi_entry); if (compare_key(&item->bi_key, key)) { memcpy(&item->bi_value, value, sizeof *value); return B_SUCCESS; } + + entry = b_queue_next(entry); } struct b_hashmap_bucket_item *item = create_bucket_item(); @@ -194,6 +207,7 @@ static b_status hashmap_put( memcpy(&item->bi_value, value, sizeof *value); b_queue_push_back(&bucket->bk_items, &item->bi_entry); + hashmap->h_count++; return B_SUCCESS; } @@ -208,14 +222,16 @@ static const struct b_hashmap_value *hashmap_get( return NULL; } - b_queue_iterator it; - b_queue_foreach (&it, &bucket->bk_items) { - struct b_hashmap_bucket_item *item = b_unbox( - struct b_hashmap_bucket_item, it.entry, bi_entry); + struct b_queue_entry *entry = b_queue_first(&bucket->bk_items); + while (entry) { + struct b_hashmap_bucket_item *item + = b_unbox(struct b_hashmap_bucket_item, entry, bi_entry); if (compare_key(&item->bi_key, key)) { return &item->bi_value; } + + entry = b_queue_next(entry); } return NULL; @@ -230,14 +246,16 @@ static bool hashmap_has_key( return false; } - b_queue_iterator it; - b_queue_foreach (&it, &bucket->bk_items) { - struct b_hashmap_bucket_item *item = b_unbox( - struct b_hashmap_bucket_item, it.entry, bi_entry); + struct b_queue_entry *entry = b_queue_first(&bucket->bk_items); + while (entry) { + struct b_hashmap_bucket_item *item + = b_unbox(struct b_hashmap_bucket_item, entry, bi_entry); if (compare_key(&item->bi_key, key)) { return true; } + + entry = b_queue_next(entry); } return false; @@ -245,19 +263,7 @@ static bool hashmap_has_key( static size_t hashmap_get_size(const struct b_hashmap_p *hashmap) { - size_t count = 0; - b_btree_iterator it1; - b_queue_iterator it2; - b_btree_foreach (&it1, &hashmap->h_buckets) { - struct b_hashmap_bucket *bucket - = b_unbox(struct b_hashmap_bucket, it1.node, bk_node); - - b_queue_foreach (&it2, &bucket->bk_items) { - count++; - } - } - - return count; + return hashmap->h_count; } static bool hashmap_is_empty(const struct b_hashmap_p *hashmap) @@ -300,6 +306,7 @@ static b_status delete_item( free(bucket); } + hashmap->h_count--; return B_SUCCESS; } @@ -370,19 +377,19 @@ static void hashmap_fini(b_object *obj, void *priv) { struct b_hashmap_p *map = priv; - b_btree_iterator it1; - b_btree_iterator_begin(&map->h_buckets, &it1); - while (b_btree_iterator_is_valid(&it1)) { + struct b_btree_node *node = b_btree_first(&map->h_buckets); + while (node) { struct b_hashmap_bucket *b - = b_unbox(struct b_hashmap_bucket, it1.node, bk_node); - b_btree_iterator_erase(&it1); + = b_unbox(struct b_hashmap_bucket, node, bk_node); + struct b_btree_node *next_node = b_btree_next(node); + b_btree_delete(&map->h_buckets, node); - b_queue_iterator it2; - b_queue_iterator_begin(&b->bk_items, &it2); - while (b_queue_iterator_is_valid(&it2)) { + struct b_queue_entry *entry = b_queue_first(&b->bk_items); + while (entry) { struct b_hashmap_bucket_item *item = b_unbox( - struct b_hashmap_bucket_item, it2.entry, bi_entry); - b_queue_iterator_erase(&it2); + struct b_hashmap_bucket_item, entry, bi_entry); + struct b_queue_entry *next_entry = b_queue_next(entry); + b_queue_delete(&b->bk_items, entry); if (map->h_key_dtor) { map->h_key_dtor((void *)item->bi_key.key_data); @@ -393,85 +400,52 @@ static void hashmap_fini(b_object *obj, void *priv) } free(item); + entry = next_entry; } free(b); + node = next_node; } } -/*** CLASS DEFINITION *********************************************************/ - -B_TYPE_CLASS_DEFINITION_BEGIN(b_hashmap) - B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT) - B_INTERFACE_ENTRY(to_string) = NULL; - B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT) -B_TYPE_CLASS_DEFINITION_END(b_hashmap) - -B_TYPE_DEFINITION_BEGIN(b_hashmap) - B_TYPE_ID(0x7bf5bcd1, 0x1ff3, 0x4e43, 0xbed8, 0x7c74f28348bf); - B_TYPE_CLASS(b_hashmap_class); - B_TYPE_INSTANCE_PRIVATE(struct b_hashmap_p); - B_TYPE_INSTANCE_INIT(hashmap_init); - B_TYPE_INSTANCE_FINI(hashmap_fini); -B_TYPE_DEFINITION_END(b_hashmap) - /*** ITERATOR FUNCTIONS *******************************************************/ -static bool hashmap_iterator_next(struct b_iterator *it) +static b_iterator *iterable_begin(b_hashmap *hashmap) { - return b_hashmap_iterator_next((struct b_hashmap_iterator *)it); -} + b_hashmap_iterator *it_obj = b_object_create(B_TYPE_HASHMAP_ITERATOR); + struct b_hashmap_iterator_p *it + = b_object_get_private(it_obj, B_TYPE_HASHMAP_ITERATOR); -static b_status hashmap_iterator_erase(struct b_iterator *it) -{ - return b_hashmap_iterator_erase((struct b_hashmap_iterator *)it); -} - -static bool hashmap_iterator_is_valid(const struct b_iterator *it) -{ - return b_hashmap_iterator_is_valid((struct b_hashmap_iterator *)it); -} - -static struct b_iterator_ops it_ops = { - .it_next = hashmap_iterator_next, - .it_erase = hashmap_iterator_erase, - .it_close = NULL, - .it_is_valid = hashmap_iterator_is_valid, -}; - -int b_hashmap_iterator_begin(b_hashmap *hashmap, struct b_hashmap_iterator *it) -{ it->_h = hashmap; it->_h_p = b_object_get_private(hashmap, B_TYPE_HASHMAP); - it->_base.it_ops = &it_ops; it->i = 0; if (b_hashmap_is_empty(hashmap)) { - it->key = NULL; - it->value = NULL; - return -1; + memset(&it->item, 0x0, sizeof it->item); + b_iterator_set_status(it_obj, B_ERR_NO_DATA); + return it_obj; } struct b_btree_node *first_node = b_btree_first(&it->_h_p->h_buckets); struct b_hashmap_bucket *first_bucket = b_unbox(struct b_hashmap_bucket, first_node, bk_node); if (!first_bucket) { - it->key = NULL; - it->value = NULL; - return -1; + memset(&it->item, 0x0, sizeof it->item); + b_iterator_set_status(it_obj, B_ERR_NO_DATA); + return it_obj; } struct b_queue_entry *first_entry = b_queue_first(&first_bucket->bk_items); struct b_hashmap_bucket_item *first_item = b_unbox(struct b_hashmap_bucket_item, first_entry, bi_entry); if (!first_item) { - it->key = NULL; - it->value = NULL; - return -1; + memset(&it->item, 0x0, sizeof it->item); + b_iterator_set_status(it_obj, B_ERR_NO_DATA); + return it_obj; } - it->key = &first_item->bi_key; - it->value = &first_item->bi_value; + memcpy(&it->item.key, &first_item->bi_key, sizeof it->item.key); + memcpy(&it->item.value, &first_item->bi_value, sizeof it->item.value); it->_cbn = first_node; it->_cqe = first_entry; @@ -479,28 +453,34 @@ int b_hashmap_iterator_begin(b_hashmap *hashmap, struct b_hashmap_iterator *it) return 0; } -bool b_hashmap_iterator_next(struct b_hashmap_iterator *it) +static const b_iterator *iterable_cbegin(const b_hashmap *hashmap) { + return iterable_begin((b_hashmap *)hashmap); +} + +static enum b_status iterator_move_next(const b_iterator *obj) +{ + struct b_hashmap_iterator_p *it + = b_object_get_private(obj, B_TYPE_HASHMAP_ITERATOR); + struct b_btree_node *next_node; struct b_queue_entry *next_entry; if (!get_next_node(it->_cbn, it->_cqe, &next_node, &next_entry)) { - it->key = NULL; - it->value = NULL; - return false; + memset(&it->item, 0x0, sizeof it->item); + return B_ERR_NO_DATA; } struct b_hashmap_bucket_item *next_item = b_unbox(struct b_hashmap_bucket_item, next_entry, bi_entry); if (!next_item) { - it->key = NULL; - it->value = NULL; - return false; + memset(&it->item, 0x0, sizeof it->item); + return B_ERR_NO_DATA; } it->i++; - it->key = &next_item->bi_key; - it->value = &next_item->bi_value; + memcpy(&it->item.key, &next_item->bi_key, sizeof it->item.key); + memcpy(&it->item.value, &next_item->bi_value, sizeof it->item.value); it->_cbn = next_node; it->_cqe = next_entry; @@ -508,22 +488,25 @@ bool b_hashmap_iterator_next(struct b_hashmap_iterator *it) return true; } -b_status b_hashmap_iterator_erase(struct b_hashmap_iterator *it) +static enum b_status iterator_erase(b_iterator *obj) { - if ((it->key || it->value) && !(it->_cbn && it->_cqe)) { + struct b_hashmap_iterator_p *it + = b_object_get_private(obj, B_TYPE_HASHMAP_ITERATOR); + + if ((it->item.key.key_data || it->item.value.value_data) + && !(it->_cbn && it->_cqe)) { return B_ERR_BAD_STATE; } - if (!it->key || !it->_cqe) { - return B_ERR_OUT_OF_BOUNDS; + if (!it->item.key.key_data || !it->_cqe) { + return B_ERR_NO_DATA; } struct b_btree_node *next_node; struct b_queue_entry *next_entry; if (!get_next_node(it->_cbn, it->_cqe, &next_node, &next_entry)) { - it->key = NULL; - it->value = NULL; - return false; + memset(&it->item, 0x0, sizeof it->item); + return B_ERR_NO_DATA; } struct b_hashmap_bucket *cur_bucket @@ -540,14 +523,14 @@ b_status b_hashmap_iterator_erase(struct b_hashmap_iterator *it) } if (next_item) { - it->key = &next_item->bi_key; - it->value = &next_item->bi_value; + memcpy(&it->item.key, &next_item->bi_key, sizeof it->item.key); + memcpy(&it->item.value, &next_item->bi_value, + sizeof it->item.value); it->_cbn = next_node; it->_cqe = next_entry; } else { - it->key = NULL; - it->value = NULL; + memset(&it->item, 0x0, sizeof it->item); it->_cbn = NULL; it->_cqe = NULL; @@ -556,7 +539,60 @@ b_status b_hashmap_iterator_erase(struct b_hashmap_iterator *it) return B_SUCCESS; } -bool b_hashmap_iterator_is_valid(const struct b_hashmap_iterator *it) +static b_iterator_value iterator_get_value(b_iterator *obj) { - return it->key != NULL; + struct b_hashmap_iterator_p *it + = b_object_get_private(obj, B_TYPE_HASHMAP_ITERATOR); + return B_ITERATOR_VALUE_PTR(&it->item); } + +static const b_iterator_value iterator_get_cvalue(const b_iterator *obj) +{ + const struct b_hashmap_iterator_p *it + = b_object_get_private(obj, B_TYPE_HASHMAP_ITERATOR); + return B_ITERATOR_VALUE_CPTR(&it->item); +} + +/*** CLASS DEFINITION *********************************************************/ + +// ---- b_hashmap DEFINITION +B_TYPE_CLASS_DEFINITION_BEGIN(b_hashmap) + B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT) + B_INTERFACE_ENTRY(to_string) = NULL; + B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT) + + B_TYPE_CLASS_INTERFACE_BEGIN(b_iterable, B_TYPE_ITERABLE) + B_INTERFACE_ENTRY(it_begin) = iterable_begin; + B_INTERFACE_ENTRY(it_cbegin) = iterable_cbegin; + B_TYPE_CLASS_INTERFACE_END(b_iterable, B_TYPE_ITERABLE) +B_TYPE_CLASS_DEFINITION_END(b_hashmap) + +B_TYPE_DEFINITION_BEGIN(b_hashmap) + B_TYPE_ID(0x7bf5bcd1, 0x1ff3, 0x4e43, 0xbed8, 0x7c74f28348bf); + B_TYPE_CLASS(b_hashmap_class); + B_TYPE_IMPLEMENTS(B_TYPE_ITERABLE); + B_TYPE_INSTANCE_PRIVATE(struct b_hashmap_p); + B_TYPE_INSTANCE_INIT(hashmap_init); + B_TYPE_INSTANCE_FINI(hashmap_fini); +B_TYPE_DEFINITION_END(b_hashmap) + +// ---- b_hashmap_iterator DEFINITION +B_TYPE_CLASS_DEFINITION_BEGIN(b_hashmap_iterator) + B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT) + B_INTERFACE_ENTRY(to_string) = NULL; + B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT) + + B_TYPE_CLASS_INTERFACE_BEGIN(b_iterator, B_TYPE_ITERATOR) + B_INTERFACE_ENTRY(it_move_next) = iterator_move_next; + B_INTERFACE_ENTRY(it_erase) = iterator_erase; + B_INTERFACE_ENTRY(it_get_value) = iterator_get_value; + B_INTERFACE_ENTRY(it_get_cvalue) = iterator_get_cvalue; + B_TYPE_CLASS_INTERFACE_END(b_iterator, B_TYPE_ITERATOR) +B_TYPE_CLASS_DEFINITION_END(b_hashmap_iterator) + +B_TYPE_DEFINITION_BEGIN(b_hashmap_iterator) + B_TYPE_ID(0xd9658456, 0xdd80, 0x419a, 0xb23a, 0xb513013e6431); + B_TYPE_EXTENDS(B_TYPE_ITERATOR); + B_TYPE_CLASS(b_hashmap_iterator_class); + B_TYPE_INSTANCE_PRIVATE(struct b_hashmap_iterator_p); +B_TYPE_DEFINITION_END(b_hashmap_iterator) diff --git a/ds/include/blue/ds/hashmap.h b/ds/include/blue/ds/hashmap.h index 52f651a..1603968 100644 --- a/ds/include/blue/ds/hashmap.h +++ b/ds/include/blue/ds/hashmap.h @@ -12,13 +12,18 @@ B_DECLS_BEGIN; struct b_hashmap_p; -#define B_TYPE_HASHMAP (b_hashmap_get_type()) +#define B_TYPE_HASHMAP (b_hashmap_get_type()) +#define B_TYPE_HASHMAP_ITERATOR (b_hashmap_iterator_get_type()) B_DECLARE_TYPE(b_hashmap); +B_DECLARE_TYPE(b_hashmap_iterator); B_TYPE_CLASS_DECLARATION_BEGIN(b_hashmap) B_TYPE_CLASS_DECLARATION_END(b_hashmap) +B_TYPE_CLASS_DECLARATION_BEGIN(b_hashmap_iterator) +B_TYPE_CLASS_DECLARATION_END(b_hashmap_iterator) + #define B_HASHMAP_KEY(k, ks) {.key_data = (k), .key_size = (ks)} #define B_HASHMAP_VALUE(v, vs) {.value_data = (v), .value_size = (vs)} @@ -54,19 +59,8 @@ typedef struct b_hashmap_item { b_hashmap_value value; } b_hashmap_item; -typedef struct b_hashmap_iterator { - b_iterator _base; - size_t i; - const b_hashmap_key *key; - const b_hashmap_value *value; - - b_hashmap *_h; - struct b_hashmap_p *_h_p; - b_btree_node *_cbn; - b_queue_entry *_cqe; -} b_hashmap_iterator; - BLUE_API b_type b_hashmap_get_type(void); +BLUE_API b_type b_hashmap_iterator_get_type(void); BLUE_API b_hashmap *b_hashmap_create( b_hashmap_key_destructor key_dtor, b_hashmap_value_destructor value_dtor); @@ -81,11 +75,6 @@ BLUE_API bool b_hashmap_has_key(const b_hashmap *hashmap, const b_hashmap_key *k BLUE_API size_t b_hashmap_get_size(const b_hashmap *hashmap); BLUE_API bool b_hashmap_is_empty(const b_hashmap *hashmap); -BLUE_API int b_hashmap_iterator_begin(b_hashmap *hashmap, b_hashmap_iterator *it); -BLUE_API bool b_hashmap_iterator_next(b_hashmap_iterator *it); -BLUE_API b_status b_hashmap_iterator_erase(b_hashmap_iterator *it); -BLUE_API bool b_hashmap_iterator_is_valid(const b_hashmap_iterator *it); - B_DECLS_END; #endif