1251875Speter/* Licensed to the Apache Software Foundation (ASF) under one or more
2251875Speter * contributor license agreements.  See the NOTICE file distributed with
3251875Speter * this work for additional information regarding copyright ownership.
4251875Speter * The ASF licenses this file to You under the Apache License, Version 2.0
5251875Speter * (the "License"); you may not use this file except in compliance with
6251875Speter * the License.  You may obtain a copy of the License at
7251875Speter *
8251875Speter *     http://www.apache.org/licenses/LICENSE-2.0
9251875Speter *
10251875Speter * Unless required by applicable law or agreed to in writing, software
11251875Speter * distributed under the License is distributed on an "AS IS" BASIS,
12251875Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13251875Speter * See the License for the specific language governing permissions and
14251875Speter * limitations under the License.
15251875Speter */
16251875Speter
17251875Speter#include "apr_private.h"
18251875Speter
19251875Speter#include "apr_general.h"
20251875Speter#include "apr_pools.h"
21251875Speter#include "apr_time.h"
22251875Speter
23251875Speter#include "apr_hash.h"
24251875Speter
25251875Speter#if APR_HAVE_STDLIB_H
26251875Speter#include <stdlib.h>
27251875Speter#endif
28251875Speter#if APR_HAVE_STRING_H
29251875Speter#include <string.h>
30251875Speter#endif
31251875Speter
32251875Speter#if APR_POOL_DEBUG && APR_HAVE_STDIO_H
33251875Speter#include <stdio.h>
34251875Speter#endif
35251875Speter
36251875Speter/*
37251875Speter * The internal form of a hash table.
38251875Speter *
39251875Speter * The table is an array indexed by the hash of the key; collisions
40251875Speter * are resolved by hanging a linked list of hash entries off each
41251875Speter * element of the array. Although this is a really simple design it
42251875Speter * isn't too bad given that pools have a low allocation overhead.
43251875Speter */
44251875Speter
45251875Spetertypedef struct apr_hash_entry_t apr_hash_entry_t;
46251875Speter
47251875Speterstruct apr_hash_entry_t {
48251875Speter    apr_hash_entry_t *next;
49251875Speter    unsigned int      hash;
50251875Speter    const void       *key;
51251875Speter    apr_ssize_t       klen;
52251875Speter    const void       *val;
53251875Speter};
54251875Speter
55251875Speter/*
56251875Speter * Data structure for iterating through a hash table.
57251875Speter *
58251875Speter * We keep a pointer to the next hash entry here to allow the current
59251875Speter * hash entry to be freed or otherwise mangled between calls to
60251875Speter * apr_hash_next().
61251875Speter */
62251875Speterstruct apr_hash_index_t {
63251875Speter    apr_hash_t         *ht;
64251875Speter    apr_hash_entry_t   *this, *next;
65251875Speter    unsigned int        index;
66251875Speter};
67251875Speter
68251875Speter/*
69251875Speter * The size of the array is always a power of two. We use the maximum
70251875Speter * index rather than the size so that we can use bitwise-AND for
71251875Speter * modular arithmetic.
72251875Speter * The count of hash entries may be greater depending on the chosen
73251875Speter * collision rate.
74251875Speter */
75251875Speterstruct apr_hash_t {
76251875Speter    apr_pool_t          *pool;
77251875Speter    apr_hash_entry_t   **array;
78251875Speter    apr_hash_index_t     iterator;  /* For apr_hash_first(NULL, ...) */
79251875Speter    unsigned int         count, max, seed;
80251875Speter    apr_hashfunc_t       hash_func;
81251875Speter    apr_hash_entry_t    *free;  /* List of recycled entries */
82251875Speter};
83251875Speter
84251875Speter#define INITIAL_MAX 15 /* tunable == 2^n - 1 */
85251875Speter
86251875Speter
87251875Speter/*
88251875Speter * Hash creation functions.
89251875Speter */
90251875Speter
91251875Speterstatic apr_hash_entry_t **alloc_array(apr_hash_t *ht, unsigned int max)
92251875Speter{
93251875Speter   return apr_pcalloc(ht->pool, sizeof(*ht->array) * (max + 1));
94251875Speter}
95251875Speter
96251875SpeterAPR_DECLARE(apr_hash_t *) apr_hash_make(apr_pool_t *pool)
97251875Speter{
98251875Speter    apr_hash_t *ht;
99251875Speter    apr_time_t now = apr_time_now();
100251875Speter
101251875Speter    ht = apr_palloc(pool, sizeof(apr_hash_t));
102251875Speter    ht->pool = pool;
103251875Speter    ht->free = NULL;
104251875Speter    ht->count = 0;
105251875Speter    ht->max = INITIAL_MAX;
106251875Speter    ht->seed = (unsigned int)((now >> 32) ^ now ^ (apr_uintptr_t)pool ^
107251875Speter                              (apr_uintptr_t)ht ^ (apr_uintptr_t)&now) - 1;
108251875Speter    ht->array = alloc_array(ht, ht->max);
109251875Speter    ht->hash_func = NULL;
110251875Speter
111251875Speter    return ht;
112251875Speter}
113251875Speter
114251875SpeterAPR_DECLARE(apr_hash_t *) apr_hash_make_custom(apr_pool_t *pool,
115251875Speter                                               apr_hashfunc_t hash_func)
116251875Speter{
117251875Speter    apr_hash_t *ht = apr_hash_make(pool);
118251875Speter    ht->hash_func = hash_func;
119251875Speter    return ht;
120251875Speter}
121251875Speter
122251875Speter
123251875Speter/*
124251875Speter * Hash iteration functions.
125251875Speter */
126251875Speter
127251875SpeterAPR_DECLARE(apr_hash_index_t *) apr_hash_next(apr_hash_index_t *hi)
128251875Speter{
129251875Speter    hi->this = hi->next;
130251875Speter    while (!hi->this) {
131251875Speter        if (hi->index > hi->ht->max)
132251875Speter            return NULL;
133251875Speter
134251875Speter        hi->this = hi->ht->array[hi->index++];
135251875Speter    }
136251875Speter    hi->next = hi->this->next;
137251875Speter    return hi;
138251875Speter}
139251875Speter
140251875SpeterAPR_DECLARE(apr_hash_index_t *) apr_hash_first(apr_pool_t *p, apr_hash_t *ht)
141251875Speter{
142251875Speter    apr_hash_index_t *hi;
143251875Speter    if (p)
144251875Speter        hi = apr_palloc(p, sizeof(*hi));
145251875Speter    else
146251875Speter        hi = &ht->iterator;
147251875Speter
148251875Speter    hi->ht = ht;
149251875Speter    hi->index = 0;
150251875Speter    hi->this = NULL;
151251875Speter    hi->next = NULL;
152251875Speter    return apr_hash_next(hi);
153251875Speter}
154251875Speter
155251875SpeterAPR_DECLARE(void) apr_hash_this(apr_hash_index_t *hi,
156251875Speter                                const void **key,
157251875Speter                                apr_ssize_t *klen,
158251875Speter                                void **val)
159251875Speter{
160251875Speter    if (key)  *key  = hi->this->key;
161251875Speter    if (klen) *klen = hi->this->klen;
162251875Speter    if (val)  *val  = (void *)hi->this->val;
163251875Speter}
164251875Speter
165269847SpeterAPR_DECLARE(const void *) apr_hash_this_key(apr_hash_index_t *hi)
166269847Speter{
167269847Speter    const void *key;
168251875Speter
169269847Speter    apr_hash_this(hi, &key, NULL, NULL);
170269847Speter    return key;
171269847Speter}
172269847Speter
173269847SpeterAPR_DECLARE(apr_ssize_t) apr_hash_this_key_len(apr_hash_index_t *hi)
174269847Speter{
175269847Speter    apr_ssize_t klen;
176269847Speter
177269847Speter    apr_hash_this(hi, NULL, &klen, NULL);
178269847Speter    return klen;
179269847Speter}
180269847Speter
181269847SpeterAPR_DECLARE(void *) apr_hash_this_val(apr_hash_index_t *hi)
182269847Speter{
183269847Speter    void *val;
184269847Speter
185269847Speter    apr_hash_this(hi, NULL, NULL, &val);
186269847Speter    return val;
187269847Speter}
188269847Speter
189251875Speter/*
190251875Speter * Expanding a hash table
191251875Speter */
192251875Speter
193251875Speterstatic void expand_array(apr_hash_t *ht)
194251875Speter{
195251875Speter    apr_hash_index_t *hi;
196251875Speter    apr_hash_entry_t **new_array;
197251875Speter    unsigned int new_max;
198251875Speter
199251875Speter    new_max = ht->max * 2 + 1;
200251875Speter    new_array = alloc_array(ht, new_max);
201251875Speter    for (hi = apr_hash_first(NULL, ht); hi; hi = apr_hash_next(hi)) {
202251875Speter        unsigned int i = hi->this->hash & new_max;
203251875Speter        hi->this->next = new_array[i];
204251875Speter        new_array[i] = hi->this;
205251875Speter    }
206251875Speter    ht->array = new_array;
207251875Speter    ht->max = new_max;
208251875Speter}
209251875Speter
210251875Speterstatic unsigned int hashfunc_default(const char *char_key, apr_ssize_t *klen,
211251875Speter                                     unsigned int hash)
212251875Speter{
213251875Speter    const unsigned char *key = (const unsigned char *)char_key;
214251875Speter    const unsigned char *p;
215251875Speter    apr_ssize_t i;
216251875Speter
217251875Speter    /*
218251875Speter     * This is the popular `times 33' hash algorithm which is used by
219251875Speter     * perl and also appears in Berkeley DB. This is one of the best
220251875Speter     * known hash functions for strings because it is both computed
221251875Speter     * very fast and distributes very well.
222251875Speter     *
223251875Speter     * The originator may be Dan Bernstein but the code in Berkeley DB
224251875Speter     * cites Chris Torek as the source. The best citation I have found
225251875Speter     * is "Chris Torek, Hash function for text in C, Usenet message
226251875Speter     * <27038@mimsy.umd.edu> in comp.lang.c , October, 1990." in Rich
227251875Speter     * Salz's USENIX 1992 paper about INN which can be found at
228251875Speter     * <http://citeseer.nj.nec.com/salz92internetnews.html>.
229251875Speter     *
230251875Speter     * The magic of number 33, i.e. why it works better than many other
231251875Speter     * constants, prime or not, has never been adequately explained by
232251875Speter     * anyone. So I try an explanation: if one experimentally tests all
233251875Speter     * multipliers between 1 and 256 (as I did while writing a low-level
234251875Speter     * data structure library some time ago) one detects that even
235251875Speter     * numbers are not useable at all. The remaining 128 odd numbers
236251875Speter     * (except for the number 1) work more or less all equally well.
237251875Speter     * They all distribute in an acceptable way and this way fill a hash
238251875Speter     * table with an average percent of approx. 86%.
239251875Speter     *
240251875Speter     * If one compares the chi^2 values of the variants (see
241251875Speter     * Bob Jenkins ``Hashing Frequently Asked Questions'' at
242251875Speter     * http://burtleburtle.net/bob/hash/hashfaq.html for a description
243251875Speter     * of chi^2), the number 33 not even has the best value. But the
244251875Speter     * number 33 and a few other equally good numbers like 17, 31, 63,
245251875Speter     * 127 and 129 have nevertheless a great advantage to the remaining
246251875Speter     * numbers in the large set of possible multipliers: their multiply
247251875Speter     * operation can be replaced by a faster operation based on just one
248251875Speter     * shift plus either a single addition or subtraction operation. And
249251875Speter     * because a hash function has to both distribute good _and_ has to
250251875Speter     * be very fast to compute, those few numbers should be preferred.
251251875Speter     *
252251875Speter     *                  -- Ralf S. Engelschall <rse@engelschall.com>
253251875Speter     */
254251875Speter
255251875Speter    if (*klen == APR_HASH_KEY_STRING) {
256251875Speter        for (p = key; *p; p++) {
257251875Speter            hash = hash * 33 + *p;
258251875Speter        }
259251875Speter        *klen = p - key;
260251875Speter    }
261251875Speter    else {
262251875Speter        for (p = key, i = *klen; i; i--, p++) {
263251875Speter            hash = hash * 33 + *p;
264251875Speter        }
265251875Speter    }
266251875Speter
267251875Speter    return hash;
268251875Speter}
269251875Speter
270251875SpeterAPR_DECLARE_NONSTD(unsigned int) apr_hashfunc_default(const char *char_key,
271251875Speter                                                      apr_ssize_t *klen)
272251875Speter{
273251875Speter    return hashfunc_default(char_key, klen, 0);
274251875Speter}
275251875Speter
276251875Speter/*
277251875Speter * This is where we keep the details of the hash function and control
278251875Speter * the maximum collision rate.
279251875Speter *
280251875Speter * If val is non-NULL it creates and initializes a new hash entry if
281251875Speter * there isn't already one there; it returns an updatable pointer so
282251875Speter * that hash entries can be removed.
283251875Speter */
284251875Speter
285251875Speterstatic apr_hash_entry_t **find_entry(apr_hash_t *ht,
286251875Speter                                     const void *key,
287251875Speter                                     apr_ssize_t klen,
288251875Speter                                     const void *val)
289251875Speter{
290251875Speter    apr_hash_entry_t **hep, *he;
291251875Speter    unsigned int hash;
292251875Speter
293251875Speter    if (ht->hash_func)
294251875Speter        hash = ht->hash_func(key, &klen);
295251875Speter    else
296251875Speter        hash = hashfunc_default(key, &klen, ht->seed);
297251875Speter
298251875Speter    /* scan linked list */
299251875Speter    for (hep = &ht->array[hash & ht->max], he = *hep;
300251875Speter         he; hep = &he->next, he = *hep) {
301251875Speter        if (he->hash == hash
302251875Speter            && he->klen == klen
303251875Speter            && memcmp(he->key, key, klen) == 0)
304251875Speter            break;
305251875Speter    }
306251875Speter    if (he || !val)
307251875Speter        return hep;
308251875Speter
309251875Speter    /* add a new entry for non-NULL values */
310251875Speter    if ((he = ht->free) != NULL)
311251875Speter        ht->free = he->next;
312251875Speter    else
313251875Speter        he = apr_palloc(ht->pool, sizeof(*he));
314251875Speter    he->next = NULL;
315251875Speter    he->hash = hash;
316251875Speter    he->key  = key;
317251875Speter    he->klen = klen;
318251875Speter    he->val  = val;
319251875Speter    *hep = he;
320251875Speter    ht->count++;
321251875Speter    return hep;
322251875Speter}
323251875Speter
324251875SpeterAPR_DECLARE(apr_hash_t *) apr_hash_copy(apr_pool_t *pool,
325251875Speter                                        const apr_hash_t *orig)
326251875Speter{
327251875Speter    apr_hash_t *ht;
328251875Speter    apr_hash_entry_t *new_vals;
329251875Speter    unsigned int i, j;
330251875Speter
331251875Speter    ht = apr_palloc(pool, sizeof(apr_hash_t) +
332251875Speter                    sizeof(*ht->array) * (orig->max + 1) +
333251875Speter                    sizeof(apr_hash_entry_t) * orig->count);
334251875Speter    ht->pool = pool;
335251875Speter    ht->free = NULL;
336251875Speter    ht->count = orig->count;
337251875Speter    ht->max = orig->max;
338251875Speter    ht->seed = orig->seed;
339251875Speter    ht->hash_func = orig->hash_func;
340251875Speter    ht->array = (apr_hash_entry_t **)((char *)ht + sizeof(apr_hash_t));
341251875Speter
342251875Speter    new_vals = (apr_hash_entry_t *)((char *)(ht) + sizeof(apr_hash_t) +
343251875Speter                                    sizeof(*ht->array) * (orig->max + 1));
344251875Speter    j = 0;
345251875Speter    for (i = 0; i <= ht->max; i++) {
346251875Speter        apr_hash_entry_t **new_entry = &(ht->array[i]);
347251875Speter        apr_hash_entry_t *orig_entry = orig->array[i];
348251875Speter        while (orig_entry) {
349251875Speter            *new_entry = &new_vals[j++];
350251875Speter            (*new_entry)->hash = orig_entry->hash;
351251875Speter            (*new_entry)->key = orig_entry->key;
352251875Speter            (*new_entry)->klen = orig_entry->klen;
353251875Speter            (*new_entry)->val = orig_entry->val;
354251875Speter            new_entry = &((*new_entry)->next);
355251875Speter            orig_entry = orig_entry->next;
356251875Speter        }
357251875Speter        *new_entry = NULL;
358251875Speter    }
359251875Speter    return ht;
360251875Speter}
361251875Speter
362251875SpeterAPR_DECLARE(void *) apr_hash_get(apr_hash_t *ht,
363251875Speter                                 const void *key,
364251875Speter                                 apr_ssize_t klen)
365251875Speter{
366251875Speter    apr_hash_entry_t *he;
367251875Speter    he = *find_entry(ht, key, klen, NULL);
368251875Speter    if (he)
369251875Speter        return (void *)he->val;
370251875Speter    else
371251875Speter        return NULL;
372251875Speter}
373251875Speter
374251875SpeterAPR_DECLARE(void) apr_hash_set(apr_hash_t *ht,
375251875Speter                               const void *key,
376251875Speter                               apr_ssize_t klen,
377251875Speter                               const void *val)
378251875Speter{
379251875Speter    apr_hash_entry_t **hep;
380251875Speter    hep = find_entry(ht, key, klen, val);
381251875Speter    if (*hep) {
382251875Speter        if (!val) {
383251875Speter            /* delete entry */
384251875Speter            apr_hash_entry_t *old = *hep;
385251875Speter            *hep = (*hep)->next;
386251875Speter            old->next = ht->free;
387251875Speter            ht->free = old;
388251875Speter            --ht->count;
389251875Speter        }
390251875Speter        else {
391251875Speter            /* replace entry */
392251875Speter            (*hep)->val = val;
393251875Speter            /* check that the collision rate isn't too high */
394251875Speter            if (ht->count > ht->max) {
395251875Speter                expand_array(ht);
396251875Speter            }
397251875Speter        }
398251875Speter    }
399251875Speter    /* else key not present and val==NULL */
400251875Speter}
401251875Speter
402251875SpeterAPR_DECLARE(unsigned int) apr_hash_count(apr_hash_t *ht)
403251875Speter{
404251875Speter    return ht->count;
405251875Speter}
406251875Speter
407251875SpeterAPR_DECLARE(void) apr_hash_clear(apr_hash_t *ht)
408251875Speter{
409251875Speter    apr_hash_index_t *hi;
410251875Speter    for (hi = apr_hash_first(NULL, ht); hi; hi = apr_hash_next(hi))
411251875Speter        apr_hash_set(ht, hi->this->key, hi->this->klen, NULL);
412251875Speter}
413251875Speter
414251875SpeterAPR_DECLARE(apr_hash_t*) apr_hash_overlay(apr_pool_t *p,
415251875Speter                                          const apr_hash_t *overlay,
416251875Speter                                          const apr_hash_t *base)
417251875Speter{
418251875Speter    return apr_hash_merge(p, overlay, base, NULL, NULL);
419251875Speter}
420251875Speter
421251875SpeterAPR_DECLARE(apr_hash_t *) apr_hash_merge(apr_pool_t *p,
422251875Speter                                         const apr_hash_t *overlay,
423251875Speter                                         const apr_hash_t *base,
424251875Speter                                         void * (*merger)(apr_pool_t *p,
425251875Speter                                                     const void *key,
426251875Speter                                                     apr_ssize_t klen,
427251875Speter                                                     const void *h1_val,
428251875Speter                                                     const void *h2_val,
429251875Speter                                                     const void *data),
430251875Speter                                         const void *data)
431251875Speter{
432251875Speter    apr_hash_t *res;
433251875Speter    apr_hash_entry_t *new_vals = NULL;
434251875Speter    apr_hash_entry_t *iter;
435251875Speter    apr_hash_entry_t *ent;
436251875Speter    unsigned int i, j, k, hash;
437251875Speter
438251875Speter#if APR_POOL_DEBUG
439251875Speter    /* we don't copy keys and values, so it's necessary that
440251875Speter     * overlay->a.pool and base->a.pool have a life span at least
441251875Speter     * as long as p
442251875Speter     */
443251875Speter    if (!apr_pool_is_ancestor(overlay->pool, p)) {
444251875Speter        fprintf(stderr,
445251875Speter                "apr_hash_merge: overlay's pool is not an ancestor of p\n");
446251875Speter        abort();
447251875Speter    }
448251875Speter    if (!apr_pool_is_ancestor(base->pool, p)) {
449251875Speter        fprintf(stderr,
450251875Speter                "apr_hash_merge: base's pool is not an ancestor of p\n");
451251875Speter        abort();
452251875Speter    }
453251875Speter#endif
454251875Speter
455251875Speter    res = apr_palloc(p, sizeof(apr_hash_t));
456251875Speter    res->pool = p;
457251875Speter    res->free = NULL;
458251875Speter    res->hash_func = base->hash_func;
459251875Speter    res->count = base->count;
460251875Speter    res->max = (overlay->max > base->max) ? overlay->max : base->max;
461251875Speter    if (base->count + overlay->count > res->max) {
462251875Speter        res->max = res->max * 2 + 1;
463251875Speter    }
464251875Speter    res->seed = base->seed;
465251875Speter    res->array = alloc_array(res, res->max);
466251875Speter    if (base->count + overlay->count) {
467251875Speter        new_vals = apr_palloc(p, sizeof(apr_hash_entry_t) *
468251875Speter                              (base->count + overlay->count));
469251875Speter    }
470251875Speter    j = 0;
471251875Speter    for (k = 0; k <= base->max; k++) {
472251875Speter        for (iter = base->array[k]; iter; iter = iter->next) {
473251875Speter            i = iter->hash & res->max;
474251875Speter            new_vals[j].klen = iter->klen;
475251875Speter            new_vals[j].key = iter->key;
476251875Speter            new_vals[j].val = iter->val;
477251875Speter            new_vals[j].hash = iter->hash;
478251875Speter            new_vals[j].next = res->array[i];
479251875Speter            res->array[i] = &new_vals[j];
480251875Speter            j++;
481251875Speter        }
482251875Speter    }
483251875Speter
484251875Speter    for (k = 0; k <= overlay->max; k++) {
485251875Speter        for (iter = overlay->array[k]; iter; iter = iter->next) {
486251875Speter            if (res->hash_func)
487251875Speter                hash = res->hash_func(iter->key, &iter->klen);
488251875Speter            else
489251875Speter                hash = hashfunc_default(iter->key, &iter->klen, res->seed);
490251875Speter            i = hash & res->max;
491251875Speter            for (ent = res->array[i]; ent; ent = ent->next) {
492251875Speter                if ((ent->klen == iter->klen) &&
493251875Speter                    (memcmp(ent->key, iter->key, iter->klen) == 0)) {
494251875Speter                    if (merger) {
495251875Speter                        ent->val = (*merger)(p, iter->key, iter->klen,
496251875Speter                                             iter->val, ent->val, data);
497251875Speter                    }
498251875Speter                    else {
499251875Speter                        ent->val = iter->val;
500251875Speter                    }
501251875Speter                    break;
502251875Speter                }
503251875Speter            }
504251875Speter            if (!ent) {
505251875Speter                new_vals[j].klen = iter->klen;
506251875Speter                new_vals[j].key = iter->key;
507251875Speter                new_vals[j].val = iter->val;
508251875Speter                new_vals[j].hash = hash;
509251875Speter                new_vals[j].next = res->array[i];
510251875Speter                res->array[i] = &new_vals[j];
511251875Speter                res->count++;
512251875Speter                j++;
513251875Speter            }
514251875Speter        }
515251875Speter    }
516251875Speter    return res;
517251875Speter}
518251875Speter
519251875Speter/* This is basically the following...
520251875Speter * for every element in hash table {
521251875Speter *    comp elemeny.key, element.value
522251875Speter * }
523251875Speter *
524251875Speter * Like with apr_table_do, the comp callback is called for each and every
525251875Speter * element of the hash table.
526251875Speter */
527251875SpeterAPR_DECLARE(int) apr_hash_do(apr_hash_do_callback_fn_t *comp,
528251875Speter                             void *rec, const apr_hash_t *ht)
529251875Speter{
530251875Speter    apr_hash_index_t  hix;
531251875Speter    apr_hash_index_t *hi;
532251875Speter    int rv, dorv  = 1;
533251875Speter
534251875Speter    hix.ht    = (apr_hash_t *)ht;
535251875Speter    hix.index = 0;
536251875Speter    hix.this  = NULL;
537251875Speter    hix.next  = NULL;
538251875Speter
539251875Speter    if ((hi = apr_hash_next(&hix))) {
540251875Speter        /* Scan the entire table */
541251875Speter        do {
542251875Speter            rv = (*comp)(rec, hi->this->key, hi->this->klen, hi->this->val);
543251875Speter        } while (rv && (hi = apr_hash_next(hi)));
544251875Speter
545251875Speter        if (rv == 0) {
546251875Speter            dorv = 0;
547251875Speter        }
548251875Speter    }
549251875Speter    return dorv;
550251875Speter}
551251875Speter
552251875SpeterAPR_POOL_IMPLEMENT_ACCESSOR(hash)
553