diff options
-rw-r--r-- | include/apr_hash.h | 14 | ||||
-rw-r--r-- | tables/apr_hash.c | 19 | ||||
-rw-r--r-- | test/testhash.c | 29 |
3 files changed, 62 insertions, 0 deletions
diff --git a/include/apr_hash.h b/include/apr_hash.h index 37d972f9d..7ad9380eb 100644 --- a/include/apr_hash.h +++ b/include/apr_hash.h @@ -118,6 +118,20 @@ APR_DECLARE(void *) apr_hash_get(apr_hash_t *ht, const void *key, apr_ssize_t klen); /** + * Look up the value associated with a key in a hash table, or if none exists + * associate a value. + * @param ht The hash table + * @param key Pointer to the key + * @param klen Length of the key. Can be APR_HASH_KEY_STRING to use the string + * length. + * @param val Value to associate with the key (if none exists). + * @return Returns the existing value if any, the given value otherwise. + * @remark If the given value is NULL and a hash entry exists, nothing is done. + */ +APR_DECLARE(void *) apr_hash_get_or_set(apr_hash_t *ht, const void *key, + apr_ssize_t klen, const void *val); + +/** * Start iterating over the entries in a hash table. * @param p The pool to allocate the apr_hash_index_t iterator. If this * pool is NULL, then an internal, non-thread-safe iterator is used. diff --git a/tables/apr_hash.c b/tables/apr_hash.c index 0bf4d28c2..d4567710d 100644 --- a/tables/apr_hash.c +++ b/tables/apr_hash.c @@ -399,6 +399,25 @@ APR_DECLARE(void) apr_hash_set(apr_hash_t *ht, /* else key not present and val==NULL */ } +APR_DECLARE(void *) apr_hash_get_or_set(apr_hash_t *ht, + const void *key, + apr_ssize_t klen, + const void *val) +{ + apr_hash_entry_t **hep; + hep = find_entry(ht, key, klen, val); + if (*hep) { + val = (*hep)->val; + /* check that the collision rate isn't too high */ + if (ht->count > ht->max) { + expand_array(ht); + } + return (void *)val; + } + /* else key not present and val==NULL */ + return NULL; +} + APR_DECLARE(unsigned int) apr_hash_count(apr_hash_t *ht) { return ht->count; diff --git a/test/testhash.c b/test/testhash.c index 3c8419024..9dd5804b8 100644 --- a/test/testhash.c +++ b/test/testhash.c @@ -97,6 +97,34 @@ static void hash_set(abts_case *tc, void *data) ABTS_STR_EQUAL(tc, "value", result); } +static void hash_get_or_set(abts_case *tc, void *data) +{ + apr_hash_t *h = NULL; + char *result = NULL; + + h = apr_hash_make(p); + ABTS_PTR_NOTNULL(tc, h); + + result = apr_hash_get_or_set(h, "key", APR_HASH_KEY_STRING, "value"); + ABTS_STR_EQUAL(tc, "value", result); + + result = apr_hash_get_or_set(h, "key", APR_HASH_KEY_STRING, "other"); + ABTS_STR_EQUAL(tc, "value", result); + + result = apr_hash_get_or_set(h, "key", APR_HASH_KEY_STRING, NULL); + ABTS_STR_EQUAL(tc, "value", result); + + apr_hash_set(h, "key", APR_HASH_KEY_STRING, NULL); + result = apr_hash_get(h, "key", APR_HASH_KEY_STRING); + ABTS_PTR_EQUAL(tc, NULL, result); + + result = apr_hash_get_or_set(h, "key", APR_HASH_KEY_STRING, NULL); + ABTS_PTR_EQUAL(tc, NULL, result); + + result = apr_hash_get_or_set(h, "key", APR_HASH_KEY_STRING, "other"); + ABTS_STR_EQUAL(tc, "other", result); +} + static void hash_reset(abts_case *tc, void *data) { apr_hash_t *h = NULL; @@ -517,6 +545,7 @@ abts_suite *testhash(abts_suite *suite) abts_run_test(suite, hash_make, NULL); abts_run_test(suite, hash_set, NULL); + abts_run_test(suite, hash_get_or_set, NULL); abts_run_test(suite, hash_reset, NULL); abts_run_test(suite, same_value, NULL); abts_run_test(suite, same_value_custom, NULL); |