Refactor and simplify isc_symtab
This commit does several changes to isc_symtab: 1. Rewrite the isc_symtab to internally use isc_hashmap instead of hand-stiched hashtable. 2. Create a new isc_symtab_define_and_return() api, which returns the already defined symvalue on ISC_R_EXISTS; this allows users of the API to skip the isc_symtab_lookup()+isc_symtab_define() calls and directly call isc_symtab_define_and_return(). 3. Merge isccc_symtab into isc_symtab - the only missing function was isccc_symtab_foreach() that was merged into isc_symtab API. 4. Add full set of unit tests for the isc_symtab API.
This commit is contained in:
@@ -28,105 +28,254 @@
|
||||
|
||||
#include <tests/isc.h>
|
||||
|
||||
static void
|
||||
undefine(char *key, unsigned int type, isc_symvalue_t value, void *arg) {
|
||||
UNUSED(arg);
|
||||
#define TEST_NITEMS 10000
|
||||
|
||||
assert_int_equal(type, 1);
|
||||
static void
|
||||
undefine(char *key, unsigned int type ISC_ATTR_UNUSED, isc_symvalue_t value,
|
||||
void *arg ISC_ATTR_UNUSED) {
|
||||
isc_mem_free(mctx, key);
|
||||
isc_mem_free(mctx, value.as_pointer);
|
||||
}
|
||||
|
||||
/* test symbol table growth */
|
||||
ISC_RUN_TEST_IMPL(symtab_grow) {
|
||||
ISC_RUN_TEST_IMPL(symtab_define) {
|
||||
isc_result_t result;
|
||||
isc_symtab_t *st = NULL;
|
||||
isc_symtab_t *symtab = NULL;
|
||||
isc_symvalue_t value;
|
||||
isc_symvalue_t found;
|
||||
isc_symexists_t policy = isc_symexists_reject;
|
||||
char str[16], *key;
|
||||
snprintf(str, sizeof(str), "%p", "define");
|
||||
key = isc_mem_strdup(mctx, str);
|
||||
|
||||
isc_symtab_create(mctx, undefine, NULL, false, &symtab);
|
||||
assert_non_null(symtab);
|
||||
|
||||
value.as_pointer = isc_mem_strdup(mctx, key);
|
||||
assert_non_null(value.as_pointer);
|
||||
|
||||
result = isc_symtab_define(symtab, key, 1, value, policy);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
|
||||
result = isc_symtab_lookup(symtab, key, 1, &found);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
assert_string_equal(value.as_pointer, found.as_pointer);
|
||||
|
||||
result = isc_symtab_lookup(symtab, key, 2, NULL);
|
||||
assert_int_equal(result, ISC_R_NOTFOUND);
|
||||
|
||||
isc_symtab_destroy(&symtab);
|
||||
}
|
||||
|
||||
ISC_RUN_TEST_IMPL(symtab_undefine) {
|
||||
isc_result_t result;
|
||||
isc_symtab_t *symtab = NULL;
|
||||
isc_symvalue_t value;
|
||||
isc_symexists_t policy = isc_symexists_reject;
|
||||
int i;
|
||||
|
||||
UNUSED(state);
|
||||
/* We need a separate copy of the key to prevent an use-after-free */
|
||||
char str[16], *key, *key_after_undefine;
|
||||
snprintf(str, sizeof(str), "%p", "undefine");
|
||||
|
||||
isc_symtab_create(mctx, 3, undefine, NULL, false, &st);
|
||||
assert_non_null(st);
|
||||
key = isc_mem_strdup(mctx, str);
|
||||
key_after_undefine = isc_mem_strdup(mctx, str);
|
||||
|
||||
isc_symtab_create(mctx, undefine, NULL, false, &symtab);
|
||||
assert_non_null(symtab);
|
||||
|
||||
value.as_pointer = isc_mem_strdup(mctx, key);
|
||||
assert_non_null(value.as_pointer);
|
||||
|
||||
result = isc_symtab_define(symtab, key, 1, value, policy);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
|
||||
result = isc_symtab_lookup(symtab, key_after_undefine, 1, NULL);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
|
||||
result = isc_symtab_undefine(symtab, key, 1);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
|
||||
result = isc_symtab_lookup(symtab, key_after_undefine, 1, NULL);
|
||||
assert_int_equal(result, ISC_R_NOTFOUND);
|
||||
|
||||
isc_symtab_destroy(&symtab);
|
||||
|
||||
/* key will be freed by isc_symtab_undefine, so we don't need to free
|
||||
* it again
|
||||
*/
|
||||
isc_mem_free(mctx, key_after_undefine);
|
||||
}
|
||||
|
||||
ISC_RUN_TEST_IMPL(symtab_replace) {
|
||||
isc_result_t result;
|
||||
isc_symtab_t *symtab = NULL;
|
||||
isc_symvalue_t value1;
|
||||
isc_symvalue_t value2;
|
||||
isc_symvalue_t found;
|
||||
isc_symexists_t policy = isc_symexists_replace;
|
||||
char str[16], *key1, *key2;
|
||||
snprintf(str, sizeof(str), "%p", "replace");
|
||||
key1 = isc_mem_strdup(mctx, str);
|
||||
key2 = isc_mem_strdup(mctx, str);
|
||||
|
||||
isc_symtab_create(mctx, undefine, NULL, false, &symtab);
|
||||
assert_non_null(symtab);
|
||||
|
||||
value1.as_pointer = isc_mem_strdup(mctx, key1);
|
||||
assert_non_null(value1.as_pointer);
|
||||
|
||||
value2.as_pointer = isc_mem_strdup(mctx, key2);
|
||||
assert_non_null(value2.as_pointer);
|
||||
|
||||
result = isc_symtab_define(symtab, key1, 1, value1, policy);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
|
||||
result = isc_symtab_lookup(symtab, key1, 1, &found);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
assert_string_equal(value1.as_pointer, found.as_pointer);
|
||||
|
||||
result = isc_symtab_define(symtab, key2, 1, value2, policy);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
|
||||
result = isc_symtab_lookup(symtab, key2, 1, &found);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
assert_string_equal(value2.as_pointer, found.as_pointer);
|
||||
|
||||
result = isc_symtab_undefine(symtab, key2, 1);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
|
||||
isc_symtab_destroy(&symtab);
|
||||
}
|
||||
|
||||
ISC_RUN_TEST_IMPL(symtab_reject) {
|
||||
isc_result_t result;
|
||||
isc_symtab_t *symtab = NULL;
|
||||
isc_symvalue_t value1;
|
||||
isc_symvalue_t value2;
|
||||
isc_symvalue_t found;
|
||||
isc_symexists_t policy = isc_symexists_reject;
|
||||
char str[16], *key1, *key2;
|
||||
snprintf(str, sizeof(str), "%p", "reject");
|
||||
key1 = isc_mem_strdup(mctx, str);
|
||||
key2 = isc_mem_strdup(mctx, str);
|
||||
|
||||
isc_symtab_create(mctx, undefine, NULL, false, &symtab);
|
||||
assert_non_null(symtab);
|
||||
|
||||
value1.as_pointer = isc_mem_strdup(mctx, key1);
|
||||
assert_non_null(value1.as_pointer);
|
||||
|
||||
value2.as_pointer = isc_mem_strdup(mctx, key2);
|
||||
assert_non_null(value2.as_pointer);
|
||||
|
||||
result = isc_symtab_define(symtab, key1, 1, value1, policy);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
|
||||
result = isc_symtab_lookup(symtab, key1, 1, &found);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
assert_string_equal(value1.as_pointer, found.as_pointer);
|
||||
|
||||
result = isc_symtab_define_and_return(symtab, key2, 1, value2, policy,
|
||||
&found);
|
||||
assert_int_equal(result, ISC_R_EXISTS);
|
||||
assert_string_equal(value1.as_pointer, found.as_pointer);
|
||||
|
||||
result = isc_symtab_lookup(symtab, key2, 1, &found);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
assert_string_equal(value1.as_pointer, found.as_pointer);
|
||||
|
||||
result = isc_symtab_undefine(symtab, key1, 1);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
|
||||
undefine(key2, 1, value2, NULL);
|
||||
|
||||
isc_symtab_destroy(&symtab);
|
||||
}
|
||||
|
||||
static bool
|
||||
peek(char *key ISC_ATTR_UNUSED, unsigned int type,
|
||||
isc_symvalue_t value ISC_ATTR_UNUSED, void *arg) {
|
||||
bool *seen = arg;
|
||||
size_t i = type - 1;
|
||||
|
||||
assert_false(seen[i]);
|
||||
|
||||
seen[i] = true;
|
||||
|
||||
return i % 2;
|
||||
}
|
||||
|
||||
ISC_RUN_TEST_IMPL(symtab_foreach) {
|
||||
isc_result_t result;
|
||||
isc_symtab_t *symtab = NULL;
|
||||
isc_symvalue_t value;
|
||||
isc_symexists_t policy = isc_symexists_reject;
|
||||
bool seen[TEST_NITEMS] = { 0 };
|
||||
|
||||
isc_symtab_create(mctx, undefine, NULL, false, &symtab);
|
||||
|
||||
/* Nothing should be in the table yet */
|
||||
assert_non_null(symtab);
|
||||
|
||||
/*
|
||||
* Put 1024 entries in the table (this should necessate
|
||||
* regrowing the hash table several times
|
||||
* Put TEST_NITEMS entries in the table.
|
||||
*/
|
||||
for (i = 0; i < 1024; i++) {
|
||||
char str[16], *key;
|
||||
for (size_t i = 0; i < TEST_NITEMS; i++) {
|
||||
char str[256] = {}, *key;
|
||||
|
||||
snprintf(str, sizeof(str), "%08zx", i);
|
||||
|
||||
snprintf(str, sizeof(str), "%04x", i);
|
||||
key = isc_mem_strdup(mctx, str);
|
||||
assert_non_null(key);
|
||||
value.as_pointer = isc_mem_strdup(mctx, str);
|
||||
assert_non_null(value.as_pointer);
|
||||
result = isc_symtab_define(st, key, 1, value, policy);
|
||||
result = isc_symtab_define(symtab, key, i + 1, value, policy);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
undefine(key, 1, value, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to put them in again; this should fail
|
||||
*/
|
||||
for (i = 0; i < 1024; i++) {
|
||||
char str[16], *key;
|
||||
|
||||
snprintf(str, sizeof(str), "%04x", i);
|
||||
key = isc_mem_strdup(mctx, str);
|
||||
assert_non_null(key);
|
||||
value.as_pointer = isc_mem_strdup(mctx, str);
|
||||
assert_non_null(value.as_pointer);
|
||||
result = isc_symtab_define(st, key, 1, value, policy);
|
||||
assert_int_equal(result, ISC_R_EXISTS);
|
||||
undefine(key, 1, value, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve them; this should succeed
|
||||
*/
|
||||
for (i = 0; i < 1024; i++) {
|
||||
char str[16];
|
||||
for (size_t i = 0; i < TEST_NITEMS; i++) {
|
||||
char str[256] = {};
|
||||
|
||||
snprintf(str, sizeof(str), "%04x", i);
|
||||
result = isc_symtab_lookup(st, str, 0, &value);
|
||||
snprintf(str, sizeof(str), "%08zx", i);
|
||||
result = isc_symtab_lookup(symtab, str, i + 1, &value);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
assert_string_equal(str, (char *)value.as_pointer);
|
||||
}
|
||||
|
||||
/*
|
||||
* Undefine them
|
||||
* Undefine even items them via foreach
|
||||
*/
|
||||
for (i = 0; i < 1024; i++) {
|
||||
char str[16];
|
||||
isc_symtab_foreach(symtab, peek, seen);
|
||||
|
||||
snprintf(str, sizeof(str), "%04x", i);
|
||||
result = isc_symtab_undefine(st, str, 1);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
for (size_t i = 0; i < TEST_NITEMS; i++) {
|
||||
assert_true(seen[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve them again; this should fail
|
||||
* Destroy the even ones by hand.
|
||||
*/
|
||||
for (i = 0; i < 1024; i++) {
|
||||
char str[16];
|
||||
for (size_t i = 0; i < TEST_NITEMS; i++) {
|
||||
if (i % 2 == 0) {
|
||||
char str[256] = {};
|
||||
|
||||
snprintf(str, sizeof(str), "%04x", i);
|
||||
result = isc_symtab_lookup(st, str, 0, &value);
|
||||
assert_int_equal(result, ISC_R_NOTFOUND);
|
||||
snprintf(str, sizeof(str), "%08zx", i);
|
||||
result = isc_symtab_undefine(symtab, str, i + 1);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
isc_symtab_destroy(&st);
|
||||
isc_symtab_destroy(&symtab);
|
||||
}
|
||||
|
||||
ISC_TEST_LIST_START
|
||||
|
||||
ISC_TEST_ENTRY(symtab_grow)
|
||||
ISC_TEST_ENTRY(symtab_define)
|
||||
ISC_TEST_ENTRY(symtab_undefine)
|
||||
ISC_TEST_ENTRY(symtab_reject)
|
||||
ISC_TEST_ENTRY(symtab_replace)
|
||||
ISC_TEST_ENTRY(symtab_foreach)
|
||||
|
||||
ISC_TEST_LIST_END
|
||||
|
||||
|
||||
Reference in New Issue
Block a user