[BZ #2509]
[glibc.git] / locale / programs / simple-hash.c
blobde8998cc7a607e017ff5e49aabff3bf617fafe2a
1 /* Implement simple hashing table with string based keys.
2 Copyright (C) 1994-1997,2000,2001,2002,2005 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, October 1994.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License version 2 as
8 published by the Free Software Foundation.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software Foundation,
17 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/types.h>
28 #if HAVE_OBSTACK
29 # include <obstack.h>
30 #else
31 # include "obstack.h"
32 #endif
34 #ifdef HAVE_VALUES_H
35 # include <values.h>
36 #endif
38 #include "simple-hash.h"
40 #define obstack_chunk_alloc malloc
41 #define obstack_chunk_free free
43 #ifndef BITSPERBYTE
44 # define BITSPERBYTE 8
45 #endif
47 #ifndef bcopy
48 # define bcopy(s, d, n) memcpy ((d), (s), (n))
49 #endif
51 #include "hashval.h"
53 extern void *xmalloc (size_t __n);
54 extern void *xcalloc (size_t __n, size_t __m);
56 typedef struct hash_entry
58 unsigned long used;
59 const void *key;
60 size_t keylen;
61 void *data;
62 struct hash_entry *next;
64 hash_entry;
66 /* Prototypes for local functions. */
67 static void insert_entry_2 (hash_table *htab, const void *key, size_t keylen,
68 unsigned long hval, size_t idx, void *data);
69 static size_t lookup (const hash_table *htab, const void *key, size_t keylen,
70 unsigned long int hval);
71 static int is_prime (unsigned long int candidate);
74 int
75 init_hash (htab, init_size)
76 hash_table *htab;
77 unsigned long int init_size;
79 /* We need the size to be a prime. */
80 init_size = next_prime (init_size);
82 /* Initialize the data structure. */
83 htab->size = init_size;
84 htab->filled = 0;
85 htab->first = NULL;
86 htab->table = (void *) xcalloc (init_size + 1, sizeof (hash_entry));
87 if (htab->table == NULL)
88 return -1;
90 obstack_init (&htab->mem_pool);
92 return 0;
96 int
97 delete_hash (htab)
98 hash_table *htab;
100 free (htab->table);
101 obstack_free (&htab->mem_pool, NULL);
102 return 0;
107 insert_entry (htab, key, keylen, data)
108 hash_table *htab;
109 const void *key;
110 size_t keylen;
111 void *data;
113 unsigned long int hval = compute_hashval (key, keylen);
114 hash_entry *table = (hash_entry *) htab->table;
115 size_t idx = lookup (htab, key, keylen, hval);
117 if (table[idx].used)
118 /* We don't want to overwrite the old value. */
119 return -1;
120 else
122 /* An empty bucket has been found. */
123 insert_entry_2 (htab, obstack_copy (&htab->mem_pool, key, keylen),
124 keylen, hval, idx, data);
125 return 0;
129 static void
130 insert_entry_2 (htab, key, keylen, hval, idx, data)
131 hash_table *htab;
132 const void *key;
133 size_t keylen;
134 unsigned long int hval;
135 size_t idx;
136 void *data;
138 hash_entry *table = (hash_entry *) htab->table;
140 table[idx].used = hval;
141 table[idx].key = key;
142 table[idx].keylen = keylen;
143 table[idx].data = data;
145 /* List the new value in the list. */
146 if ((hash_entry *) htab->first == NULL)
148 table[idx].next = &table[idx];
149 htab->first = &table[idx];
151 else
153 table[idx].next = ((hash_entry *) htab->first)->next;
154 ((hash_entry *) htab->first)->next = &table[idx];
155 htab->first = &table[idx];
158 ++htab->filled;
159 if (100 * htab->filled > 75 * htab->size)
161 /* Table is filled more than 75%. Resize the table.
162 Experiments have shown that for best performance, this threshold
163 must lie between 40% and 85%. */
164 unsigned long int old_size = htab->size;
166 htab->size = next_prime (htab->size * 2);
167 htab->filled = 0;
168 htab->first = NULL;
169 htab->table = (void *) xcalloc (1 + htab->size, sizeof (hash_entry));
171 for (idx = 1; idx <= old_size; ++idx)
172 if (table[idx].used)
173 insert_entry_2 (htab, table[idx].key, table[idx].keylen,
174 table[idx].used,
175 lookup (htab, table[idx].key, table[idx].keylen,
176 table[idx].used),
177 table[idx].data);
179 free (table);
185 find_entry (htab, key, keylen, result)
186 const hash_table *htab;
187 const void *key;
188 size_t keylen;
189 void **result;
191 hash_entry *table = (hash_entry *) htab->table;
192 size_t idx = lookup (htab, key, keylen, compute_hashval (key, keylen));
194 if (table[idx].used == 0)
195 return -1;
197 *result = table[idx].data;
198 return 0;
203 set_entry (htab, key, keylen, newval)
204 hash_table *htab;
205 const void *key;
206 size_t keylen;
207 void *newval;
209 hash_entry *table = (hash_entry *) htab->table;
210 size_t idx = lookup (htab, key, keylen, compute_hashval (key, keylen));
212 if (table[idx].used == 0)
213 return -1;
215 table[idx].data = newval;
216 return 0;
221 iterate_table (htab, ptr, key, keylen, data)
222 const hash_table *htab;
223 void **ptr;
224 const void **key;
225 size_t *keylen;
226 void **data;
228 if (*ptr == NULL)
230 if (htab->first == NULL)
231 return -1;
232 *ptr = (void *) ((hash_entry *) htab->first)->next;
234 else
236 if (*ptr == htab->first)
237 return -1;
238 *ptr = (void *) (((hash_entry *) *ptr)->next);
241 *key = ((hash_entry *) *ptr)->key;
242 *keylen = ((hash_entry *) *ptr)->keylen;
243 *data = ((hash_entry *) *ptr)->data;
244 return 0;
248 /* References:
249 [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986
250 [Knuth] The Art of Computer Programming, part3 (6.4) */
252 static size_t
253 lookup (htab, key, keylen, hval)
254 const hash_table *htab;
255 const void *key;
256 size_t keylen;
257 unsigned long int hval;
259 unsigned long int hash;
260 size_t idx;
261 hash_entry *table = (hash_entry *) htab->table;
263 /* First hash function: simply take the modul but prevent zero. */
264 hash = 1 + hval % htab->size;
266 idx = hash;
268 if (table[idx].used)
270 if (table[idx].used == hval && table[idx].keylen == keylen
271 && memcmp (table[idx].key, key, keylen) == 0)
272 return idx;
274 /* Second hash function as suggested in [Knuth]. */
275 hash = 1 + hval % (htab->size - 2);
279 if (idx <= hash)
280 idx = htab->size + idx - hash;
281 else
282 idx -= hash;
284 /* If entry is found use it. */
285 if (table[idx].used == hval && table[idx].keylen == keylen
286 && memcmp (table[idx].key, key, keylen) == 0)
287 return idx;
289 while (table[idx].used);
291 return idx;
295 unsigned long int
296 next_prime (seed)
297 unsigned long int seed;
299 /* Make it definitely odd. */
300 seed |= 1;
302 while (!is_prime (seed))
303 seed += 2;
305 return seed;
309 static int
310 is_prime (candidate)
311 unsigned long int candidate;
313 /* No even number and none less than 10 will be passed here. */
314 unsigned long int divn = 3;
315 unsigned long int sq = divn * divn;
317 while (sq < candidate && candidate % divn != 0)
319 ++divn;
320 sq += 4 * divn;
321 ++divn;
324 return candidate % divn != 0;