Hello,

I'm currently working on a code with a quite painful pattern (hot path) :

    value = apr_hash_get(key);
    if (value == NULL) {
        value = make_new_value();
        apr_hash_set(key, value)
    }

and would be interested in having the following apr_hash_get_or_set()
function to do something like :

    value = apr_hash_get_or_set(key, ctx->spare_value);
    if (value == ctx->spare_value) {
        ctx->spare_value = make_new_value();
    }

Do you think this is suitable for APR (possibly 1.6)?

Index: tables/apr_hash.c
===================================================================
--- tables/apr_hash.c    (revision 1627394)
+++ tables/apr_hash.c    (working copy)
@@ -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;
Index: include/apr_hash.h
===================================================================
--- include/apr_hash.h    (revision 1627394)
+++ include/apr_hash.h    (working copy)
@@ -118,6 +118,20 @@ APR_DECLARE(void *) apr_hash_get(apr_hash_t *ht, c
                                  apr_ssize_t klen);

 /**
+ * Look up the value associated with a key in a hash table, or associate the
+ * given value if none exists.
+ * @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.
[END]

Regards,
Yann.

Reply via email to