summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/apr_hash.h14
-rw-r--r--tables/apr_hash.c19
-rw-r--r--test/testhash.c29
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);