1 /* $NetBSD: strhash.c,v 1.4 2014/12/10 04:37:55 christos Exp $ */
4 static char *rcsid
= "Id: strhash.c,v 1.1 2003/06/04 00:26:13 marka Exp ";
8 * Copyright (c) 2000 Japan Network Information Center. All rights reserved.
10 * By using this file, you agree to the terms and conditions set forth bellow.
12 * LICENSE TERMS AND CONDITIONS
14 * The following License Terms and Conditions apply, unless a different
15 * license is obtained from Japan Network Information Center ("JPNIC"),
16 * a Japanese association, Kokusai-Kougyou-Kanda Bldg 6F, 2-3-4 Uchi-Kanda,
17 * Chiyoda-ku, Tokyo 101-0047, Japan.
19 * 1. Use, Modification and Redistribution (including distribution of any
20 * modified or derived work) in source and/or binary forms is permitted
21 * under this License Terms and Conditions.
23 * 2. Redistribution of source code must retain the copyright notices as they
24 * appear in each source code file, this License Terms and Conditions.
26 * 3. Redistribution in binary form must reproduce the Copyright Notice,
27 * this License Terms and Conditions, in the documentation and/or other
28 * materials provided with the distribution. For the purposes of binary
29 * distribution the "Copyright Notice" refers to the following language:
30 * "Copyright (c) 2000-2002 Japan Network Information Center. All rights reserved."
32 * 4. The name of JPNIC may not be used to endorse or promote products
33 * derived from this Software without specific prior written approval of
36 * 5. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY JPNIC
37 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
38 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
39 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JPNIC BE LIABLE
40 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
41 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
42 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
46 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
55 #include <idn/assert.h>
56 #include <idn/logmacro.h>
57 #include <idn/result.h>
58 #include <idn/strhash.h>
61 * Initially, the number of hash buckets is INITIAL_HASH_SIZE.
62 * As the more elements are put in the hash, the number of elements
63 * per bucket will exceed THRESHOLD eventually. When it happens,
64 * the number of buckets will be multiplied by FACTOR.
66 #define INITIAL_HASH_SIZE 67
72 typedef struct strhash_entry
{
73 struct strhash_entry
*next
;
74 unsigned long hash_value
;
82 strhash_entry_t
**bins
;
85 static unsigned long hash_value(const char *key
);
86 static strhash_entry_t
*find_entry(strhash_entry_t
*entry
, const char *key
,
88 static strhash_entry_t
*new_entry(const char *key
, void *value
);
89 static idn_result_t
expand_bins(idn__strhash_t hash
, int new_size
);
92 idn__strhash_create(idn__strhash_t
*hashp
) {
96 TRACE(("idn__strhash_create()\n"));
98 assert(hashp
!= NULL
);
102 if ((hash
= malloc(sizeof(struct idn__strhash
))) == NULL
) {
103 WARNING(("idn__strhash_create: malloc failed (hash)\n"));
104 return (idn_nomemory
);
109 if ((r
= expand_bins(hash
, INITIAL_HASH_SIZE
)) != idn_success
) {
110 WARNING(("idn__strhash_create: malloc failed (bins)\n"));
117 return (idn_success
);
121 idn__strhash_destroy(idn__strhash_t hash
, idn__strhash_freeproc_t proc
) {
124 assert(hash
!= NULL
&& hash
->bins
!= NULL
);
126 for (i
= 0; i
< hash
->nbins
; i
++) {
127 strhash_entry_t
*bin
= hash
->bins
[i
];
128 strhash_entry_t
*next
;
130 while (bin
!= NULL
) {
143 idn__strhash_put(idn__strhash_t hash
, const char *key
, void *value
) {
144 unsigned long h
, h_index
;
145 strhash_entry_t
*entry
;
147 assert(hash
!= NULL
&& key
!= NULL
);
150 h_index
= h
% hash
->nbins
;
152 if ((entry
= find_entry(hash
->bins
[h_index
], key
, h
)) != NULL
) {
153 /* Entry exists. Replace the value. */
154 entry
->value
= value
;
156 /* Create new entry. */
157 if ((entry
= new_entry(key
, value
)) == NULL
) {
158 return (idn_nomemory
);
160 /* Insert it to the list. */
161 entry
->next
= hash
->bins
[h_index
];
162 hash
->bins
[h_index
] = entry
;
165 if (hash
->nelements
> hash
->nbins
* THRESHOLD
) {
167 r
= expand_bins(hash
, hash
->nbins
* FACTOR
);
168 if (r
!= idn_success
) {
169 TRACE(("idn__strhash_put: hash table "
170 "expansion failed\n"));
175 return (idn_success
);
179 idn__strhash_get(idn__strhash_t hash
, const char *key
, void **valuep
) {
181 strhash_entry_t
*entry
;
183 assert(hash
!= NULL
&& key
!= NULL
&& valuep
!= NULL
);
186 entry
= find_entry(hash
->bins
[h
% hash
->nbins
], key
, h
);
188 return (idn_noentry
);
190 *valuep
= entry
->value
;
191 return (idn_success
);
195 idn__strhash_exists(idn__strhash_t hash
, const char *key
) {
198 assert(hash
!= NULL
&& key
!= NULL
);
201 return (find_entry(hash
->bins
[h
% hash
->nbins
], key
, h
) != NULL
);
205 hash_value(const char *key
) {
207 unsigned char *p
= (unsigned char *)key
;
210 while ((c
= *p
++) != '\0') {
211 h
= h
* HASH_MULT
+ c
;
216 static strhash_entry_t
*
217 find_entry(strhash_entry_t
*entry
, const char *key
, unsigned long hash
) {
220 while (entry
!= NULL
) {
221 if (entry
->hash_value
== hash
&& strcmp(key
, entry
->key
) == 0)
228 static strhash_entry_t
*
229 new_entry(const char *key
, void *value
) {
230 strhash_entry_t
*entry
;
235 len
= strlen(key
) + 1;
236 if ((entry
= malloc(sizeof(strhash_entry_t
) + len
)) == NULL
) {
240 entry
->hash_value
= hash_value(key
);
241 entry
->key
= (char *)(entry
+ 1);
242 (void)strcpy(entry
->key
, key
);
243 entry
->value
= value
;
249 expand_bins(idn__strhash_t hash
, int new_size
) {
250 strhash_entry_t
**old_bins
, **new_bins
;
252 int old_index
, new_index
;
254 new_bins
= malloc(sizeof(strhash_entry_t
*) * new_size
);
255 if (new_bins
== NULL
)
256 return (idn_nomemory
);
258 memset(new_bins
, 0, sizeof(strhash_entry_t
*) * new_size
);
260 old_bins
= hash
->bins
;
261 old_size
= hash
->nbins
;
262 for (old_index
= 0; old_index
< old_size
; old_index
++) {
263 strhash_entry_t
*entries
= old_bins
[old_index
];
265 while (entries
!= NULL
) {
266 strhash_entry_t
*e
= entries
;
268 /* Remove the top element from the linked list. */
269 entries
= entries
->next
;
271 /* ..and move to the new hash. */
272 new_index
= e
->hash_value
% new_size
;
273 e
->next
= new_bins
[new_index
];
274 new_bins
[new_index
] = e
;
278 hash
->nbins
= new_size
;
279 hash
->bins
= new_bins
;
281 if (old_bins
!= NULL
)
284 return (idn_success
);