2024-10-24 19:24:54 +01:00
|
|
|
#include "dict.h"
|
|
|
|
|
|
|
|
|
|
#include <blue/core/status.h>
|
2025-06-27 21:47:55 +01:00
|
|
|
#include <blue/core/stream.h>
|
2025-08-09 19:57:42 +01:00
|
|
|
#include <blue/ds/dict.h>
|
|
|
|
|
#include <blue/ds/string.h>
|
|
|
|
|
#include <blue/ds/type.h>
|
2024-10-24 19:24:54 +01:00
|
|
|
#include <stdbool.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
|
|
#define HASH_OFFSET_BASIS 0xcbf29ce484222325
|
|
|
|
|
#define HASH_PRIME 0x100000001b3
|
|
|
|
|
|
|
|
|
|
uint64_t b_cstr_hash(const char *s)
|
|
|
|
|
{
|
|
|
|
|
uint64_t hash = HASH_OFFSET_BASIS;
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; s[i]; i++) {
|
|
|
|
|
hash *= HASH_PRIME;
|
|
|
|
|
hash ^= s[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return hash;
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-09 19:57:42 +01:00
|
|
|
static void dict_release(struct b_dsref *obj);
|
|
|
|
|
static void dict_to_string(struct b_dsref *obj, struct b_stream *out);
|
2024-10-24 19:24:54 +01:00
|
|
|
|
2025-08-09 19:57:42 +01:00
|
|
|
static struct b_dsref_type dict_type = {
|
2024-10-24 19:24:54 +01:00
|
|
|
.t_name = "corelib::dict",
|
2025-08-09 19:57:42 +01:00
|
|
|
.t_flags = B_DSREF_FUNDAMENTAL,
|
|
|
|
|
.t_id = B_DSREF_TYPE_DICT,
|
2024-10-24 19:24:54 +01:00
|
|
|
.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
|
2025-08-09 19:57:42 +01:00
|
|
|
= (struct b_dict *)b_dsref_type_instantiate(&dict_type);
|
2024-10-24 19:24:54 +01:00
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
struct b_dict_bucket *bucket = malloc(sizeof *bucket);
|
|
|
|
|
if (!bucket) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memset(bucket, 0x0, sizeof *bucket);
|
|
|
|
|
return bucket;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct b_dict_bucket_item *create_bucket_item(void)
|
|
|
|
|
{
|
|
|
|
|
struct b_dict_bucket_item *item = malloc(sizeof *item);
|
|
|
|
|
if (!item) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memset(item, 0x0, sizeof *item);
|
|
|
|
|
return item;
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-09 19:57:42 +01:00
|
|
|
b_status b_dict_put(struct b_dict *dict, const char *key, b_dsref *value)
|
2024-10-24 19:24:54 +01:00
|
|
|
{
|
|
|
|
|
uint64_t hash = b_cstr_hash(key);
|
|
|
|
|
struct b_dict_bucket *bucket = get_bucket(&dict->d_buckets, hash);
|
|
|
|
|
if (!bucket) {
|
|
|
|
|
bucket = create_bucket();
|
|
|
|
|
if (!bucket) {
|
|
|
|
|
return B_ERR_NO_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bucket->bk_hash = hash;
|
|
|
|
|
put_bucket(&dict->d_buckets, bucket);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct b_dict_bucket_item *item = create_bucket_item();
|
|
|
|
|
if (!item) {
|
|
|
|
|
return B_ERR_NO_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
item->bi_str = b_strdup(key);
|
|
|
|
|
item->bi_value = b_retain(value);
|
|
|
|
|
|
|
|
|
|
b_queue_push_back(&bucket->bk_items, &item->bi_entry);
|
|
|
|
|
|
|
|
|
|
return B_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-09 19:57:42 +01:00
|
|
|
b_dsref *b_dict_at(const struct b_dict *dict, const char *key)
|
2024-10-24 19:24:54 +01:00
|
|
|
{
|
|
|
|
|
uint64_t hash = b_cstr_hash(key);
|
|
|
|
|
struct b_dict_bucket *bucket = get_bucket(&dict->d_buckets, hash);
|
|
|
|
|
if (!bucket) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
b_queue_iterator it;
|
|
|
|
|
b_queue_foreach (&it, &bucket->bk_items) {
|
|
|
|
|
struct b_dict_bucket_item *item
|
|
|
|
|
= b_unbox(struct b_dict_bucket_item, it.entry, bi_entry);
|
|
|
|
|
|
|
|
|
|
if (!strcmp(item->bi_str, key)) {
|
|
|
|
|
return item->bi_value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-09 19:57:42 +01:00
|
|
|
b_dsref *b_dict_get(struct b_dict *dict, const char *key)
|
2024-10-24 19:24:54 +01:00
|
|
|
{
|
2025-08-09 19:57:42 +01:00
|
|
|
b_dsref *value = b_dict_at(dict, key);
|
2024-10-24 19:24:54 +01:00
|
|
|
if (value) {
|
|
|
|
|
b_retain(value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool b_dict_has_key(const struct b_dict *dict, const char *key)
|
|
|
|
|
{
|
|
|
|
|
return b_dict_at(dict, key) != NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t b_dict_get_size(const struct b_dict *dict)
|
|
|
|
|
{
|
|
|
|
|
size_t count = 0;
|
|
|
|
|
b_btree_iterator it1;
|
|
|
|
|
b_queue_iterator it2;
|
|
|
|
|
|
|
|
|
|
b_btree_foreach (&it1, &dict->d_buckets) {
|
|
|
|
|
struct b_dict_bucket *bucket
|
|
|
|
|
= b_unbox(struct b_dict_bucket, it1.node, bk_node);
|
|
|
|
|
|
|
|
|
|
b_queue_foreach (&it2, &bucket->bk_items) {
|
|
|
|
|
count++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool b_dict_is_empty(const b_dict *dict)
|
|
|
|
|
{
|
|
|
|
|
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) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-09 19:57:42 +01:00
|
|
|
static void dict_to_string(struct b_dsref *obj, struct b_stream *out)
|
2024-10-24 19:24:54 +01:00
|
|
|
{
|
|
|
|
|
struct b_dict *dict = B_DICT(obj);
|
|
|
|
|
|
|
|
|
|
if (b_dict_is_empty(dict)) {
|
2025-06-27 21:47:55 +01:00
|
|
|
b_stream_write_string(out, "{}", NULL);
|
2024-10-24 19:24:54 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-27 21:47:55 +01:00
|
|
|
b_stream_write_string(out, "{\n", NULL);
|
2024-10-24 19:24:54 +01:00
|
|
|
|
2025-06-27 21:47:55 +01:00
|
|
|
b_stream_push_indent(out, 1);
|
2024-10-24 19:24:54 +01:00
|
|
|
size_t len = b_dict_get_size(dict);
|
|
|
|
|
|
|
|
|
|
b_dict_iterator it;
|
|
|
|
|
b_dict_foreach(&it, dict)
|
|
|
|
|
{
|
2025-06-27 21:47:55 +01:00
|
|
|
b_stream_write_fmt(out, NULL, "%s: ", it.key);
|
|
|
|
|
|
2025-08-09 19:57:42 +01:00
|
|
|
bool is_string = b_typeid(it.value) == B_DSREF_TYPE_STRING;
|
2025-06-27 21:47:55 +01:00
|
|
|
|
|
|
|
|
if (is_string) {
|
|
|
|
|
b_stream_write_char(out, '"');
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-24 19:24:54 +01:00
|
|
|
b_to_string(it.value, out);
|
|
|
|
|
|
2025-06-27 21:47:55 +01:00
|
|
|
if (is_string) {
|
|
|
|
|
b_stream_write_char(out, '"');
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-24 19:24:54 +01:00
|
|
|
if (it.i < len - 1) {
|
2025-06-27 21:47:55 +01:00
|
|
|
b_stream_write_string(out, ",", NULL);
|
2024-10-24 19:24:54 +01:00
|
|
|
}
|
|
|
|
|
|
2025-06-27 21:47:55 +01:00
|
|
|
b_stream_write_char(out, '\n');
|
2024-10-24 19:24:54 +01:00
|
|
|
}
|
|
|
|
|
|
2025-06-27 21:47:55 +01:00
|
|
|
b_stream_pop_indent(out);
|
|
|
|
|
b_stream_write_char(out, '}');
|
2024-10-24 19:24:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
struct b_dict_bucket *cur_bucket
|
|
|
|
|
= b_unbox(struct b_dict_bucket, cur_node, bk_node);
|
|
|
|
|
if (!cur_bucket) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct b_dict_bucket_item *cur_item
|
|
|
|
|
= b_unbox(struct b_dict_bucket_item, cur_entry, bi_entry);
|
|
|
|
|
if (!cur_item) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct b_btree_node *next_node = cur_node;
|
|
|
|
|
struct b_queue_entry *next_entry = b_queue_next(cur_entry);
|
|
|
|
|
if (!next_entry) {
|
|
|
|
|
next_node = b_btree_next(cur_node);
|
|
|
|
|
if (!next_node) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct b_dict_bucket *next_bucket
|
|
|
|
|
= b_unbox(struct b_dict_bucket, next_node, bk_node);
|
|
|
|
|
if (!next_bucket) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
next_entry = b_queue_first(&next_bucket->bk_items);
|
|
|
|
|
if (!next_entry) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct b_dict_bucket_item *next_item
|
|
|
|
|
= b_unbox(struct b_dict_bucket_item, next_entry, bi_entry);
|
|
|
|
|
if (!next_item) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*out_next_node = next_node;
|
|
|
|
|
*out_next_entry = next_entry;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool b_dict_iterator_next(b_dict_iterator *it)
|
|
|
|
|
{
|
|
|
|
|
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 -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct b_dict_bucket_item *next_item
|
|
|
|
|
= b_unbox(struct b_dict_bucket_item, next_entry, bi_entry);
|
|
|
|
|
|
|
|
|
|
if (!next_item) {
|
|
|
|
|
it->key = NULL;
|
|
|
|
|
it->value = NULL;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
it->i++;
|
|
|
|
|
it->key = next_item->bi_str;
|
|
|
|
|
it->value = next_item->bi_value;
|
|
|
|
|
|
|
|
|
|
it->_cbn = next_node;
|
|
|
|
|
it->_cqe = next_entry;
|
|
|
|
|
|
|
|
|
|
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)) {
|
|
|
|
|
return B_ERR_BAD_STATE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!it->key || !it->_cqe) {
|
|
|
|
|
return B_ERR_OUT_OF_BOUNDS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct b_dict_bucket *cur_bucket
|
|
|
|
|
= b_unbox(struct b_dict_bucket, it->_cbn, bk_node);
|
|
|
|
|
struct b_dict_bucket_item *cur_item
|
|
|
|
|
= b_unbox(struct b_dict_bucket_item, it->_cqe, bi_entry);
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
if (B_ERR(status)) {
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (next_item) {
|
|
|
|
|
it->key = next_item->bi_str;
|
|
|
|
|
it->value = next_item->bi_value;
|
|
|
|
|
|
|
|
|
|
it->_cbn = next_node;
|
|
|
|
|
it->_cqe = next_entry;
|
|
|
|
|
} else {
|
|
|
|
|
it->key = NULL;
|
|
|
|
|
it->value = NULL;
|
|
|
|
|
|
|
|
|
|
it->_cbn = NULL;
|
|
|
|
|
it->_cqe = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return B_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool b_dict_iterator_is_valid(const struct b_dict_iterator *it)
|
|
|
|
|
{
|
|
|
|
|
return it->key != NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-09 19:57:42 +01:00
|
|
|
static void dict_release(struct b_dsref *obj)
|
2024-10-24 19:24:54 +01:00
|
|
|
{
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-09 19:57:42 +01:00
|
|
|
b_dsref_type_id b_dict_type_id(void)
|
2024-10-24 19:24:54 +01:00
|
|
|
{
|
2025-08-09 19:57:42 +01:00
|
|
|
return (b_dsref_type_id)&dict_type;
|
2024-10-24 19:24:54 +01:00
|
|
|
}
|