Here's apdated patch with more optimizations to apr_hash_copy based
on Greg's comments on the original.

--Brian


Index: srclib/apr/include/apr_hash.h
===================================================================
RCS file: /home/cvspublic/apr/include/apr_hash.h,v
retrieving revision 1.30
diff -u -r1.30 apr_hash.h
--- srclib/apr/include/apr_hash.h       2001/08/24 17:55:45     1.30
+++ srclib/apr/include/apr_hash.h       2001/11/07 14:53:50
@@ -105,6 +105,16 @@
 APR_DECLARE(apr_hash_t *) apr_hash_make(apr_pool_t *pool);
 
 /**
+ * Make a copy of a hash table
+ * @param pool The pool from which to allocate the new hash table
+ * @param h The hash table to clone
+ * @return The hash table just created
+ * @remark Makes a shallow copy
+ */
+APR_DECLARE(apr_hash_t *) apr_hash_copy(apr_pool_t *pool,
+                                        const apr_hash_t *h);
+
+/**
  * Associate a value with a key in a hash table.
  * @param ht The hash table
  * @param key Pointer to the key
@@ -192,6 +202,30 @@
 APR_DECLARE(apr_hash_t *) apr_hash_overlay(apr_pool_t *p,
                                            const apr_hash_t *overlay, 
                                            const apr_hash_t *base);
+
+/**
+ * Merge two hash tables into one new hash table. If the same key
+ * is present in both tables, call the supplied merge function to
+ * produce a merged value for the key in the new table.
+ * @param p The pool to use for the new hash table
+ * @param h1 The first of the tables to merge
+ * @param h2 The second of the tables to merge
+ * @param merger A callback function to merge values, or NULL to
+ *  make values from h1 override values from h2 (same semantics as
+ *  apr_hash_overlay())
+ * @param data Client data to pass to the merger function
+ * @return A new hash table containing all of the data from the two passed in
+ */
+APR_DECLARE(apr_hash_t *) apr_hash_merge(apr_pool_t *p,
+                                         const apr_hash_t *h1,
+                                         const apr_hash_t *h2,
+                                         void * (*merger)(apr_pool_t *p,
+                                                     const void *key,
+                                                     apr_ssize_t klen,
+                                                     const void *h1_val,
+                                                     const void *h2_val,
+                                                     const void *data),
+                                         const void *data);
 
 /**
  * Get a pointer to the pool which the hash table 
Index: srclib/apr/tables/apr_hash.c
===================================================================
RCS file: /home/cvspublic/apr/tables/apr_hash.c,v
retrieving revision 1.25
diff -u -r1.25 apr_hash.c
--- srclib/apr/tables/apr_hash.c        2001/09/06 06:34:59     1.25
+++ srclib/apr/tables/apr_hash.c        2001/11/07 14:53:51
@@ -289,6 +289,41 @@
     return hep;
 }
 
+APR_DECLARE(apr_hash_t *) apr_hash_copy(apr_pool_t *pool,
+                                        const apr_hash_t *orig)
+{
+    apr_hash_t *ht;
+    apr_hash_entry_t *new_vals;
+    int i, j;
+
+    ht = apr_palloc(pool, sizeof(apr_hash_t) +
+                    sizeof(*ht->array) * (orig->max + 1) +
+                    sizeof(apr_hash_entry_t) * orig->count);
+    ht->pool = pool;
+    ht->count = orig->count;
+    ht->max = orig->max;
+    ht->array = (apr_hash_entry_t **)((char *)ht + sizeof(apr_hash_t));
+
+    new_vals = (apr_hash_entry_t *)((char *)(ht) + sizeof(apr_hash_t) +
+                                    sizeof(*ht->array) * (orig->max + 1));
+    j = 0;
+    for (i = 0; i <= ht->max; i++) {
+        apr_hash_entry_t **new_entry = &(ht->array[i]);
+        apr_hash_entry_t *orig_entry = orig->array[i];
+        while (orig_entry) {
+            *new_entry = &new_vals[j++];
+            (*new_entry)->hash = orig_entry->hash;
+            (*new_entry)->key = orig_entry->key;
+            (*new_entry)->klen = orig_entry->klen;
+            (*new_entry)->val = orig_entry->val;
+            new_entry = &((*new_entry)->next);
+            orig_entry = orig_entry->next;
+        }
+        *new_entry = NULL;
+    }
+    return ht;
+}
+
 APR_DECLARE(void *) apr_hash_get(apr_hash_t *ht,
                               const void *key,
                               apr_ssize_t klen)
@@ -335,10 +370,25 @@
                                           const apr_hash_t *overlay, 
                                           const apr_hash_t *base)
 {
+    return apr_hash_merge(p, overlay, base, NULL, NULL);
+}
+
+APR_DECLARE(apr_hash_t *) apr_hash_merge(apr_pool_t *p,
+                                         const apr_hash_t *overlay, 
+                                         const apr_hash_t *base,
+                                         void * (*merger)(apr_pool_t *p,
+                                                     const void *key,
+                                                     apr_ssize_t klen,
+                                                     const void *h1_val,
+                                                     const void *h2_val,
+                                                     const void *data),
+                                         const void *data)
+{
     apr_hash_t *res;
-    apr_hash_index_t *hi;
     apr_hash_entry_t *new_vals;
-    int i,j;
+    apr_hash_entry_t *iter;
+    apr_hash_entry_t *ent;
+    int i,j,k;
 
 #ifdef POOL_DEBUG
     /* we don't copy keys and values, so it's necessary that
@@ -361,27 +411,54 @@
     res->pool = p;
     res->count = base->count;
     res->max = (overlay->max > base->max) ? overlay->max : base->max;
+    if (base->count + overlay->count > res->max) {
+        res->max = res->max * 2 + 1;
+    }
     res->array = alloc_array(res, res->max);
-    new_vals = apr_palloc(p, sizeof(apr_hash_entry_t) * res->count);
+    if (base->count + overlay->count) {
+        new_vals = apr_palloc(p, sizeof(apr_hash_entry_t) *
+                              (base->count + overlay->count));
+    }
     j = 0;
-    for (hi = apr_hash_first(NULL, (apr_hash_t*)base); hi; hi = 
apr_hash_next(hi)) {
-        i = hi->this->hash & res->max;
-
-        new_vals[j].klen = hi->this->klen;
-        new_vals[j].key = hi->this->key;
-        new_vals[j].val = hi->this->val;
-        new_vals[j].hash = hi->this->hash;
-        new_vals[j].next = res->array[i];
-        res->array[i] = &new_vals[j];
-        j++;
+    for (k = 0; k <= base->max; k++) {
+        for (iter = base->array[k]; iter; iter = iter->next) {
+            i = iter->hash & res->max;
+            new_vals[j].klen = iter->klen;
+            new_vals[j].key = iter->key;
+            new_vals[j].val = iter->val;
+            new_vals[j].hash = iter->hash;
+            new_vals[j].next = res->array[i];
+            res->array[i] = &new_vals[j];
+            j++;
+        }
     }
 
-    /* can't simply copy the stuff over, need to set each one so as to
-     * increment the counts/array properly
-     */
-    for (hi = apr_hash_first(NULL, (apr_hash_t*)overlay); hi; 
-         hi = apr_hash_next(hi)) {
-        apr_hash_set(res, hi->this->key, hi->this->klen, hi->this->val);
+    for (k = 0; k < overlay->max; k++) {
+        for (iter = overlay->array[k]; iter; iter = iter->next) {
+            i = iter->hash & res->max;
+            for (ent = res->array[i]; ent; ent = ent->next) {
+                if ((ent->klen == iter->klen) &&
+                    (memcmp(ent->key, iter->key, iter->klen) == 0)) {
+                    if (merger) {
+                        ent->val = (*merger)(p, iter->key, iter->klen,
+                                             iter->val, ent->val, data);
+                    }
+                    else {
+                        ent->val = iter->val;
+                    }
+                    break;
+                }
+            }
+            if (!ent) {
+                new_vals[j].klen = iter->klen;
+                new_vals[j].key = iter->key;
+                new_vals[j].val = iter->val;
+                new_vals[j].hash = iter->hash;
+                new_vals[j].next = res->array[i];
+                res->array[i] = &new_vals[j];
+                j++;
+            }
+        }
     }
     return res;
 }
