blob: 61759636fedaa477d1f787a25dd19c2db98a2f9a [file] [log] [blame]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001/* Copyright (C) 2000, 2001, 2002, 2005 Red Hat, Inc.
2 Written by Ulrich Drepper <drepper@redhat.com>, 2000.
3
4 This program is Open Source software; you can redistribute it and/or
5 modify it under the terms of the Open Software License version 1.0 as
6 published by the Open Source Initiative.
7
8 You should have received a copy of the Open Software License along
9 with this program; if not, you may obtain a copy of the Open Software
10 License version 1.0 from http://www.opensource.org/licenses/osl.php or
11 by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
12 3001 King Ranch Road, Ukiah, CA 95482. */
13
14#include <assert.h>
15#include <stdlib.h>
16#include <system.h>
17
18/* Before including this file the following macros must be defined:
19
20 NAME name of the hash table structure.
21 TYPE data type of the hash table entries
22 COMPARE comparison function taking two pointers to TYPE objects
23
24 The following macros if present select features:
25
26 ITERATE iterating over the table entries is possible
27 REVERSE iterate in reverse order of insert
28 */
29
30
31static size_t
32lookup (htab, hval, val)
33 NAME *htab;
34 unsigned long int hval;
35 TYPE val __attribute__ ((unused));
36{
37 /* First hash function: simply take the modul but prevent zero. */
38 size_t idx = 1 + hval % htab->size;
39
40 if (htab->table[idx].hashval != 0)
41 {
42 unsigned long int hash;
43
44 if (htab->table[idx].hashval == hval
45 && COMPARE (htab->table[idx].data, val) == 0)
46 return idx;
47
48 /* Second hash function as suggested in [Knuth]. */
49 hash = 1 + hval % (htab->size - 2);
50
51 do
52 {
53 if (idx <= hash)
54 idx = htab->size + idx - hash;
55 else
56 idx -= hash;
57
58 /* If entry is found use it. */
59 if (htab->table[idx].hashval == hval
60 && COMPARE (htab->table[idx].data, val) == 0)
61 return idx;
62 }
63 while (htab->table[idx].hashval);
64 }
65 return idx;
66}
67
68
69static void
70insert_entry_2 (NAME *htab, unsigned long int hval, size_t idx, TYPE data)
71{
72#ifdef ITERATE
73 if (htab->table[idx].hashval == 0)
74 {
75# ifdef REVERSE
76 htab->table[idx].next = htab->first;
77 htab->first = &htab->table[idx];
78# else
79 /* Add the new value to the list. */
80 if (htab->first == NULL)
81 htab->first = htab->table[idx].next = &htab->table[idx];
82 else
83 {
84 htab->table[idx].next = htab->first->next;
85 htab->first = htab->first->next = &htab->table[idx];
86 }
87# endif
88 }
89#endif
90
91 htab->table[idx].hashval = hval;
92 htab->table[idx].data = data;
93
94 ++htab->filled;
95 if (100 * htab->filled > 90 * htab->size)
96 {
97 /* Table is filled more than 90%. Resize the table. */
98#ifdef ITERATE
99 __typeof__ (htab->first) first;
100# ifndef REVERSE
101 __typeof__ (htab->first) runp;
102# endif
103#else
104 unsigned long int old_size = htab->size;
105#endif
106#define _TABLE(name) \
107 name##_ent *table = htab->table
108#define TABLE(name) _TABLE (name)
109 TABLE(NAME);
110
111 htab->size = next_prime (htab->size * 2);
112 htab->filled = 0;
113#ifdef ITERATE
114 first = htab->first;
115 htab->first = NULL;
116#endif
117 htab->table = calloc ((1 + htab->size), sizeof (htab->table[0]));
118 if (htab->table == NULL)
119 {
120 /* We cannot enlarge the table. Live with what we got. This
121 might lead to an infinite loop at some point, though. */
122 htab->table = table;
123 return;
124 }
125
126 /* Add the old entries to the new table. When iteration is
127 supported we maintain the order. */
128#ifdef ITERATE
129# ifdef REVERSE
130 while (first != NULL)
131 {
132 insert_entry_2 (htab, first->hashval,
133 lookup (htab, first->hashval, first->data),
134 first->data);
135
136 first = first->next;
137 }
138# else
139 assert (first != NULL);
140 runp = first = first->next;
141 do
142 insert_entry_2 (htab, runp->hashval,
143 lookup (htab, runp->hashval, runp->data), runp->data);
144 while ((runp = runp->next) != first);
145# endif
146#else
147 for (idx = 1; idx <= old_size; ++idx)
148 if (table[idx].hashval != 0)
149 insert_entry_2 (htab, table[idx].hashval,
150 lookup (htab, table[idx].hashval, table[idx].data),
151 table[idx].data);
152#endif
153
154 free (table);
155 }
156}
157
158
159int
160#define INIT(name) _INIT (name)
161#define _INIT(name) \
162 name##_init
163INIT(NAME) (htab, init_size)
164 NAME *htab;
165 unsigned long int init_size;
166{
167 /* We need the size to be a prime. */
168 init_size = next_prime (init_size);
169
170 /* Initialize the data structure. */
171 htab->size = init_size;
172 htab->filled = 0;
173#ifdef ITERATE
174 htab->first = NULL;
175#endif
176 htab->table = (void *) calloc ((init_size + 1), sizeof (htab->table[0]));
177 if (htab->table == NULL)
178 return -1;
179
180 return 0;
181}
182
183
184int
185#define FREE(name) _FREE (name)
186#define _FREE(name) \
187 name##_free
188FREE(NAME) (htab)
189 NAME *htab;
190{
191 free (htab->table);
192 return 0;
193}
194
195
196int
197#define INSERT(name) _INSERT (name)
198#define _INSERT(name) \
199 name##_insert
200INSERT(NAME) (htab, hval, data)
201 NAME *htab;
202 unsigned long int hval;
203 TYPE data;
204{
205 size_t idx;
206
207 /* Make the hash value nonzero. */
208 hval = hval ?: 1;
209
210 idx = lookup (htab, hval, data);
211
212 if (htab->table[idx].hashval != 0)
213 /* We don't want to overwrite the old value. */
214 return -1;
215
216 /* An empty bucket has been found. */
217 insert_entry_2 (htab, hval, idx, data);
218 return 0;
219}
220
221
222#ifdef OVERWRITE
223int
224#define INSERT(name) _INSERT (name)
225#define _INSERT(name) \
226 name##_overwrite
227INSERT(NAME) (htab, hval, data)
228 NAME *htab;
229 unsigned long int hval;
230 TYPE data;
231{
232 size_t idx;
233
234 /* Make the hash value nonzero. */
235 hval = hval ?: 1;
236
237 idx = lookup (htab, hval, data);
238
239 /* The correct bucket has been found. */
240 insert_entry_2 (htab, hval, idx, data);
241 return 0;
242}
243#endif
244
245
246TYPE
247#define FIND(name) _FIND (name)
248#define _FIND(name) \
249 name##_find
250FIND(NAME) (htab, hval, val)
251 NAME *htab;
252 unsigned long int hval;
253 TYPE val;
254{
255 size_t idx;
256
257 /* Make the hash value nonzero. */
258 hval = hval ?: 1;
259
260 idx = lookup (htab, hval, val);
261
262 if (htab->table[idx].hashval == 0)
263 return NULL;
264
265 return htab->table[idx].data;
266}
267
268
269#ifdef ITERATE
270# define ITERATEFCT(name) _ITERATEFCT (name)
271# define _ITERATEFCT(name) \
272 name##_iterate
273TYPE
274ITERATEFCT(NAME) (htab, ptr)
275 NAME *htab;
276 void **ptr;
277{
278 void *p = *ptr;
279
280# define TYPENAME(name) _TYPENAME (name)
281# define _TYPENAME(name) name##_ent
282
283# ifdef REVERSE
284 if (p == NULL)
285 p = htab->first;
286 else
287 p = ((TYPENAME(NAME) *) p)->next;
288
289 if (p == NULL)
290 {
291 *ptr = NULL;
292 return NULL;
293 }
294# else
295 if (p == NULL)
296 {
297 if (htab->first == NULL)
298 return NULL;
299 p = htab->first->next;
300 }
301 else
302 {
303 if (p == htab->first)
304 return NULL;
305
306 p = ((TYPENAME(NAME) *) p)->next;
307 }
308# endif
309
310 /* Prepare the next element. If possible this will pull the data
311 into the cache, for reading. */
312 __builtin_prefetch (((TYPENAME(NAME) *) p)->next, 0, 2);
313
314 return ((TYPENAME(NAME) *) (*ptr = p))->data;
315}
316#endif