diff options
Diffstat (limited to '')
-rw-r--r-- | src/lib/str-table.c | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/src/lib/str-table.c b/src/lib/str-table.c new file mode 100644 index 0000000..10eddd6 --- /dev/null +++ b/src/lib/str-table.c @@ -0,0 +1,78 @@ +/* Copyright (c) 2014-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "hash.h" +#include "str-table.h" + +struct str_table { + HASH_TABLE(char *, void *) hash; +}; + +struct str_table *str_table_init(void) +{ + struct str_table *table; + + table = i_new(struct str_table, 1); + hash_table_create(&table->hash, default_pool, 0, str_hash, strcmp); + return table; +} + +void str_table_deinit(struct str_table **_table) +{ + struct str_table *table = *_table; + struct hash_iterate_context *iter; + char *key; + void *value; + + *_table = NULL; + + iter = hash_table_iterate_init(table->hash); + while (hash_table_iterate(iter, table->hash, &key, &value)) + i_free(key); + hash_table_iterate_deinit(&iter); + hash_table_destroy(&table->hash); + i_free(table); +} + +bool str_table_is_empty(struct str_table *table) +{ + return hash_table_count(table->hash) == 0; +} + +const char *str_table_ref(struct str_table *table, const char *str) +{ + char *key; + void *value; + unsigned int ref; + + if (!hash_table_lookup_full(table->hash, str, &key, &value)) { + key = i_strdup(str); + ref = 1; + } else { + ref = POINTER_CAST_TO(value, unsigned int); + i_assert(ref > 0); + ref++; + } + hash_table_update(table->hash, key, POINTER_CAST(ref)); + return key; +} + +void str_table_unref(struct str_table *table, const char **str) +{ + char *key; + void *value; + unsigned int ref; + + if (!hash_table_lookup_full(table->hash, *str, &key, &value)) + i_unreached(); + + ref = POINTER_CAST_TO(value, unsigned int); + i_assert(ref > 0); + if (--ref > 0) + hash_table_update(table->hash, key, POINTER_CAST(ref)); + else { + hash_table_remove(table->hash, key); + i_free(key); + } + *str = NULL; +} |