ds: hashmap: convert to new object system
This commit is contained in:
665
ds/hashmap.c
665
ds/hashmap.c
@@ -1,32 +1,42 @@
|
||||
#include "hashmap.h"
|
||||
|
||||
#include <blue/core/misc.h>
|
||||
#include <blue/core/status.h>
|
||||
#include <blue/ds/hashmap.h>
|
||||
#include <blue/ds/string.h>
|
||||
#include <blue/ds/type.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define HASH_OFFSET_BASIS 0xcbf29ce484222325
|
||||
#define HASH_PRIME 0x100000001b3
|
||||
|
||||
/* clang-format off */
|
||||
/*** PRIVATE DATA *************************************************************/
|
||||
|
||||
struct b_hashmap_bucket_item {
|
||||
struct b_queue_entry bi_entry;
|
||||
struct b_hashmap_key bi_key;
|
||||
struct b_hashmap_value bi_value;
|
||||
};
|
||||
|
||||
struct b_hashmap_bucket {
|
||||
struct b_btree_node bk_node;
|
||||
uint64_t bk_hash;
|
||||
struct b_queue bk_items;
|
||||
};
|
||||
|
||||
struct b_hashmap_p {
|
||||
struct b_btree h_buckets;
|
||||
b_hashmap_key_destructor h_key_dtor;
|
||||
b_hashmap_value_destructor h_value_dtor;
|
||||
};
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
|
||||
static B_BTREE_DEFINE_SIMPLE_GET(
|
||||
struct b_hashmap_bucket,
|
||||
uint64_t,
|
||||
bk_node,
|
||||
bk_hash,
|
||||
get_bucket)
|
||||
struct b_hashmap_bucket, uint64_t, bk_node, bk_hash, get_bucket);
|
||||
static B_BTREE_DEFINE_SIMPLE_INSERT(
|
||||
struct b_hashmap_bucket,
|
||||
bk_node,
|
||||
bk_hash,
|
||||
put_bucket)
|
||||
struct b_hashmap_bucket, bk_node, bk_hash, put_bucket);
|
||||
|
||||
static uint64_t hash_data(const void *p, size_t size)
|
||||
{
|
||||
/* clang-format on */
|
||||
const unsigned char *s = p;
|
||||
uint64_t hash = HASH_OFFSET_BASIS;
|
||||
|
||||
@@ -38,8 +48,6 @@ static uint64_t hash_data(const void *p, size_t size)
|
||||
return hash;
|
||||
}
|
||||
|
||||
static void hashmap_release(struct b_dsref *obj);
|
||||
|
||||
static uint64_t hash_key(const struct b_hashmap_key *key)
|
||||
{
|
||||
if (key->key_flags & B_HASHMAP_KEY_F_INTVALUE) {
|
||||
@@ -79,270 +87,6 @@ static bool compare_key(
|
||||
return memcmp(a_data, b_data, cmp_len) == 0;
|
||||
}
|
||||
|
||||
static struct b_dsref_type hashmap_type = {
|
||||
.t_name = "corelib::hashmap",
|
||||
.t_flags = B_DSREF_FUNDAMENTAL,
|
||||
.t_id = B_DSREF_TYPE_HASHMAP,
|
||||
.t_instance_size = sizeof(struct b_hashmap),
|
||||
.t_release = hashmap_release,
|
||||
};
|
||||
|
||||
struct b_hashmap *b_hashmap_create(
|
||||
b_hashmap_key_destructor key_dtor, b_hashmap_value_destructor value_dtor)
|
||||
{
|
||||
struct b_hashmap *hashmap
|
||||
= (struct b_hashmap *)b_dsref_type_instantiate(&hashmap_type);
|
||||
if (!hashmap) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return hashmap;
|
||||
}
|
||||
|
||||
struct b_hashmap *b_hashmap_create_with_items(const b_hashmap_item *items)
|
||||
{
|
||||
struct b_hashmap *hashmap = b_hashmap_create(NULL, NULL);
|
||||
if (!hashmap) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (size_t i = 0; items[i].key.key_data && items[i].key.key_size; i++) {
|
||||
b_hashmap_put(hashmap, &items[i].key, &items[i].value);
|
||||
}
|
||||
|
||||
return hashmap;
|
||||
}
|
||||
|
||||
static struct b_hashmap_bucket *create_bucket(void)
|
||||
{
|
||||
/* clang-format on */
|
||||
struct b_hashmap_bucket *bucket = malloc(sizeof *bucket);
|
||||
if (!bucket) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(bucket, 0x0, sizeof *bucket);
|
||||
return bucket;
|
||||
}
|
||||
|
||||
static struct b_hashmap_bucket_item *create_bucket_item(void)
|
||||
{
|
||||
struct b_hashmap_bucket_item *item = malloc(sizeof *item);
|
||||
if (!item) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(item, 0x0, sizeof *item);
|
||||
return item;
|
||||
}
|
||||
|
||||
b_status b_hashmap_put(
|
||||
struct b_hashmap *hashmap, const b_hashmap_key *key,
|
||||
const b_hashmap_value *value)
|
||||
{
|
||||
uint64_t hash = hash_key(key);
|
||||
struct b_hashmap_bucket *bucket = get_bucket(&hashmap->h_buckets, hash);
|
||||
|
||||
if (!bucket) {
|
||||
bucket = create_bucket();
|
||||
if (!bucket) {
|
||||
return B_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
bucket->bk_hash = hash;
|
||||
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);
|
||||
|
||||
if (compare_key(&item->bi_key, key)) {
|
||||
memcpy(&item->bi_value, value, sizeof *value);
|
||||
return B_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
struct b_hashmap_bucket_item *item = create_bucket_item();
|
||||
if (!item) {
|
||||
return B_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
memcpy(&item->bi_key, key, sizeof *key);
|
||||
memcpy(&item->bi_value, value, sizeof *value);
|
||||
|
||||
b_queue_push_back(&bucket->bk_items, &item->bi_entry);
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
const struct b_hashmap_value *b_hashmap_get(
|
||||
const struct b_hashmap *hashmap, const struct b_hashmap_key *key)
|
||||
{
|
||||
uint64_t hash = hash_key(key);
|
||||
|
||||
struct b_hashmap_bucket *bucket = get_bucket(&hashmap->h_buckets, hash);
|
||||
if (!bucket) {
|
||||
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);
|
||||
|
||||
if (compare_key(&item->bi_key, key)) {
|
||||
return &item->bi_value;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool b_hashmap_has_key(const struct b_hashmap *hashmap, const b_hashmap_key *key)
|
||||
{
|
||||
uint64_t hash = hash_key(key);
|
||||
struct b_hashmap_bucket *bucket = get_bucket(&hashmap->h_buckets, hash);
|
||||
if (!bucket) {
|
||||
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);
|
||||
|
||||
if (compare_key(&item->bi_key, key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t b_hashmap_get_size(const struct b_hashmap *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;
|
||||
}
|
||||
|
||||
bool b_hashmap_is_empty(const b_hashmap *hashmap)
|
||||
{
|
||||
b_btree_node *first_node = b_btree_first(&hashmap->h_buckets);
|
||||
struct b_hashmap_bucket *first_bucket
|
||||
= b_unbox(struct b_hashmap_bucket, first_node, bk_node);
|
||||
if (!first_bucket) {
|
||||
return true;
|
||||
}
|
||||
|
||||
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) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static b_status delete_item(
|
||||
struct b_hashmap *hashmap, struct b_hashmap_bucket *bucket,
|
||||
struct b_hashmap_bucket_item *item)
|
||||
{
|
||||
b_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 (b_queue_empty(&bucket->bk_items)) {
|
||||
b_btree_delete(&hashmap->h_buckets, &bucket->bk_node);
|
||||
free(bucket);
|
||||
}
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static bool hashmap_iterator_next(struct b_iterator *it)
|
||||
{
|
||||
return b_hashmap_iterator_next((struct b_hashmap_iterator *)it);
|
||||
}
|
||||
|
||||
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(
|
||||
struct b_hashmap *hashmap, struct b_hashmap_iterator *it)
|
||||
{
|
||||
it->_h = hashmap;
|
||||
it->_base.it_ops = &it_ops;
|
||||
|
||||
it->i = 0;
|
||||
if (b_hashmap_is_empty(hashmap)) {
|
||||
it->key = NULL;
|
||||
it->value = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct b_btree_node *first_node = b_btree_first(&hashmap->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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
it->key = &first_item->bi_key;
|
||||
it->value = &first_item->bi_value;
|
||||
|
||||
it->_cbn = first_node;
|
||||
it->_cqe = first_entry;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool get_next_node(
|
||||
struct b_btree_node *cur_node, struct b_queue_entry *cur_entry,
|
||||
struct b_btree_node **out_next_node, struct b_queue_entry **out_next_entry)
|
||||
@@ -391,6 +135,349 @@ static bool get_next_node(
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct b_hashmap_bucket *create_bucket(void)
|
||||
{
|
||||
struct b_hashmap_bucket *bucket = malloc(sizeof *bucket);
|
||||
if (!bucket) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(bucket, 0x0, sizeof *bucket);
|
||||
return bucket;
|
||||
}
|
||||
|
||||
static struct b_hashmap_bucket_item *create_bucket_item(void)
|
||||
{
|
||||
struct b_hashmap_bucket_item *item = malloc(sizeof *item);
|
||||
if (!item) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(item, 0x0, sizeof *item);
|
||||
return item;
|
||||
}
|
||||
|
||||
static b_status hashmap_put(
|
||||
struct b_hashmap_p *hashmap, const b_hashmap_key *key,
|
||||
const b_hashmap_value *value)
|
||||
{
|
||||
uint64_t hash = hash_key(key);
|
||||
struct b_hashmap_bucket *bucket = get_bucket(&hashmap->h_buckets, hash);
|
||||
|
||||
if (!bucket) {
|
||||
bucket = create_bucket();
|
||||
if (!bucket) {
|
||||
return B_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
bucket->bk_hash = hash;
|
||||
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);
|
||||
|
||||
if (compare_key(&item->bi_key, key)) {
|
||||
memcpy(&item->bi_value, value, sizeof *value);
|
||||
return B_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
struct b_hashmap_bucket_item *item = create_bucket_item();
|
||||
if (!item) {
|
||||
return B_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
memcpy(&item->bi_key, key, sizeof *key);
|
||||
memcpy(&item->bi_value, value, sizeof *value);
|
||||
|
||||
b_queue_push_back(&bucket->bk_items, &item->bi_entry);
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static const struct b_hashmap_value *hashmap_get(
|
||||
const struct b_hashmap_p *hashmap, const struct b_hashmap_key *key)
|
||||
{
|
||||
uint64_t hash = hash_key(key);
|
||||
|
||||
struct b_hashmap_bucket *bucket = get_bucket(&hashmap->h_buckets, hash);
|
||||
if (!bucket) {
|
||||
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);
|
||||
|
||||
if (compare_key(&item->bi_key, key)) {
|
||||
return &item->bi_value;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool hashmap_has_key(
|
||||
const struct b_hashmap_p *hashmap, const b_hashmap_key *key)
|
||||
{
|
||||
uint64_t hash = hash_key(key);
|
||||
struct b_hashmap_bucket *bucket = get_bucket(&hashmap->h_buckets, hash);
|
||||
if (!bucket) {
|
||||
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);
|
||||
|
||||
if (compare_key(&item->bi_key, key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static bool hashmap_is_empty(const struct b_hashmap_p *hashmap)
|
||||
{
|
||||
b_btree_node *first_node = b_btree_first(&hashmap->h_buckets);
|
||||
struct b_hashmap_bucket *first_bucket
|
||||
= b_unbox(struct b_hashmap_bucket, first_node, bk_node);
|
||||
if (!first_bucket) {
|
||||
return true;
|
||||
}
|
||||
|
||||
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) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static b_status delete_item(
|
||||
struct b_hashmap_p *hashmap, struct b_hashmap_bucket *bucket,
|
||||
struct b_hashmap_bucket_item *item)
|
||||
{
|
||||
b_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 (b_queue_empty(&bucket->bk_items)) {
|
||||
b_btree_delete(&hashmap->h_buckets, &bucket->bk_node);
|
||||
free(bucket);
|
||||
}
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
/*** PUBLIC FUNCTIONS *********************************************************/
|
||||
|
||||
b_hashmap *b_hashmap_create(
|
||||
b_hashmap_key_destructor key_dtor, b_hashmap_value_destructor value_dtor)
|
||||
{
|
||||
b_hashmap *hashmap = b_object_create(B_TYPE_HASHMAP);
|
||||
if (!hashmap) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return hashmap;
|
||||
}
|
||||
|
||||
b_hashmap *b_hashmap_create_with_items(const b_hashmap_item *items)
|
||||
{
|
||||
b_hashmap *hashmap = b_hashmap_create(NULL, NULL);
|
||||
if (!hashmap) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct b_hashmap_p *p = b_object_get_private(hashmap, B_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;
|
||||
}
|
||||
|
||||
b_status b_hashmap_put(
|
||||
b_hashmap *hashmap, const b_hashmap_key *key, const b_hashmap_value *value)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_HASHMAP, hashmap_put, hashmap, key, value);
|
||||
}
|
||||
|
||||
const struct b_hashmap_value *b_hashmap_get(
|
||||
const b_hashmap *hashmap, const struct b_hashmap_key *key)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_HASHMAP, hashmap_get, hashmap, key);
|
||||
}
|
||||
|
||||
bool b_hashmap_has_key(const b_hashmap *hashmap, const b_hashmap_key *key)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_HASHMAP, hashmap_has_key, hashmap, key);
|
||||
}
|
||||
|
||||
size_t b_hashmap_get_size(const b_hashmap *hashmap)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_HASHMAP, hashmap_get_size, hashmap);
|
||||
}
|
||||
|
||||
bool b_hashmap_is_empty(const b_hashmap *hashmap)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_HASHMAP, hashmap_is_empty, hashmap);
|
||||
}
|
||||
|
||||
/*** VIRTUAL FUNCTIONS ********************************************************/
|
||||
|
||||
static void hashmap_init(b_object *obj, void *priv)
|
||||
{
|
||||
struct b_hashmap_p *map = priv;
|
||||
}
|
||||
|
||||
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_hashmap_bucket *b
|
||||
= b_unbox(struct b_hashmap_bucket, it1.node, bk_node);
|
||||
b_btree_iterator_erase(&it1);
|
||||
|
||||
b_queue_iterator it2;
|
||||
b_queue_iterator_begin(&b->bk_items, &it2);
|
||||
while (b_queue_iterator_is_valid(&it2)) {
|
||||
struct b_hashmap_bucket_item *item = b_unbox(
|
||||
struct b_hashmap_bucket_item, it2.entry, bi_entry);
|
||||
b_queue_iterator_erase(&it2);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
free(b);
|
||||
}
|
||||
}
|
||||
|
||||
/*** 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_INIT(hashmap_init);
|
||||
B_TYPE_INSTANCE_INIT(hashmap_fini);
|
||||
B_TYPE_DEFINITION_END(b_hashmap)
|
||||
|
||||
/*** ITERATOR FUNCTIONS *******************************************************/
|
||||
|
||||
static bool hashmap_iterator_next(struct b_iterator *it)
|
||||
{
|
||||
return b_hashmap_iterator_next((struct b_hashmap_iterator *)it);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
it->key = &first_item->bi_key;
|
||||
it->value = &first_item->bi_value;
|
||||
|
||||
it->_cbn = first_node;
|
||||
it->_cqe = first_entry;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool b_hashmap_iterator_next(struct b_hashmap_iterator *it)
|
||||
{
|
||||
struct b_btree_node *next_node;
|
||||
@@ -446,7 +533,7 @@ b_status b_hashmap_iterator_erase(struct b_hashmap_iterator *it)
|
||||
struct b_hashmap_bucket_item *next_item
|
||||
= b_unbox(struct b_hashmap_bucket_item, next_entry, bi_entry);
|
||||
|
||||
b_status status = delete_item(it->_h, cur_bucket, cur_item);
|
||||
b_status status = delete_item(it->_h_p, cur_bucket, cur_item);
|
||||
if (B_ERR(status)) {
|
||||
return status;
|
||||
}
|
||||
@@ -472,19 +559,3 @@ bool b_hashmap_iterator_is_valid(const struct b_hashmap_iterator *it)
|
||||
{
|
||||
return it->key != NULL;
|
||||
}
|
||||
|
||||
static void hashmap_release(struct b_dsref *obj)
|
||||
{
|
||||
struct b_hashmap *map = B_HASHMAP(obj);
|
||||
|
||||
b_hashmap_iterator it;
|
||||
b_hashmap_iterator_begin(map, &it);
|
||||
while (b_hashmap_iterator_is_valid(&it)) {
|
||||
b_hashmap_iterator_erase(&it);
|
||||
}
|
||||
}
|
||||
|
||||
b_dsref_type_id b_hashmap_type_id(void)
|
||||
{
|
||||
return (b_dsref_type_id)&hashmap_type;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user