#include #include #include #include #include #include #define HASH_OFFSET_BASIS 0xcbf29ce484222325 #define HASH_PRIME 0x100000001b3 /*** PRIVATE DATA *************************************************************/ struct fx_hashmap_bucket_item { struct fx_queue_entry bi_entry; struct fx_hashmap_key bi_key; struct fx_hashmap_value bi_value; }; struct fx_hashmap_bucket { struct fx_bst_node bk_node; uint64_t bk_hash; struct fx_queue bk_items; }; struct fx_hashmap_p { size_t h_count; struct fx_bst h_buckets; fx_hashmap_key_destructor h_key_dtor; fx_hashmap_value_destructor h_value_dtor; }; struct fx_hashmap_iterator_p { size_t i; fx_hashmap_item item; fx_hashmap *_h; struct fx_hashmap_p *_h_p; fx_bst_node *_cbn; fx_queue_entry *_cqe; }; /*** PRIVATE FUNCTIONS ********************************************************/ static FX_BST_DEFINE_SIMPLE_GET( struct fx_hashmap_bucket, uint64_t, bk_node, bk_hash, get_bucket); static FX_BST_DEFINE_SIMPLE_INSERT( struct fx_hashmap_bucket, bk_node, bk_hash, put_bucket); static uint64_t hash_data(const void *p, size_t size) { const unsigned char *s = p; uint64_t hash = HASH_OFFSET_BASIS; for (size_t i = 0; s[i]; i++) { hash *= HASH_PRIME; hash ^= s[i]; } return hash; } static uint64_t hash_key(const struct fx_hashmap_key *key) { if (key->key_flags & FX_HASHMAP_KEY_F_INTVALUE) { return hash_data(&key->key_data, sizeof key->key_data); } else { return hash_data(key->key_data, key->key_size); } } static bool compare_key( const struct fx_hashmap_key *a, const struct fx_hashmap_key *b) { const void *a_data = NULL, *fx_data = NULL; size_t a_len = 0, fx_len = 0; if (a->key_flags & FX_HASHMAP_KEY_F_INTVALUE) { a_data = &a->key_data; a_len = sizeof a->key_data; } else { a_data = a->key_data; a_len = a->key_size; } if (b->key_flags & FX_HASHMAP_KEY_F_INTVALUE) { fx_data = &b->key_data; fx_len = sizeof b->key_data; } else { fx_data = b->key_data; fx_len = b->key_size; } if (a_len != fx_len) { return false; } size_t cmp_len = a_len; return memcmp(a_data, fx_data, cmp_len) == 0; } static bool get_next_node( struct fx_bst_node *cur_node, struct fx_queue_entry *cur_entry, struct fx_bst_node **out_next_node, struct fx_queue_entry **out_next_entry) { struct fx_hashmap_bucket *cur_bucket = fx_unbox(struct fx_hashmap_bucket, cur_node, bk_node); if (!cur_bucket) { return false; } struct fx_hashmap_bucket_item *cur_item = fx_unbox(struct fx_hashmap_bucket_item, cur_entry, bi_entry); if (!cur_item) { return false; } struct fx_bst_node *next_node = cur_node; struct fx_queue_entry *next_entry = fx_queue_next(cur_entry); if (!next_entry) { next_node = fx_bst_next(cur_node); if (!next_node) { return false; } struct fx_hashmap_bucket *next_bucket = fx_unbox(struct fx_hashmap_bucket, next_node, bk_node); if (!next_bucket) { return false; } next_entry = fx_queue_first(&next_bucket->bk_items); if (!next_entry) { return false; } } struct fx_hashmap_bucket_item *next_item = fx_unbox(struct fx_hashmap_bucket_item, next_entry, bi_entry); if (!next_item) { return false; } *out_next_node = next_node; *out_next_entry = next_entry; return true; } static struct fx_hashmap_bucket *create_bucket(void) { struct fx_hashmap_bucket *bucket = malloc(sizeof *bucket); if (!bucket) { return NULL; } memset(bucket, 0x0, sizeof *bucket); return bucket; } static struct fx_hashmap_bucket_item *create_bucket_item(void) { struct fx_hashmap_bucket_item *item = malloc(sizeof *item); if (!item) { return NULL; } memset(item, 0x0, sizeof *item); return item; } static fx_status hashmap_put( struct fx_hashmap_p *hashmap, const fx_hashmap_key *key, const fx_hashmap_value *value) { uint64_t hash = hash_key(key); struct fx_hashmap_bucket *bucket = get_bucket(&hashmap->h_buckets, hash); if (!bucket) { bucket = create_bucket(); if (!bucket) { return FX_ERR_NO_MEMORY; } bucket->bk_hash = hash; put_bucket(&hashmap->h_buckets, bucket); } struct fx_queue_entry *entry = fx_queue_first(&bucket->bk_items); while (entry) { struct fx_hashmap_bucket_item *item = fx_unbox(struct fx_hashmap_bucket_item, entry, bi_entry); if (compare_key(&item->bi_key, key)) { memcpy(&item->bi_value, value, sizeof *value); return FX_SUCCESS; } entry = fx_queue_next(entry); } struct fx_hashmap_bucket_item *item = create_bucket_item(); if (!item) { return FX_ERR_NO_MEMORY; } memcpy(&item->bi_key, key, sizeof *key); memcpy(&item->bi_value, value, sizeof *value); fx_queue_push_back(&bucket->bk_items, &item->bi_entry); hashmap->h_count++; return FX_SUCCESS; } static const struct fx_hashmap_value *hashmap_get( const struct fx_hashmap_p *hashmap, const struct fx_hashmap_key *key) { uint64_t hash = hash_key(key); struct fx_hashmap_bucket *bucket = get_bucket(&hashmap->h_buckets, hash); if (!bucket) { return NULL; } struct fx_queue_entry *entry = fx_queue_first(&bucket->bk_items); while (entry) { struct fx_hashmap_bucket_item *item = fx_unbox(struct fx_hashmap_bucket_item, entry, bi_entry); if (compare_key(&item->bi_key, key)) { return &item->bi_value; } entry = fx_queue_next(entry); } return NULL; } static bool hashmap_has_key( const struct fx_hashmap_p *hashmap, const fx_hashmap_key *key) { uint64_t hash = hash_key(key); struct fx_hashmap_bucket *bucket = get_bucket(&hashmap->h_buckets, hash); if (!bucket) { return false; } struct fx_queue_entry *entry = fx_queue_first(&bucket->bk_items); while (entry) { struct fx_hashmap_bucket_item *item = fx_unbox(struct fx_hashmap_bucket_item, entry, bi_entry); if (compare_key(&item->bi_key, key)) { return true; } entry = fx_queue_next(entry); } return false; } static size_t hashmap_get_size(const struct fx_hashmap_p *hashmap) { return hashmap->h_count; } static bool hashmap_is_empty(const struct fx_hashmap_p *hashmap) { fx_bst_node *first_node = fx_bst_first(&hashmap->h_buckets); struct fx_hashmap_bucket *first_bucket = fx_unbox(struct fx_hashmap_bucket, first_node, bk_node); if (!first_bucket) { return true; } fx_queue_entry *first_entry = fx_queue_first(&first_bucket->bk_items); struct fx_hashmap_bucket_item *first_item = fx_unbox(struct fx_hashmap_bucket_item, first_entry, bi_entry); if (!first_item) { return true; } return false; } static fx_status delete_item( struct fx_hashmap_p *hashmap, struct fx_hashmap_bucket *bucket, struct fx_hashmap_bucket_item *item) { fx_queue_delete(&bucket->bk_items, &item->bi_entry); if (hashmap->h_key_dtor) { hashmap->h_key_dtor((void *)item->bi_key.key_data); } if (hashmap->h_value_dtor) { hashmap->h_value_dtor((void *)item->bi_value.value_data); } free(item); if (fx_queue_empty(&bucket->bk_items)) { fx_bst_delete(&hashmap->h_buckets, &bucket->bk_node); free(bucket); } hashmap->h_count--; return FX_SUCCESS; } /*** PUBLIC FUNCTIONS *********************************************************/ fx_hashmap *fx_hashmap_create( fx_hashmap_key_destructor key_dtor, fx_hashmap_value_destructor value_dtor) { fx_hashmap *hashmap = fx_object_create(FX_TYPE_HASHMAP); if (!hashmap) { return NULL; } return hashmap; } fx_hashmap *fx_hashmap_create_with_items(const fx_hashmap_item *items) { fx_hashmap *hashmap = fx_hashmap_create(NULL, NULL); if (!hashmap) { return NULL; } struct fx_hashmap_p *p = fx_object_get_private(hashmap, FX_TYPE_HASHMAP); for (size_t i = 0; items[i].key.key_data && items[i].key.key_size; i++) { hashmap_put(p, &items[i].key, &items[i].value); } return hashmap; } fx_status fx_hashmap_put( fx_hashmap *hashmap, const fx_hashmap_key *key, const fx_hashmap_value *value) { FX_CLASS_DISPATCH_STATIC(FX_TYPE_HASHMAP, hashmap_put, hashmap, key, value); } const struct fx_hashmap_value *fx_hashmap_get( const fx_hashmap *hashmap, const struct fx_hashmap_key *key) { FX_CLASS_DISPATCH_STATIC(FX_TYPE_HASHMAP, hashmap_get, hashmap, key); } bool fx_hashmap_has_key(const fx_hashmap *hashmap, const fx_hashmap_key *key) { FX_CLASS_DISPATCH_STATIC(FX_TYPE_HASHMAP, hashmap_has_key, hashmap, key); } size_t fx_hashmap_get_size(const fx_hashmap *hashmap) { FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_HASHMAP, hashmap_get_size, hashmap); } bool fx_hashmap_is_empty(const fx_hashmap *hashmap) { FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_HASHMAP, hashmap_is_empty, hashmap); } fx_iterator *fx_hashmap_begin(fx_hashmap *hashmap) { fx_hashmap_iterator *it_obj = fx_object_create(FX_TYPE_HASHMAP_ITERATOR); struct fx_hashmap_iterator_p *it = fx_object_get_private(it_obj, FX_TYPE_HASHMAP_ITERATOR); it->_h = hashmap; it->_h_p = fx_object_get_private(hashmap, FX_TYPE_HASHMAP); it->i = 0; if (fx_hashmap_is_empty(hashmap)) { memset(&it->item, 0x0, sizeof it->item); fx_iterator_set_status(it_obj, FX_ERR_NO_DATA); return it_obj; } struct fx_bst_node *first_node = fx_bst_first(&it->_h_p->h_buckets); struct fx_hashmap_bucket *first_bucket = fx_unbox(struct fx_hashmap_bucket, first_node, bk_node); if (!first_bucket) { memset(&it->item, 0x0, sizeof it->item); fx_iterator_set_status(it_obj, FX_ERR_NO_DATA); return it_obj; } struct fx_queue_entry *first_entry = fx_queue_first(&first_bucket->bk_items); struct fx_hashmap_bucket_item *first_item = fx_unbox(struct fx_hashmap_bucket_item, first_entry, bi_entry); if (!first_item) { memset(&it->item, 0x0, sizeof it->item); fx_iterator_set_status(it_obj, FX_ERR_NO_DATA); return it_obj; } 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; return it_obj; } const fx_iterator *fx_hashmap_cbegin(const fx_hashmap *hashmap) { return fx_hashmap_begin((fx_hashmap *)hashmap); } /*** VIRTUAL FUNCTIONS ********************************************************/ static void hashmap_init(fx_object *obj, void *priv) { struct fx_hashmap_p *map = priv; } static void hashmap_fini(fx_object *obj, void *priv) { struct fx_hashmap_p *map = priv; struct fx_bst_node *node = fx_bst_first(&map->h_buckets); while (node) { struct fx_hashmap_bucket *b = fx_unbox(struct fx_hashmap_bucket, node, bk_node); struct fx_bst_node *next_node = fx_bst_next(node); fx_bst_delete(&map->h_buckets, node); struct fx_queue_entry *entry = fx_queue_first(&b->bk_items); while (entry) { struct fx_hashmap_bucket_item *item = fx_unbox( struct fx_hashmap_bucket_item, entry, bi_entry); struct fx_queue_entry *next_entry = fx_queue_next(entry); fx_queue_delete(&b->bk_items, entry); if (map->h_key_dtor) { map->h_key_dtor((void *)item->bi_key.key_data); } if (map->h_value_dtor) { map->h_value_dtor((void *)item->bi_value.value_data); } free(item); entry = next_entry; } free(b); node = next_node; } } /*** ITERATOR FUNCTIONS *******************************************************/ static enum fx_status iterator_move_next(const fx_iterator *obj) { struct fx_hashmap_iterator_p *it = fx_object_get_private(obj, FX_TYPE_HASHMAP_ITERATOR); struct fx_bst_node *next_node; struct fx_queue_entry *next_entry; if (!get_next_node(it->_cbn, it->_cqe, &next_node, &next_entry)) { memset(&it->item, 0x0, sizeof it->item); return FX_ERR_NO_DATA; } struct fx_hashmap_bucket_item *next_item = fx_unbox(struct fx_hashmap_bucket_item, next_entry, bi_entry); if (!next_item) { memset(&it->item, 0x0, sizeof it->item); return FX_ERR_NO_DATA; } it->i++; 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; return FX_SUCCESS; } static enum fx_status iterator_erase(fx_iterator *obj) { struct fx_hashmap_iterator_p *it = fx_object_get_private(obj, FX_TYPE_HASHMAP_ITERATOR); if ((it->item.key.key_data || it->item.value.value_data) && !(it->_cbn && it->_cqe)) { return FX_ERR_BAD_STATE; } if (!it->item.key.key_data || !it->_cqe) { return FX_ERR_NO_DATA; } struct fx_bst_node *next_node; struct fx_queue_entry *next_entry; if (!get_next_node(it->_cbn, it->_cqe, &next_node, &next_entry)) { memset(&it->item, 0x0, sizeof it->item); return FX_ERR_NO_DATA; } struct fx_hashmap_bucket *cur_bucket = fx_unbox(struct fx_hashmap_bucket, it->_cbn, bk_node); struct fx_hashmap_bucket_item *cur_item = fx_unbox(struct fx_hashmap_bucket_item, it->_cqe, bi_entry); struct fx_hashmap_bucket_item *next_item = fx_unbox(struct fx_hashmap_bucket_item, next_entry, bi_entry); fx_status status = delete_item(it->_h_p, cur_bucket, cur_item); if (FX_ERR(status)) { return status; } if (next_item) { 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 { memset(&it->item, 0x0, sizeof it->item); it->_cbn = NULL; it->_cqe = NULL; } return FX_SUCCESS; } static fx_iterator_value iterator_get_value(fx_iterator *obj) { struct fx_hashmap_iterator_p *it = fx_object_get_private(obj, FX_TYPE_HASHMAP_ITERATOR); return FX_ITERATOR_VALUE_PTR(&it->item); } static const fx_iterator_value iterator_get_cvalue(const fx_iterator *obj) { const struct fx_hashmap_iterator_p *it = fx_object_get_private(obj, FX_TYPE_HASHMAP_ITERATOR); return FX_ITERATOR_VALUE_CPTR(&it->item); } /*** CLASS DEFINITION *********************************************************/ // ---- fx_hashmap DEFINITION FX_TYPE_CLASS_DEFINITION_BEGIN(fx_hashmap) FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT) FX_INTERFACE_ENTRY(to_string) = NULL; FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT) FX_TYPE_CLASS_INTERFACE_BEGIN(fx_iterable, FX_TYPE_ITERABLE) FX_INTERFACE_ENTRY(it_begin) = fx_hashmap_begin; FX_INTERFACE_ENTRY(it_cbegin) = fx_hashmap_cbegin; FX_TYPE_CLASS_INTERFACE_END(fx_iterable, FX_TYPE_ITERABLE) FX_TYPE_CLASS_DEFINITION_END(fx_hashmap) FX_TYPE_DEFINITION_BEGIN(fx_hashmap) FX_TYPE_ID(0x7bf5bcd1, 0x1ff3, 0x4e43, 0xbed8, 0x7c74f28348bf); FX_TYPE_CLASS(fx_hashmap_class); FX_TYPE_IMPLEMENTS(FX_TYPE_ITERABLE); FX_TYPE_INSTANCE_PRIVATE(struct fx_hashmap_p); FX_TYPE_INSTANCE_INIT(hashmap_init); FX_TYPE_INSTANCE_FINI(hashmap_fini); FX_TYPE_DEFINITION_END(fx_hashmap) // ---- fx_hashmap_iterator DEFINITION FX_TYPE_CLASS_DEFINITION_BEGIN(fx_hashmap_iterator) FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT) FX_INTERFACE_ENTRY(to_string) = NULL; FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT) FX_TYPE_CLASS_INTERFACE_BEGIN(fx_iterator, FX_TYPE_ITERATOR) FX_INTERFACE_ENTRY(it_move_next) = iterator_move_next; FX_INTERFACE_ENTRY(it_erase) = iterator_erase; FX_INTERFACE_ENTRY(it_get_value) = iterator_get_value; FX_INTERFACE_ENTRY(it_get_cvalue) = iterator_get_cvalue; FX_TYPE_CLASS_INTERFACE_END(fx_iterator, FX_TYPE_ITERATOR) FX_TYPE_CLASS_DEFINITION_END(fx_hashmap_iterator) FX_TYPE_DEFINITION_BEGIN(fx_hashmap_iterator) FX_TYPE_ID(0xd9658456, 0xdd80, 0x419a, 0xb23a, 0xb513013e6431); FX_TYPE_EXTENDS(FX_TYPE_ITERATOR); FX_TYPE_CLASS(fx_hashmap_iterator_class); FX_TYPE_INSTANCE_PRIVATE(struct fx_hashmap_iterator_p); FX_TYPE_DEFINITION_END(fx_hashmap_iterator)