Index: modules/http/mod_mime.c
===================================================================
RCS file: /home/cvspublic/httpd-2.0/modules/http/mod_mime.c,v
retrieving revision 1.68
diff -u -r1.68 mod_mime.c
--- modules/http/mod_mime.c     2001/10/15 02:39:37     1.68
+++ modules/http/mod_mime.c     2001/11/07 14:53:51
@@ -166,52 +166,41 @@
 /*
  * Overlay one hash table of extension_mappings onto another
  */
-static void overlay_extension_mappings(apr_pool_t *p,
-                                       apr_hash_t *overlay, apr_hash_t *base)
+static void *overlay_extension_mappings(apr_pool_t *p,
+                                        const void *key,
+                                        apr_ssize_t klen,
+                                        const void *overlay_val,
+                                        const void *base_val,
+                                        const void *data)
 {
-    apr_hash_index_t *index;
-    for (index = apr_hash_first(p, overlay); index;
-         index = apr_hash_next(index)) {
-        char *key;
-        apr_ssize_t klen;
-        extension_info *overlay_info, *base_info;
-        
-        apr_hash_this(index, (const void**)&key, &klen, (void**)&overlay_info);
-
-        base_info = (extension_info*)apr_hash_get(base, key, klen);
-
-        if (base_info) {
-            extension_info *copyinfo = base_info;
-            base_info = (extension_info*)apr_palloc(p, sizeof(*base_info));
-            apr_hash_set(base, key, klen, base_info);
-            memcpy(base_info, copyinfo, sizeof(*base_info));
-
-            if (overlay_info->forced_type) {
-                base_info->forced_type = overlay_info->forced_type;
-            }
-            if (overlay_info->encoding_type) {
-                base_info->encoding_type = overlay_info->encoding_type;
-            }
-            if (overlay_info->language_type) {
-                base_info->language_type = overlay_info->language_type;
-            }
-            if (overlay_info->handler) {
-                base_info->handler = overlay_info->handler;
-            }
-            if (overlay_info->charset_type) {
-                base_info->charset_type = overlay_info->charset_type;
-            }
-            if (overlay_info->input_filters) {
-                base_info->input_filters = overlay_info->input_filters;
-            }
-            if (overlay_info->output_filters) {
-                base_info->output_filters = overlay_info->output_filters;
-            }
-        }
-        else {
-            apr_hash_set(base, key, klen, overlay_info);
-        }
+    extension_info *new_info = apr_palloc(p, sizeof(extension_info));
+    const extension_info *overlay_info = (const extension_info *)overlay_val;
+    const extension_info *base_info = (const extension_info *)base_val;
+
+    memcpy(new_info, base_info, sizeof(extension_info));
+    if (overlay_info->forced_type) {
+        new_info->forced_type = overlay_info->forced_type;
+    }
+    if (overlay_info->encoding_type) {
+        new_info->encoding_type = overlay_info->encoding_type;
+    }
+    if (overlay_info->language_type) {
+        new_info->language_type = overlay_info->language_type;
     }
+    if (overlay_info->handler) {
+        new_info->handler = overlay_info->handler;
+    }
+    if (overlay_info->charset_type) {
+        new_info->charset_type = overlay_info->charset_type;
+    }
+    if (overlay_info->input_filters) {
+        new_info->input_filters = overlay_info->input_filters;
+    }
+    if (overlay_info->output_filters) {
+        new_info->output_filters = overlay_info->output_filters;
+    }
+
+    return new_info;
 }
 
 /* Member is the offset within an extension_info of the pointer to reset 
@@ -244,11 +233,10 @@
     mime_dir_config *new = apr_palloc(p, sizeof(mime_dir_config));
 
     if (base->extension_mappings && add->extension_mappings) {
-        new->extension_mappings = apr_hash_make(p);
-        overlay_extension_mappings(p, base->extension_mappings,
-                                   new->extension_mappings);
-        overlay_extension_mappings(p, add->extension_mappings,
-                                   new->extension_mappings);
+        new->extension_mappings = apr_hash_merge(p, add->extension_mappings,
+                                                 base->extension_mappings,
+                                                 overlay_extension_mappings,
+                                                 NULL);
     }
     else {
         if (base->extension_mappings == NULL) {
@@ -262,9 +250,8 @@
          * We must have a copy for safety.
          */
         if (new->extension_mappings && add->remove_mappings) {
-            apr_hash_t *copyhash = new->extension_mappings;
-            new->extension_mappings = apr_hash_make(p);
-            overlay_extension_mappings(p, copyhash, new->extension_mappings);
+            new->extension_mappings =
+                apr_hash_copy(p, new->extension_mappings);
         }
     }
 
@@ -764,7 +751,7 @@
     /* Parse filename extensions which can be in any order 
      */
     while (*fn && (ext = ap_getword(r->pool, &fn, '.'))) {
-        extension_info *exinfo = NULL;
+        const extension_info *exinfo = NULL;
         int found;
 
         if (*ext == '\0')  /* ignore empty extensions "bad..html" */

Reply via email to