blob: c1c607dd85f5715ee2bbf7698c05cb76741b8c4b [file] [log] [blame]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001/* Fixed size hash table with internal linking.
2 Copyright (C) 2000, 2001, 2002, 2004, 2005 Red Hat, Inc.
3 Written by Ulrich Drepper <drepper@redhat.com>, 2000.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, version 2.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
17
18#include <errno.h>
19#include <stdlib.h>
20#include <string.h>
21#include <sys/cdefs.h>
22#include <sys/param.h>
23
24#include <system.h>
25
26#define CONCAT(t1,t2) __CONCAT (t1,t2)
27
28/* Before including this file the following macros must be defined:
29
30 TYPE data type of the hash table entries
31 HASHFCT name of the hashing function to use
32 HASHTYPE type used for the hashing value
33 COMPARE comparison function taking two pointers to TYPE objects
34 CLASS can be defined to `static' to avoid exporting the functions
35 PREFIX prefix to be used for function and data type names
36 STORE_POINTER if defined the table stores a pointer and not an element
37 of type TYPE
38 INSERT_HASH if defined alternate insert function which takes a hash
39 value is defined
40 NO_FINI_FCT if defined the fini function is not defined
41*/
42
43
44/* Defined separately. */
45extern size_t next_prime (size_t seed);
46
47
48/* Set default values. */
49#ifndef HASHTYPE
50# define HASHTYPE size_t
51#endif
52
53#ifndef CLASS
54# define CLASS
55#endif
56
57#ifndef PREFIX
58# define PREFIX
59#endif
60
61
62/* The data structure. */
63struct CONCAT(PREFIX,fshash)
64{
65 size_t nslots;
66 struct CONCAT(PREFIX,fshashent)
67 {
68 HASHTYPE hval;
69#ifdef STORE_POINTER
70# define ENTRYP(el) (el).entry
71 TYPE *entry;
72#else
73# define ENTRYP(el) &(el).entry
74 TYPE entry;
75#endif
76 } table[0];
77};
78
79
80/* Constructor for the hashing table. */
81CLASS struct CONCAT(PREFIX,fshash) *
82CONCAT(PREFIX,fshash_init) (size_t nelems)
83{
84 struct CONCAT(PREFIX,fshash) *result;
85 /* We choose a size for the hashing table 150% over the number of
86 entries. This will guarantee short medium search lengths. */
87 const size_t max_size_t = ~((size_t) 0);
88
89 if (nelems >= (max_size_t / 3) * 2)
90 {
91 errno = EINVAL;
92 return NULL;
93 }
94
95 /* Adjust the size to be used for the hashing table. */
96 nelems = next_prime (MAX ((nelems * 3) / 2, 10));
97
98 /* Allocate the data structure for the result. */
99 result = (struct CONCAT(PREFIX,fshash) *)
100 xcalloc (sizeof (struct CONCAT(PREFIX,fshash))
101 + (nelems + 1) * sizeof (struct CONCAT(PREFIX,fshashent)), 1);
102 if (result == NULL)
103 return NULL;
104
105 result->nslots = nelems;
106
107 return result;
108}
109
110
111#ifndef NO_FINI_FCT
112CLASS void
113CONCAT(PREFIX,fshash_fini) (struct CONCAT(PREFIX,fshash) *htab)
114{
115 free (htab);
116}
117#endif
118
119
120static struct CONCAT(PREFIX,fshashent) *
121CONCAT(PREFIX,fshash_lookup) (struct CONCAT(PREFIX,fshash) *htab,
122 HASHTYPE hval, TYPE *data)
123{
124 size_t idx = 1 + hval % htab->nslots;
125
126 if (htab->table[idx].hval != 0)
127 {
128 HASHTYPE hash;
129
130 /* See whether this is the same entry. */
131 if (htab->table[idx].hval == hval
132 && COMPARE (data, ENTRYP (htab->table[idx])) == 0)
133 return &htab->table[idx];
134
135 /* Second hash function as suggested in [Knuth]. */
136 hash = 1 + hval % (htab->nslots - 2);
137
138 do
139 {
140 if (idx <= hash)
141 idx = htab->nslots + idx - hash;
142 else
143 idx -= hash;
144
145 if (htab->table[idx].hval == hval
146 && COMPARE (data, ENTRYP(htab->table[idx])) == 0)
147 return &htab->table[idx];
148 }
149 while (htab->table[idx].hval != 0);
150 }
151
152 return &htab->table[idx];
153}
154
155
156CLASS int
157__attribute__ ((unused))
158CONCAT(PREFIX,fshash_insert) (struct CONCAT(PREFIX,fshash) *htab,
159 const char *str,
160 size_t len __attribute__ ((unused)), TYPE *data)
161{
162 HASHTYPE hval = HASHFCT (str, len ?: strlen (str));
163 struct CONCAT(PREFIX,fshashent) *slot;
164
165 slot = CONCAT(PREFIX,fshash_lookup) (htab, hval, data);
166 if (slot->hval != 0)
167 /* We don't want to overwrite the old value. */
168 return -1;
169
170 slot->hval = hval;
171#ifdef STORE_POINTER
172 slot->entry = data;
173#else
174 slot->entry = *data;
175#endif
176
177 return 0;
178}
179
180
181#ifdef INSERT_HASH
182CLASS int
183__attribute__ ((unused))
184CONCAT(PREFIX,fshash_insert_hash) (struct CONCAT(PREFIX,fshash) *htab,
185 HASHTYPE hval, TYPE *data)
186{
187 struct CONCAT(PREFIX,fshashent) *slot;
188
189 slot = CONCAT(PREFIX,fshash_lookup) (htab, hval, data);
190 if (slot->hval != 0)
191 /* We don't want to overwrite the old value. */
192 return -1;
193
194 slot->hval = hval;
195#ifdef STORE_POINTER
196 slot->entry = data;
197#else
198 slot->entry = *data;
199#endif
200
201 return 0;
202}
203#endif
204
205
206CLASS int
207__attribute__ ((unused))
208CONCAT(PREFIX,fshash_overwrite) (struct CONCAT(PREFIX,fshash) *htab,
209 const char *str,
210 size_t len __attribute__ ((unused)),
211 TYPE *data)
212{
213 HASHTYPE hval = HASHFCT (str, len ?: strlen (str));
214 struct CONCAT(PREFIX,fshashent) *slot;
215
216 slot = CONCAT(PREFIX,fshash_lookup) (htab, hval, data);
217 slot->hval = hval;
218#ifdef STORE_POINTER
219 slot->entry = data;
220#else
221 slot->entry = *data;
222#endif
223
224 return 0;
225}
226
227
228CLASS const TYPE *
229CONCAT(PREFIX,fshash_find) (const struct CONCAT(PREFIX,fshash) *htab,
230 const char *str,
231 size_t len __attribute__ ((unused)), TYPE *data)
232{
233 HASHTYPE hval = HASHFCT (str, len ?: strlen (str));
234 struct CONCAT(PREFIX,fshashent) *slot;
235
236 slot = CONCAT(PREFIX,fshash_lookup) ((struct CONCAT(PREFIX,fshash) *) htab,
237 hval, data);
238 if (slot->hval == 0)
239 /* Not found. */
240 return NULL;
241
242 return ENTRYP(*slot);
243}
244
245
246/* Unset the macros we expect. */
247#undef TYPE
248#undef HASHFCT
249#undef HASHTYPE
250#undef COMPARE
251#undef CLASS
252#undef PREFIX
253#undef INSERT_HASH
254#undef STORE_POINTER
255#undef NO_FINI_FCT