diff --git a/object/hashmap.c b/object/hashmap.c index 7f50283..4017f20 100644 --- a/object/hashmap.c +++ b/object/hashmap.c @@ -38,6 +38,45 @@ static uint64_t hash_data(const void *p, size_t size) return hash; } +static uint64_t hash_key(const struct b_hashmap_key *key) +{ + if (key->key_flags & B_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 b_hashmap_key *a, const struct b_hashmap_key *b) +{ + const void *a_data = NULL, *b_data = NULL; + size_t a_len = 0, b_len = 0; + + if (a->key_flags & B_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 & B_HASHMAP_KEY_F_INTVALUE) { + b_data = &b->key_data; + b_len = sizeof b->key_data; + } else { + b_data = b->key_data; + b_len = b->key_size; + } + + if (a_len != b_len) { + return false; + } + + size_t cmp_len = a_len; + return memcmp(a_data, b_data, cmp_len) == 0; +} + static void hashmap_release(struct b_object *obj); static struct b_object_type hashmap_type = { @@ -101,7 +140,7 @@ b_status b_hashmap_put( struct b_hashmap *hashmap, const b_hashmap_key *key, const b_hashmap_value *value) { - uint64_t hash = hash_data(key->key_data, key->key_size); + uint64_t hash = hash_key(key); struct b_hashmap_bucket *bucket = get_bucket(&hashmap->h_buckets, hash); if (!bucket) { @@ -119,12 +158,9 @@ b_status b_hashmap_put( struct b_hashmap_bucket_item *item = b_unbox( struct b_hashmap_bucket_item, it.entry, bi_entry); - if (item->bi_key.key_size != key->key_size) { - continue; - } - - if (!memcmp(item->bi_key.key_data, key->key_data, key->key_size)) { - return B_ERR_NAME_EXISTS; + if (compare_key(&item->bi_key, key)) { + memcpy(&item->bi_value, value, sizeof *value); + return B_SUCCESS; } } @@ -144,7 +180,8 @@ b_status b_hashmap_put( const struct b_hashmap_value *b_hashmap_get( const struct b_hashmap *hashmap, const struct b_hashmap_key *key) { - uint64_t hash = hash_data(key->key_data, key->key_size); + uint64_t hash = hash_key(key); + struct b_hashmap_bucket *bucket = get_bucket(&hashmap->h_buckets, hash); if (!bucket) { return NULL; @@ -155,11 +192,7 @@ const struct b_hashmap_value *b_hashmap_get( struct b_hashmap_bucket_item *item = b_unbox( struct b_hashmap_bucket_item, it.entry, bi_entry); - if (item->bi_key.key_size != key->key_size) { - continue; - } - - if (!memcmp(item->bi_key.key_data, key->key_data, key->key_size)) { + if (compare_key(&item->bi_key, key)) { return &item->bi_value; } } @@ -169,7 +202,7 @@ const struct b_hashmap_value *b_hashmap_get( bool b_hashmap_has_key(const struct b_hashmap *hashmap, const b_hashmap_key *key) { - uint64_t hash = hash_data(key->key_data, key->key_size); + uint64_t hash = hash_key(key); struct b_hashmap_bucket *bucket = get_bucket(&hashmap->h_buckets, hash); if (!bucket) { return false; @@ -180,11 +213,7 @@ bool b_hashmap_has_key(const struct b_hashmap *hashmap, const b_hashmap_key *key struct b_hashmap_bucket_item *item = b_unbox( struct b_hashmap_bucket_item, it.entry, bi_entry); - if (item->bi_key.key_size != key->key_size) { - continue; - } - - if (!memcmp(item->bi_key.key_data, key->key_data, key->key_size)) { + if (compare_key(&item->bi_key, key)) { return true; } } diff --git a/object/include/blue/object/hashmap.h b/object/include/blue/object/hashmap.h index 225b2f2..217aafd 100644 --- a/object/include/blue/object/hashmap.h +++ b/object/include/blue/object/hashmap.h @@ -7,6 +7,7 @@ #include #include #include +#include #define B_HASHMAP(p) ((b_hashmap *)(p)) @@ -38,7 +39,12 @@ typedef struct b_hashmap b_hashmap; typedef void (*b_hashmap_key_destructor)(void *); typedef void (*b_hashmap_value_destructor)(void *); +typedef enum b_hashmap_key_flags { + B_HASHMAP_KEY_F_INTVALUE = 0x01u, +} b_hashmap_key_flags; + typedef struct b_hashmap_key { + b_hashmap_key_flags key_flags; const void *key_data; size_t key_size; } b_hashmap_key;