Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/bmake/hash.c
39564 views
1
/* $NetBSD: hash.c,v 1.80 2025/04/22 19:28:50 rillig Exp $ */
2
3
/*
4
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
5
* All rights reserved.
6
*
7
* This code is derived from software contributed to Berkeley by
8
* Adam de Boor.
9
*
10
* Redistribution and use in source and binary forms, with or without
11
* modification, are permitted provided that the following conditions
12
* are met:
13
* 1. Redistributions of source code must retain the above copyright
14
* notice, this list of conditions and the following disclaimer.
15
* 2. Redistributions in binary form must reproduce the above copyright
16
* notice, this list of conditions and the following disclaimer in the
17
* documentation and/or other materials provided with the distribution.
18
* 3. Neither the name of the University nor the names of its contributors
19
* may be used to endorse or promote products derived from this software
20
* without specific prior written permission.
21
*
22
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32
* SUCH DAMAGE.
33
*/
34
35
/*
36
* Copyright (c) 1988, 1989 by Adam de Boor
37
* Copyright (c) 1989 by Berkeley Softworks
38
* All rights reserved.
39
*
40
* This code is derived from software contributed to Berkeley by
41
* Adam de Boor.
42
*
43
* Redistribution and use in source and binary forms, with or without
44
* modification, are permitted provided that the following conditions
45
* are met:
46
* 1. Redistributions of source code must retain the above copyright
47
* notice, this list of conditions and the following disclaimer.
48
* 2. Redistributions in binary form must reproduce the above copyright
49
* notice, this list of conditions and the following disclaimer in the
50
* documentation and/or other materials provided with the distribution.
51
* 3. All advertising materials mentioning features or use of this software
52
* must display the following acknowledgement:
53
* This product includes software developed by the University of
54
* California, Berkeley and its contributors.
55
* 4. Neither the name of the University nor the names of its contributors
56
* may be used to endorse or promote products derived from this software
57
* without specific prior written permission.
58
*
59
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
60
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
61
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
62
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
63
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
64
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
65
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
66
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
67
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
68
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
69
* SUCH DAMAGE.
70
*/
71
72
/* Hash tables with string keys and pointer values. */
73
74
#include "make.h"
75
76
/* "@(#)hash.c 8.1 (Berkeley) 6/6/93" */
77
MAKE_RCSID("$NetBSD: hash.c,v 1.80 2025/04/22 19:28:50 rillig Exp $");
78
79
/*
80
* The ratio of # entries to # buckets at which we rebuild the table to
81
* make it larger.
82
*/
83
#define rebuildLimit 3
84
85
/* This hash function matches Gosling's Emacs and java.lang.String. */
86
static unsigned
87
Hash_String(const char *key, const char **out_keyEnd)
88
{
89
unsigned h;
90
const char *p;
91
92
h = 0;
93
for (p = key; *p != '\0'; p++)
94
h = 31 * h + (unsigned char)*p;
95
96
*out_keyEnd = p;
97
return h;
98
}
99
100
/* This hash function matches Gosling's Emacs and java.lang.String. */
101
unsigned
102
Hash_Substring(Substring key)
103
{
104
unsigned h;
105
const char *p;
106
107
h = 0;
108
for (p = key.start; p != key.end; p++)
109
h = 31 * h + (unsigned char)*p;
110
return h;
111
}
112
113
static HashEntry *
114
HashTable_Find(HashTable *t, Substring key, unsigned h)
115
{
116
HashEntry *he;
117
size_t keyLen = Substring_Length(key);
118
119
#ifdef DEBUG_HASH_LOOKUP
120
DEBUG4(HASH, "HashTable_Find: %p h=%08x key=%.*s\n",
121
t, h, (int)keyLen, key.start);
122
#endif
123
124
for (he = t->buckets[h & t->bucketsMask]; he != NULL; he = he->next) {
125
if (he->hash == h &&
126
strncmp(he->key, key.start, keyLen) == 0 &&
127
he->key[keyLen] == '\0')
128
break;
129
}
130
131
return he;
132
}
133
134
/* Set up the hash table. */
135
void
136
HashTable_Init(HashTable *t)
137
{
138
unsigned n = 16, i;
139
HashEntry **buckets = bmake_malloc(sizeof *buckets * n);
140
for (i = 0; i < n; i++)
141
buckets[i] = NULL;
142
143
t->buckets = buckets;
144
t->bucketsSize = n;
145
t->numEntries = 0;
146
t->bucketsMask = n - 1;
147
}
148
149
/*
150
* Remove everything from the hash table and free up the memory for the keys
151
* of the hash table, but not for the values associated to these keys.
152
*/
153
void
154
HashTable_Done(HashTable *t)
155
{
156
HashEntry **buckets = t->buckets;
157
size_t i, n = t->bucketsSize;
158
159
for (i = 0; i < n; i++) {
160
HashEntry *he = buckets[i];
161
while (he != NULL) {
162
HashEntry *next = he->next;
163
free(he);
164
he = next;
165
}
166
}
167
168
free(t->buckets);
169
#ifdef CLEANUP
170
t->buckets = NULL;
171
#endif
172
}
173
174
/* Find the entry corresponding to the key, or return NULL. */
175
HashEntry *
176
HashTable_FindEntry(HashTable *t, const char *key)
177
{
178
const char *keyEnd;
179
unsigned h = Hash_String(key, &keyEnd);
180
return HashTable_Find(t, Substring_Init(key, keyEnd), h);
181
}
182
183
/* Find the value corresponding to the key, or return NULL. */
184
void *
185
HashTable_FindValue(HashTable *t, const char *key)
186
{
187
HashEntry *he = HashTable_FindEntry(t, key);
188
return he != NULL ? he->value : NULL;
189
}
190
191
/*
192
* Find the value corresponding to the key and the precomputed hash,
193
* or return NULL.
194
*/
195
void *
196
HashTable_FindValueBySubstringHash(HashTable *t, Substring key, unsigned h)
197
{
198
HashEntry *he = HashTable_Find(t, key, h);
199
return he != NULL ? he->value : NULL;
200
}
201
202
static unsigned
203
HashTable_MaxChain(const HashTable *t)
204
{
205
unsigned b, cl, max_cl = 0;
206
for (b = 0; b < t->bucketsSize; b++) {
207
const HashEntry *he = t->buckets[b];
208
for (cl = 0; he != NULL; he = he->next)
209
cl++;
210
if (cl > max_cl)
211
max_cl = cl;
212
}
213
return max_cl;
214
}
215
216
/*
217
* Make the hash table larger. Any bucket numbers from the old table become
218
* invalid; the hash values stay valid though.
219
*/
220
static void
221
HashTable_Enlarge(HashTable *t)
222
{
223
unsigned oldSize = t->bucketsSize;
224
HashEntry **oldBuckets = t->buckets;
225
unsigned newSize = 2 * oldSize;
226
unsigned newMask = newSize - 1;
227
HashEntry **newBuckets = bmake_malloc(sizeof *newBuckets * newSize);
228
size_t i;
229
230
for (i = 0; i < newSize; i++)
231
newBuckets[i] = NULL;
232
233
for (i = 0; i < oldSize; i++) {
234
HashEntry *he = oldBuckets[i];
235
while (he != NULL) {
236
HashEntry *next = he->next;
237
he->next = newBuckets[he->hash & newMask];
238
newBuckets[he->hash & newMask] = he;
239
he = next;
240
}
241
}
242
243
free(oldBuckets);
244
245
t->bucketsSize = newSize;
246
t->bucketsMask = newMask;
247
t->buckets = newBuckets;
248
DEBUG4(HASH, "HashTable_Enlarge: %p size=%d entries=%d maxchain=%d\n",
249
(void *)t, t->bucketsSize, t->numEntries, HashTable_MaxChain(t));
250
}
251
252
/*
253
* Find or create an entry corresponding to the key.
254
* Return in out_isNew whether a new entry has been created.
255
*/
256
HashEntry *
257
HashTable_CreateEntry(HashTable *t, const char *key, bool *out_isNew)
258
{
259
const char *keyEnd;
260
unsigned h = Hash_String(key, &keyEnd);
261
HashEntry *he = HashTable_Find(t, Substring_Init(key, keyEnd), h);
262
263
if (he != NULL) {
264
if (out_isNew != NULL)
265
*out_isNew = false;
266
return he;
267
}
268
269
if (t->numEntries >= rebuildLimit * t->bucketsSize)
270
HashTable_Enlarge(t);
271
272
he = bmake_malloc(sizeof *he + (size_t)(keyEnd - key));
273
he->value = NULL;
274
he->hash = h;
275
memcpy(he->key, key, (size_t)(keyEnd - key) + 1);
276
277
he->next = t->buckets[h & t->bucketsMask];
278
t->buckets[h & t->bucketsMask] = he;
279
t->numEntries++;
280
281
if (out_isNew != NULL)
282
*out_isNew = true;
283
return he;
284
}
285
286
void
287
HashTable_Set(HashTable *t, const char *key, void *value)
288
{
289
HashEntry *he = HashTable_CreateEntry(t, key, NULL);
290
HashEntry_Set(he, value);
291
}
292
293
/* Delete the entry from the table, don't free the value of the entry. */
294
void
295
HashTable_DeleteEntry(HashTable *t, HashEntry *he)
296
{
297
HashEntry **ref = &t->buckets[he->hash & t->bucketsMask];
298
299
for (; *ref != he; ref = &(*ref)->next)
300
continue;
301
*ref = he->next;
302
free(he);
303
t->numEntries--;
304
}
305
306
/*
307
* Place the next entry from the hash table in hi->entry, or return false if
308
* the end of the table is reached.
309
*/
310
bool
311
HashIter_Next(HashIter *hi)
312
{
313
HashTable *t = hi->table;
314
HashEntry *he = hi->entry;
315
HashEntry **buckets = t->buckets;
316
unsigned bucketsSize = t->bucketsSize;
317
318
if (he != NULL)
319
he = he->next; /* skip the most recently returned entry */
320
321
while (he == NULL) { /* find the next nonempty chain */
322
if (hi->nextBucket >= bucketsSize)
323
return false;
324
he = buckets[hi->nextBucket++];
325
}
326
hi->entry = he;
327
return true;
328
}
329
330
void
331
HashTable_DebugStats(const HashTable *t, const char *name)
332
{
333
DEBUG4(HASH, "HashTable \"%s\": size=%u entries=%u maxchain=%u\n",
334
name, t->bucketsSize, t->numEntries, HashTable_MaxChain(t));
335
}
336
337