[Core, mod_hash] Add two APIs switch_core_hash_insert_alloc_destructor and switch_core_hash_insert_dup_destructor. Code cleanup in mod_hash. Add unit-tests.

This commit is contained in:
Andrey Volk 2021-01-27 02:53:16 +03:00
parent f92368d2f2
commit 1b048a8a97
4 changed files with 113 additions and 16 deletions

View File

@ -1457,6 +1457,28 @@ SWITCH_DECLARE(switch_status_t) switch_core_hash_insert_auto_free(switch_hash_t
SWITCH_DECLARE(switch_status_t) switch_core_hash_insert_destructor(_In_ switch_hash_t *hash, _In_z_ const char *key, _In_opt_ const void *data, hashtable_destructor_t destructor);
#define switch_core_hash_insert(_h, _k, _d) switch_core_hash_insert_destructor(_h, _k, _d, NULL)
/*!
\brief Allocate memory and insert into a hash
\param hash the hash to add data to
\param key the name of the key to add the data to
\param size the size in bytes to allocate
\return pointer to the allocated memory
\note the string key must be a constant or a dynamic string
*/
SWITCH_DECLARE(void *) switch_core_hash_insert_alloc_destructor(_In_ switch_hash_t *hash, _In_z_ const char *key, _In_opt_ size_t size, hashtable_destructor_t destructor);
#define switch_core_hash_insert_alloc(_h, _k, _s) switch_core_hash_insert_alloc_destructor(_h, _k, _s, NULL)
/*!
\brief Insert strdup(data) into a hash
\param hash the hash to add data to
\param key the name of the key to add the data to
\param data string to strdup and add
\return SWITCH_STATUS_SUCCESS if the data is added
\note the string key must be a constant or a dynamic string
*/
SWITCH_DECLARE(switch_status_t) switch_core_hash_insert_dup_destructor(_In_ switch_hash_t *hash, _In_z_ const char *key, _In_opt_ const char *str, hashtable_destructor_t destructor);
#define switch_core_hash_insert_dup(_h, _k, _d) switch_core_hash_insert_dup_destructor(_h, _k, _d, NULL)
/*!
\brief Insert data into a hash

View File

@ -144,10 +144,7 @@ SWITCH_LIMIT_INCR(limit_incr_hash)
if (!(item = (limit_hash_item_t *) switch_core_hash_find(globals.limit_hash, hashkey))) {
/* No, create an empty structure and add it, then continue like as if it existed */
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG10, "Creating new limit structure: key: %s\n", hashkey);
item = (limit_hash_item_t *) malloc(sizeof(limit_hash_item_t));
switch_assert(item);
memset(item, 0, sizeof(limit_hash_item_t));
switch_core_hash_insert(globals.limit_hash, hashkey, item);
item = (limit_hash_item_t *)switch_core_hash_insert_alloc(globals.limit_hash, hashkey, sizeof(limit_hash_item_t));
}
if (!(pvt = switch_channel_get_private(channel, "limit_hash"))) {
@ -433,17 +430,13 @@ SWITCH_STANDARD_APP(hash_function)
free(value);
switch_core_hash_delete(globals.db_hash, hash_key);
}
value = strdup(argv[3]);
switch_assert(value);
switch_core_hash_insert(globals.db_hash, hash_key, value);
switch_core_hash_insert_dup(globals.db_hash, hash_key, argv[3]);
} else if (!strcasecmp(argv[0], "insert_ifempty")) {
if (argc < 4) {
goto usage;
}
if (!(value = switch_core_hash_find(globals.db_hash, hash_key))) {
value = strdup(argv[3]);
switch_assert(value);
switch_core_hash_insert(globals.db_hash, hash_key, value);
switch_core_hash_insert_dup(globals.db_hash, hash_key, argv[3]);
}
} else if (!strcasecmp(argv[0], "delete")) {
@ -506,9 +499,7 @@ SWITCH_STANDARD_API(hash_api_function)
switch_safe_free(value);
switch_core_hash_delete(globals.db_hash, hash_key);
}
value = strdup(argv[3]);
switch_assert(value);
switch_core_hash_insert(globals.db_hash, hash_key, value);
switch_core_hash_insert_dup(globals.db_hash, hash_key, argv[3]);
stream->write_function(stream, "+OK\n");
switch_thread_rwlock_unlock(globals.db_hash_rwlock);
} else if (!strcasecmp(argv[0], "insert_ifempty")) {
@ -519,9 +510,7 @@ SWITCH_STANDARD_API(hash_api_function)
if ((value = switch_core_hash_find(globals.db_hash, hash_key))) {
stream->write_function(stream, "-ERR key already exists\n");
} else {
value = strdup(argv[3]);
switch_assert(value);
switch_core_hash_insert(globals.db_hash, hash_key, value);
switch_core_hash_insert_dup(globals.db_hash, hash_key, argv[3]);
stream->write_function(stream, "+OK\n");
}
switch_thread_rwlock_unlock(globals.db_hash_rwlock);

View File

@ -68,6 +68,45 @@ SWITCH_DECLARE(switch_status_t) switch_core_hash_insert_auto_free(switch_hash_t
return SWITCH_STATUS_FALSE;
}
SWITCH_DECLARE(void *) switch_core_hash_insert_alloc_destructor(_In_ switch_hash_t *hash, _In_z_ const char *key, _In_opt_ size_t size, hashtable_destructor_t destructor) {
char *dkey;
void *data;
if (!size) return NULL;
dkey = strdup(key);
data = malloc(size);
assert(data);
if (switch_hashtable_insert_destructor(hash, dkey, data, HASHTABLE_FLAG_FREE_KEY | HASHTABLE_DUP_CHECK, destructor)) {
memset(data, 0, size);
return data;
}
free(data);
switch_safe_free(dkey);
return NULL;
}
SWITCH_DECLARE(switch_status_t) switch_core_hash_insert_dup_destructor(switch_hash_t *hash, const char *key, const char *str, hashtable_destructor_t destructor)
{
char *dkey = strdup(key);
char *dup = strdup(str);
assert(dup);
if (switch_hashtable_insert_destructor(hash, dkey, (void *)dup, HASHTABLE_FLAG_FREE_KEY | HASHTABLE_DUP_CHECK, destructor)) {
return SWITCH_STATUS_SUCCESS;
}
switch_safe_free(dup);
switch_safe_free(dkey);
return SWITCH_STATUS_FALSE;
}
SWITCH_DECLARE(switch_status_t) switch_core_hash_insert_destructor(switch_hash_t *hash, const char *key, const void *data, hashtable_destructor_t destructor)
{
char *dkey = strdup(key);

View File

@ -267,6 +267,53 @@ FST_CORE_BEGIN("./conf")
fst_check_int_equals(switch_safe_atoll(0, 3), 3);
}
FST_TEST_END()
FST_TEST_BEGIN(test_switch_core_hash_insert_dup)
{
char *magicnumber = malloc(9);
switch_hash_index_t *hi;
switch_hash_t *hash = NULL;
void *hash_val;
switch_core_hash_init(&hash);
fst_requires(hash);
snprintf(magicnumber, 9, "%s", "DEADBEEF");
switch_core_hash_insert_dup(hash, "test", (const char *)magicnumber);
snprintf(magicnumber, 9, "%s", "BAADF00D");
hi = switch_core_hash_first(hash);
switch_core_hash_this(hi, NULL, NULL, &hash_val);
fst_check_string_equals(hash_val, "DEADBEEF");
switch_safe_free(hash_val);
free(magicnumber);
free(hi);
switch_core_hash_destroy(&hash);
fst_requires(hash == NULL);
}
FST_TEST_END()
FST_TEST_BEGIN(test_switch_core_hash_insert_alloc)
{
char *item;
switch_hash_index_t *hi;
switch_hash_t *hash = NULL;
void *hash_val;
switch_core_hash_init(&hash);
fst_requires(hash);
item = switch_core_hash_insert_alloc(hash, "test", 10);
fst_requires(item);
snprintf(item, 9, "%s", "DEADBEEF");
hi = switch_core_hash_first(hash);
switch_core_hash_this(hi, NULL, NULL, &hash_val);
fst_check_string_equals(hash_val, "DEADBEEF");
free(hi);
switch_core_hash_destroy(&hash);
fst_requires(hash == NULL);
free(item);
}
FST_TEST_END()
}
FST_SUITE_END()
}