From 639587335dfe5d66dc7034817b3e685458ecbee1 Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Thu, 13 Nov 2014 02:24:46 +0200 Subject: [PATCH] lib: Added str-table API for keeping reference counted strings in a hash table. --- src/lib/Makefile.am | 3 ++ src/lib/str-table.c | 77 ++++++++++++++++++++++++++++++++++++++++ src/lib/str-table.h | 19 ++++++++++ src/lib/test-lib.c | 1 + src/lib/test-lib.h | 1 + src/lib/test-str-table.c | 33 +++++++++++++++++ 6 files changed, 134 insertions(+) create mode 100644 src/lib/str-table.c create mode 100644 src/lib/str-table.h create mode 100644 src/lib/test-str-table.c diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index d1d0edc51c..ae2f8e0989 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -126,6 +126,7 @@ liblib_la_SOURCES = \ str.c \ str-find.c \ str-sanitize.c \ + str-table.c \ strescape.c \ strfuncs.c \ strnum.c \ @@ -247,6 +248,7 @@ headers = \ str.h \ str-find.h \ str-sanitize.h \ + str-table.h \ strescape.h \ strfuncs.h \ strnum.h \ @@ -311,6 +313,7 @@ test_lib_SOURCES = \ test-strnum.c \ test-str-find.c \ test-str-sanitize.c \ + test-str-table.c \ test-time-util.c \ test-unichar.c \ test-utc-mktime.c \ diff --git a/src/lib/str-table.c b/src/lib/str-table.c new file mode 100644 index 0000000000..9ee7c654e9 --- /dev/null +++ b/src/lib/str-table.c @@ -0,0 +1,77 @@ +/* Copyright (c) 2014 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_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; +} diff --git a/src/lib/str-table.h b/src/lib/str-table.h new file mode 100644 index 0000000000..55111a6fde --- /dev/null +++ b/src/lib/str-table.h @@ -0,0 +1,19 @@ +#ifndef STR_TABLE_H +#define STR_TABLE_H + +/* Hash table containing string -> refcount. */ + +struct str_table *str_table_init(void); +void str_table_deinit(struct str_table **table); + +/* Returns TRUE if there are no referenced strings in the table. */ +bool str_table_is_empty(struct str_table *table); + +/* Return string allocated from the strtable and increase its reference + count. */ +const char *str_table_ref(struct str_table *table, const char *str); +/* Decrease string's reference count, freeing it if it reaches zero. + The str pointer must have been returned by the str_table_ref(). */ +void str_table_unref(struct str_table *table, const char **str); + +#endif diff --git a/src/lib/test-lib.c b/src/lib/test-lib.c index 693b9fde34..8083e0f769 100644 --- a/src/lib/test-lib.c +++ b/src/lib/test-lib.c @@ -42,6 +42,7 @@ int main(void) test_strnum, test_str_find, test_str_sanitize, + test_str_table, test_time_util, test_unichar, test_utc_mktime, diff --git a/src/lib/test-lib.h b/src/lib/test-lib.h index b1d5b48288..8fd07c332e 100644 --- a/src/lib/test-lib.h +++ b/src/lib/test-lib.h @@ -44,6 +44,7 @@ void test_strfuncs(void); void test_strnum(void); void test_str_find(void); void test_str_sanitize(void); +void test_str_table(void); void test_time_util(void); void test_unichar(void); void test_utc_mktime(void); diff --git a/src/lib/test-str-table.c b/src/lib/test-str-table.c new file mode 100644 index 0000000000..ae44d89a5b --- /dev/null +++ b/src/lib/test-str-table.c @@ -0,0 +1,33 @@ +/* Copyright (c) 2014 Dovecot authors, see the included COPYING file */ + +#include "test-lib.h" +#include "str-table.h" + +void test_str_table(void) +{ + struct str_table *table; + const char *key1, *key2, *key1_copy, *key2_copy; + + test_begin("str_table"); + table = str_table_init(); + + key1 = str_table_ref(table, "str1"); + key2 = str_table_ref(table, "str2"); + test_assert(key1 != key2); + key1_copy = str_table_ref(table, "str1"); + test_assert(key1_copy == key1); + key2_copy = str_table_ref(table, "str2"); + test_assert(key2_copy == key2); + + str_table_unref(table, &key1); + test_assert(key1 == NULL); + str_table_unref(table, &key1_copy); + + str_table_unref(table, &key2); + str_table_unref(table, &key2_copy); + test_assert(str_table_is_empty(table)); + + str_table_deinit(&table); + test_assert(table == NULL); + test_end(); +} -- 2.47.3