diff --git a/ds/dict.c b/ds/dict.c index c43e33c..a7201b9 100644 --- a/ds/dict.c +++ b/ds/dict.c @@ -1,16 +1,38 @@ -#include "dict.h" - #include #include #include #include -#include #include #include #define HASH_OFFSET_BASIS 0xcbf29ce484222325 #define HASH_PRIME 0x100000001b3 +/*** PRIVATE DATA *************************************************************/ + +struct b_dict_bucket_item { + b_queue_entry bi_entry; + b_string *bi_str; + b_object *bi_value; +}; + +struct b_dict_bucket { + b_btree_node bk_node; + uint64_t bk_hash; + b_queue bk_items; +}; + +struct b_dict_p { + b_btree d_buckets; +}; + +/*** MISC FUNCTIONS ***********************************************************/ + +static B_BTREE_DEFINE_SIMPLE_GET( + struct b_dict_bucket, uint64_t, bk_node, bk_hash, get_bucket); +static B_BTREE_DEFINE_SIMPLE_INSERT( + struct b_dict_bucket, bk_node, bk_hash, put_bucket); + uint64_t b_cstr_hash(const char *s) { uint64_t hash = HASH_OFFSET_BASIS; @@ -23,48 +45,9 @@ uint64_t b_cstr_hash(const char *s) return hash; } -static void dict_release(struct b_dsref *obj); -static void dict_to_string(const struct b_dsref *obj, struct b_stream *out); +/*** PRIVATE FUNCTIONS ********************************************************/ -static struct b_dsref_type dict_type = { - .t_name = "corelib::dict", - .t_flags = B_DSREF_FUNDAMENTAL, - .t_id = B_DSREF_TYPE_DICT, - .t_instance_size = sizeof(struct b_dict), - .t_release = dict_release, - .t_to_string = dict_to_string, -}; - -struct b_dict *b_dict_create(void) -{ - struct b_dict *dict - = (struct b_dict *)b_dsref_type_instantiate(&dict_type); - if (!dict) { - return NULL; - } - - return dict; -} - -struct b_dict *b_dict_create_with_items(const b_dict_item *items) -{ - struct b_dict *dict = b_dict_create(); - if (!dict) { - return NULL; - } - - for (size_t i = 0; items[i].key; i++) { - b_dict_put(dict, items[i].key, items[i].value); - } - - return dict; -} - -static B_BTREE_DEFINE_SIMPLE_GET( - struct b_dict_bucket, uint64_t, bk_node, bk_hash, - get_bucket) static B_BTREE_DEFINE_SIMPLE_INSERT(struct b_dict_bucket, bk_node, bk_hash, put_bucket) - - static struct b_dict_bucket *create_bucket(void) +static struct b_dict_bucket *create_bucket(void) { struct b_dict_bucket *bucket = malloc(sizeof *bucket); if (!bucket) { @@ -86,7 +69,7 @@ static struct b_dict_bucket_item *create_bucket_item(void) return item; } -b_status b_dict_put(struct b_dict *dict, const char *key, b_dsref *value) +static b_status dict_put(struct b_dict_p *dict, const char *key, b_object *value) { uint64_t hash = b_cstr_hash(key); struct b_dict_bucket *bucket = get_bucket(&dict->d_buckets, hash); @@ -106,15 +89,15 @@ b_status b_dict_put(struct b_dict *dict, const char *key, b_dsref *value) } item->bi_str = b_string_create_from_cstr(key); - item->bi_value = b_retain(value); + item->bi_value = b_object_ref(value); b_queue_push_back(&bucket->bk_items, &item->bi_entry); return B_SUCCESS; } -b_status b_dict_put_sk( - struct b_dict *dict, const struct b_string *key, b_dsref *value) +static b_status dict_put_sk( + struct b_dict_p *dict, const b_string *key, b_object *value) { uint64_t hash = b_string_hash(key); struct b_dict_bucket *bucket = get_bucket(&dict->d_buckets, hash); @@ -134,14 +117,14 @@ b_status b_dict_put_sk( } item->bi_str = b_string_duplicate(key); - item->bi_value = b_retain(value); + item->bi_value = b_object_ref(value); b_queue_push_back(&bucket->bk_items, &item->bi_entry); return B_SUCCESS; } -b_dsref *b_dict_at(const struct b_dict *dict, const char *key) +static b_object *dict_at(const struct b_dict_p *dict, const char *key) { uint64_t hash = b_cstr_hash(key); struct b_dict_bucket *bucket = get_bucket(&dict->d_buckets, hash); @@ -162,7 +145,7 @@ b_dsref *b_dict_at(const struct b_dict *dict, const char *key) return NULL; } -b_dsref *b_dict_at_sk(const struct b_dict *dict, const struct b_string *key) +static b_object *dict_at_sk(const struct b_dict_p *dict, const b_string *key) { uint64_t hash = b_string_hash(key); struct b_dict_bucket *bucket = get_bucket(&dict->d_buckets, hash); @@ -183,37 +166,37 @@ b_dsref *b_dict_at_sk(const struct b_dict *dict, const struct b_string *key) return NULL; } -b_dsref *b_dict_get(struct b_dict *dict, const char *key) +static b_object *dict_get(struct b_dict_p *dict, const char *key) { - b_dsref *value = b_dict_at(dict, key); + b_object *value = dict_at(dict, key); if (value) { - b_retain(value); + b_object_ref(value); } return value; } -b_dsref *b_dict_get_sk(struct b_dict *dict, const struct b_string *key) +static b_object *dict_get_sk(struct b_dict_p *dict, const b_string *key) { - b_dsref *value = b_dict_at_sk(dict, key); + b_object *value = dict_at_sk(dict, key); if (value) { - b_retain(value); + b_object_ref(value); } return value; } -bool b_dict_has_key(const struct b_dict *dict, const char *key) +static bool dict_has_key(const struct b_dict_p *dict, const char *key) { - return b_dict_at(dict, key) != NULL; + return dict_at(dict, key) != NULL; } -bool b_dict_has_skey(const struct b_dict *dict, const struct b_string *key) +static bool dict_has_skey(const struct b_dict_p *dict, const b_string *key) { - return b_dict_at_sk(dict, key) != NULL; + return dict_at_sk(dict, key) != NULL; } -size_t b_dict_get_size(const struct b_dict *dict) +static size_t dict_get_size(const struct b_dict_p *dict) { size_t count = 0; b_btree_iterator it1; @@ -231,7 +214,7 @@ size_t b_dict_get_size(const struct b_dict *dict) return count; } -bool b_dict_is_empty(const b_dict *dict) +static bool dict_is_empty(const struct b_dict_p *dict) { b_btree_node *first_node = b_btree_first(&dict->d_buckets); struct b_dict_bucket *first_bucket @@ -250,110 +233,6 @@ bool b_dict_is_empty(const b_dict *dict) return false; } -static void dict_to_string(const struct b_dsref *obj, struct b_stream *out) -{ - struct b_dict *dict = B_DICT(obj); - - if (b_dict_is_empty(dict)) { - b_stream_write_string(out, "{}", NULL); - return; - } - - b_stream_write_string(out, "{\n", NULL); - - b_stream_push_indent(out, 1); - size_t len = b_dict_get_size(dict); - - b_dict_iterator it; - b_dict_foreach(&it, dict) - { - b_to_string(B_DSREF(it.key), out); - b_stream_write_string(out, ": ", NULL); - - bool is_string = b_typeid(it.value) == B_DSREF_TYPE_STRING; - - if (is_string) { - b_stream_write_char(out, '"'); - } - - b_to_string(it.value, out); - - if (is_string) { - b_stream_write_char(out, '"'); - } - - if (it.i < len - 1) { - b_stream_write_string(out, ",", NULL); - } - - b_stream_write_char(out, '\n'); - } - - b_stream_pop_indent(out); - b_stream_write_char(out, '}'); -} - -static bool dict_iterator_next(struct b_iterator *it) -{ - return b_dict_iterator_next((struct b_dict_iterator *)it); -} - -static b_status dict_iterator_erase(struct b_iterator *it) -{ - return b_dict_iterator_erase((struct b_dict_iterator *)it); -} - -static bool dict_iterator_is_valid(const struct b_iterator *it) -{ - return b_dict_iterator_is_valid((struct b_dict_iterator *)it); -} - -static struct b_iterator_ops it_ops = { - .it_next = dict_iterator_next, - .it_close = NULL, - .it_erase = dict_iterator_erase, - .it_is_valid = dict_iterator_is_valid, -}; - -int b_dict_iterator_begin(struct b_dict *dict, b_dict_iterator *it) -{ - it->_base.it_ops = &it_ops; - - it->i = 0; - if (b_dict_is_empty(dict)) { - it->key = NULL; - it->value = NULL; - return -1; - } - - b_btree_node *first_node = b_btree_first(&dict->d_buckets); - struct b_dict_bucket *first_bucket - = b_unbox(struct b_dict_bucket, first_node, bk_node); - if (!first_bucket) { - it->key = NULL; - it->value = NULL; - return -1; - } - - b_queue_entry *first_entry = b_queue_first(&first_bucket->bk_items); - struct b_dict_bucket_item *first_item - = b_unbox(struct b_dict_bucket_item, first_entry, bi_entry); - if (!first_item) { - it->key = NULL; - it->value = NULL; - return -1; - } - - it->key = first_item->bi_str; - it->value = first_item->bi_value; - - it->_d = dict; - 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) @@ -402,6 +281,256 @@ static bool get_next_node( return true; } +static b_status delete_item( + struct b_dict_p *dict, struct b_dict_bucket *bucket, + struct b_dict_bucket_item *item) +{ + b_queue_delete(&bucket->bk_items, &item->bi_entry); + free(item); + + if (b_queue_empty(&bucket->bk_items)) { + b_btree_delete(&dict->d_buckets, &bucket->bk_node); + free(bucket); + } + + return B_SUCCESS; +} + +/*** PUBLIC FUNCTIONS *********************************************************/ + +b_dict *b_dict_create_with_items(const b_dict_item *items) +{ + b_dict *dict = b_dict_create(); + if (!dict) { + return NULL; + } + + struct b_dict_p *p = b_object_get_private(dict, B_TYPE_DICT); + + for (size_t i = 0; items[i].key; i++) { + dict_put(p, items[i].key, items[i].value); + } + + return dict; +} +b_status b_dict_put(b_dict *dict, const char *key, b_object *value) +{ + B_CLASS_DISPATCH_STATIC(B_TYPE_DICT, dict_put, dict, key, value); +} + +b_status b_dict_put_sk(b_dict *dict, const b_string *key, b_object *value) +{ + B_CLASS_DISPATCH_STATIC(B_TYPE_DICT, dict_put_sk, dict, key, value); +} + +b_object *b_dict_at(const b_dict *dict, const char *key) +{ + B_CLASS_DISPATCH_STATIC(B_TYPE_DICT, dict_at, dict, key); +} + +b_object *b_dict_at_sk(const b_dict *dict, const b_string *key) +{ + B_CLASS_DISPATCH_STATIC(B_TYPE_DICT, dict_at_sk, dict, key); +} + +b_object *b_dict_get(b_dict *dict, const char *key) +{ + B_CLASS_DISPATCH_STATIC(B_TYPE_DICT, dict_get, dict, key); +} + +b_object *b_dict_get_sk(b_dict *dict, const b_string *key) +{ + B_CLASS_DISPATCH_STATIC(B_TYPE_DICT, dict_get_sk, dict, key); +} + +bool b_dict_has_key(const b_dict *dict, const char *key) +{ + B_CLASS_DISPATCH_STATIC(B_TYPE_DICT, dict_has_key, dict, key); +} + +bool b_dict_has_skey(const b_dict *dict, const b_string *key) +{ + B_CLASS_DISPATCH_STATIC(B_TYPE_DICT, dict_has_skey, dict, key); +} + +size_t b_dict_get_size(const b_dict *dict) +{ + B_CLASS_DISPATCH_STATIC_0(B_TYPE_DICT, dict_get_size, dict); +} + +bool b_dict_is_empty(const b_dict *dict) +{ + B_CLASS_DISPATCH_STATIC_0(B_TYPE_DICT, dict_is_empty, dict); +} + +/*** PUBLIC ALIAS FUNCTIONS ***************************************************/ +/*** VIRTUAL FUNCTIONS ********************************************************/ + +static void dict_init(b_object *obj, void *priv) +{ + struct b_dict_p *dict = priv; +} + +static void dict_fini(b_object *obj, void *priv) +{ + struct b_dict_p *dict = priv; + + b_btree_iterator tree_it; + b_btree_iterator_begin(&dict->d_buckets, &tree_it); + while (b_btree_iterator_is_valid(&tree_it)) { + struct b_dict_bucket *bucket + = b_unbox(struct b_dict_bucket, tree_it.node, bk_node); + b_btree_iterator_erase(&tree_it); + + if (!bucket) { + continue; + } + + b_queue_iterator bucket_it; + b_queue_iterator_begin(&bucket->bk_items, &bucket_it); + while (b_queue_iterator_is_valid(&bucket_it)) { + struct b_dict_bucket_item *item = b_unbox( + struct b_dict_bucket_item, bucket_it.entry, + bi_entry); + b_queue_iterator_erase(&bucket_it); + + if (!item) { + continue; + } + + free(item->bi_str); + b_object_unref(item->bi_value); + free(item); + } + + free(bucket); + } +} + +static void dict_to_string(const b_object *obj, struct b_stream *out) +{ + struct b_dict_p *dict = b_object_get_private(obj, B_TYPE_DICT); + + if (dict_is_empty(dict)) { + b_stream_write_string(out, "{}", NULL); + return; + } + + b_stream_write_string(out, "{\n", NULL); + + b_stream_push_indent(out, 1); + size_t len = dict_get_size(dict); + + b_dict_iterator it; + b_dict_foreach(&it, (b_dict *)obj) + { + b_object_to_string(it.key, out); + b_stream_write_string(out, ": ", NULL); + + bool is_string = b_object_is_type(it.value, B_TYPE_STRING); + + if (is_string) { + b_stream_write_char(out, '"'); + } + + b_object_to_string(it.value, out); + + if (is_string) { + b_stream_write_char(out, '"'); + } + + if (it.i < len - 1) { + b_stream_write_string(out, ",", NULL); + } + + b_stream_write_char(out, '\n'); + } + + b_stream_pop_indent(out); + b_stream_write_char(out, '}'); +} + +/*** CLASS DEFINITION *********************************************************/ + +B_TYPE_CLASS_DEFINITION_BEGIN(b_dict) + B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT) + B_INTERFACE_ENTRY(to_string) = dict_to_string; + B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT) +B_TYPE_CLASS_DEFINITION_END(b_dict) + +B_TYPE_DEFINITION_BEGIN(b_dict) + B_TYPE_ID(0xd2af61d9, 0xd0be, 0x4960, 0xbe3f, 0x509749814c10); + B_TYPE_CLASS(b_dict_class); + B_TYPE_INSTANCE_INIT(dict_init); + B_TYPE_INSTANCE_INIT(dict_fini); +B_TYPE_DEFINITION_END(b_dict) + +/*** ITERATOR FUNCTIONS *******************************************************/ + +static bool dict_iterator_next(struct b_iterator *it) +{ + return b_dict_iterator_next((struct b_dict_iterator *)it); +} + +static b_status dict_iterator_erase(struct b_iterator *it) +{ + return b_dict_iterator_erase((struct b_dict_iterator *)it); +} + +static bool dict_iterator_is_valid(const struct b_iterator *it) +{ + return b_dict_iterator_is_valid((struct b_dict_iterator *)it); +} + +static struct b_iterator_ops it_ops = { + .it_next = dict_iterator_next, + .it_close = NULL, + .it_erase = dict_iterator_erase, + .it_is_valid = dict_iterator_is_valid, +}; + +int b_dict_iterator_begin(b_dict *dict, b_dict_iterator *it) +{ + it->_base.it_ops = &it_ops; + + it->i = 0; + it->_d = dict; + it->_d_p = b_object_get_private(dict, B_TYPE_DICT); + + if (dict_is_empty(it->_d_p)) { + it->key = NULL; + it->value = NULL; + return -1; + } + + b_btree_node *first_node = b_btree_first(&it->_d_p->d_buckets); + struct b_dict_bucket *first_bucket + = b_unbox(struct b_dict_bucket, first_node, bk_node); + if (!first_bucket) { + it->key = NULL; + it->value = NULL; + return -1; + } + + b_queue_entry *first_entry = b_queue_first(&first_bucket->bk_items); + struct b_dict_bucket_item *first_item + = b_unbox(struct b_dict_bucket_item, first_entry, bi_entry); + if (!first_item) { + it->key = NULL; + it->value = NULL; + return -1; + } + + it->key = first_item->bi_str; + it->value = first_item->bi_value; + + it->_d = dict; + it->_cbn = first_node; + it->_cqe = first_entry; + + return 0; +} + bool b_dict_iterator_next(b_dict_iterator *it) { struct b_btree_node *next_node; @@ -431,21 +560,6 @@ bool b_dict_iterator_next(b_dict_iterator *it) return 0; } -static b_status delete_item( - struct b_dict *dict, struct b_dict_bucket *bucket, - struct b_dict_bucket_item *item) -{ - b_queue_delete(&bucket->bk_items, &item->bi_entry); - free(item); - - if (b_queue_empty(&bucket->bk_items)) { - b_btree_delete(&dict->d_buckets, &bucket->bk_node); - free(bucket); - } - - return B_SUCCESS; -} - b_status b_dict_iterator_erase(struct b_dict_iterator *it) { if ((it->key || it->value) && !(it->_cbn && it->_cqe)) { @@ -472,7 +586,7 @@ b_status b_dict_iterator_erase(struct b_dict_iterator *it) struct b_dict_bucket_item *next_item = b_unbox(struct b_dict_bucket_item, next_entry, bi_entry); - b_status status = delete_item(it->_d, cur_bucket, cur_item); + b_status status = delete_item(it->_d_p, cur_bucket, cur_item); if (B_ERR(status)) { return status; } @@ -498,52 +612,3 @@ bool b_dict_iterator_is_valid(const struct b_dict_iterator *it) { return it->key != NULL; } - -static void dict_release(struct b_dsref *obj) -{ - struct b_dict *dict = B_DICT(obj); - - b_btree_iterator tree_it; - b_btree_iterator_begin(&dict->d_buckets, &tree_it); - while (b_btree_iterator_is_valid(&tree_it)) { - struct b_dict_bucket *bucket - = b_unbox(struct b_dict_bucket, tree_it.node, bk_node); - b_btree_iterator_erase(&tree_it); - - if (!bucket) { - continue; - } - - b_queue_iterator bucket_it; - b_queue_iterator_begin(&bucket->bk_items, &bucket_it); - while (b_queue_iterator_is_valid(&bucket_it)) { - struct b_dict_bucket_item *item = b_unbox( - struct b_dict_bucket_item, bucket_it.entry, - bi_entry); - b_queue_iterator_erase(&bucket_it); - - if (!item) { - continue; - } - - free(item->bi_str); - b_release(item->bi_value); - free(item); - } - - free(bucket); - } - -#if 0 - b_dict_iterator it; - b_dict_iterator_begin(dict, &it); - while (b_dict_iterator_is_valid(&it)) { - b_dict_iterator_erase(&it); - } -#endif -} - -b_dsref_type_id b_dict_type_id(void) -{ - return (b_dsref_type_id)&dict_type; -} diff --git a/ds/dict.h b/ds/dict.h deleted file mode 100644 index 1d72a51..0000000 --- a/ds/dict.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef _B_DICT_H_ -#define _B_DICT_H_ - -#include "object.h" - -#include -#include - -struct b_string; - -struct b_dict_bucket_item { - b_queue_entry bi_entry; - struct b_string *bi_str; - struct b_dsref *bi_value; -}; - -struct b_dict_bucket { - b_btree_node bk_node; - uint64_t bk_hash; - b_queue bk_items; -}; - -struct b_dict { - struct b_dsref d_base; - b_btree d_buckets; -}; - -#endif diff --git a/ds/include/blue/ds/dict.h b/ds/include/blue/ds/dict.h index c4fae50..8cd75d9 100644 --- a/ds/include/blue/ds/dict.h +++ b/ds/include/blue/ds/dict.h @@ -1,16 +1,23 @@ -#ifndef BLUELIB_DICT_H_ -#define BLUELIB_DICT_H_ +#ifndef BLUE_DS_DICT_H_ +#define BLUE_DS_DICT_H_ #include +#include #include #include #include -#include -#include +#include -struct b_string; +B_DECLS_BEGIN; -#define B_DICT(p) ((b_dict *)(p)) +#define B_TYPE_DICT (b_dict_get_type()) + +struct b_dict_p; + +B_DECLARE_TYPE(b_dict); + +B_TYPE_CLASS_DECLARATION_BEGIN(b_dict) +B_TYPE_CLASS_DECLARATION_END(b_dict) #define B_DICT_ITEM(k, v) {.key = (k), .value = (v)} #define B_DICT_ITEM_END {.key = NULL, .value = NULL} @@ -19,46 +26,38 @@ struct b_string; for (int z__b_unique_name() = b_dict_iterator_begin(dict, it); \ (it)->key != NULL; b_dict_iterator_next(it)) -typedef struct b_dict b_dict; - typedef struct b_dict_iterator { b_iterator _base; size_t i; - const struct b_string *key; - b_dsref *value; + const b_string *key; + b_object *value; b_dict *_d; + struct b_dict_p *_d_p; b_btree_node *_cbn; b_queue_entry *_cqe; } b_dict_iterator; typedef struct b_dict_item { const char *key; - b_dsref *value; + b_object *value; } b_dict_item; -BLUE_API b_dict *b_dict_create(void); +BLUE_API b_type b_dict_get_type(void); + +B_TYPE_DEFAULT_CONSTRUCTOR(b_dict, B_TYPE_DICT); + BLUE_API b_dict *b_dict_create_with_items(const b_dict_item *items); -static inline b_dict *b_dict_retain(b_dict *dict) -{ - return B_DICT(b_retain(B_DSREF(dict))); -} -static inline void b_dict_release(b_dict *dict) -{ - b_release(B_DSREF(dict)); -} - -BLUE_API b_status b_dict_put(b_dict *dict, const char *key, b_dsref *value); -BLUE_API b_status b_dict_put_sk( - b_dict *dict, const struct b_string *key, b_dsref *value); -BLUE_API b_dsref *b_dict_at(const b_dict *dict, const char *key); -BLUE_API b_dsref *b_dict_at_sk(const b_dict *dict, const struct b_string *key); -BLUE_API b_dsref *b_dict_get(b_dict *dict, const char *key); -BLUE_API b_dsref *b_dict_get_sk(b_dict *dict, const struct b_string *key); +BLUE_API b_status b_dict_put(b_dict *dict, const char *key, b_object *value); +BLUE_API b_status b_dict_put_sk(b_dict *dict, const b_string *key, b_object *value); +BLUE_API b_object *b_dict_at(const b_dict *dict, const char *key); +BLUE_API b_object *b_dict_at_sk(const b_dict *dict, const b_string *key); +BLUE_API b_object *b_dict_get(b_dict *dict, const char *key); +BLUE_API b_object *b_dict_get_sk(b_dict *dict, const b_string *key); BLUE_API bool b_dict_has_key(const b_dict *dict, const char *key); -BLUE_API bool b_dict_has_skey(const b_dict *dict, const struct b_string *key); +BLUE_API bool b_dict_has_skey(const b_dict *dict, const b_string *key); BLUE_API size_t b_dict_get_size(const b_dict *dict); BLUE_API bool b_dict_is_empty(const b_dict *dict); @@ -67,4 +66,6 @@ BLUE_API bool b_dict_iterator_next(b_dict_iterator *it); BLUE_API b_status b_dict_iterator_erase(b_dict_iterator *it); BLUE_API bool b_dict_iterator_is_valid(const b_dict_iterator *it); +B_DECLS_END; + #endif