1 /* $NetBSD: hash.c,v 1.5 2006/12/27 17:50:27 alc Exp $ */
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This software was developed by the Computer Systems Engineering group
8 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
9 * contributed to Berkeley.
11 * All advertising materials mentioning features or use of this software
12 * must display the following acknowledgement:
13 * This product includes software developed by the University of
14 * California, Lawrence Berkeley Laboratories.
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
24 * 3. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 * from: @(#)hash.c 8.1 (Berkeley) 6/6/93
43 #if HAVE_NBTOOL_CONFIG_H
44 #include "nbtool_config.h"
47 #include <sys/param.h>
55 * Interned strings are kept in a hash table. By making each string
56 * unique, the program can compare strings by comparing pointers.
59 // XXXLUKEM: a SIMPLEQ might be more appropriate
60 TAILQ_ENTRY(hashent
) h_next
;
61 const char *h_name
; /* the string */
62 u_int h_hash
; /* its hash value */
63 void *h_value
; /* other values (for name=value) */
66 size_t ht_size
; /* size (power of 2) */
67 u_int ht_mask
; /* == ht_size - 1 */
68 u_int ht_used
; /* number of entries used */
69 u_int ht_lim
; /* when to expand */
70 TAILQ_HEAD(hashenthead
, hashent
) *ht_tab
;
73 static struct hashtab strings
;
76 * HASHFRACTION controls ht_lim, which in turn controls the average chain
77 * length. We allow a few entries, on average, as comparing them is usually
78 * cheap (the h_hash values prevent a strcmp).
80 #define HASHFRACTION(sz) ((sz) * 3 / 2)
82 static void ht_expand(struct hashtab
*);
83 static void ht_init(struct hashtab
*, size_t);
84 static inline u_int
hash(const char *);
85 static inline struct hashent
*newhashent(const char *, u_int
);
88 * Initialize a new hash table. The size must be a power of 2.
91 ht_init(struct hashtab
*ht
, size_t sz
)
95 ht
->ht_tab
= emalloc(sz
* sizeof (ht
->ht_tab
[0]));
98 for (n
= 0; n
< sz
; n
++)
99 TAILQ_INIT(&ht
->ht_tab
[n
]);
101 ht
->ht_lim
= HASHFRACTION(sz
);
105 * Expand an existing hash table.
108 ht_expand(struct hashtab
*ht
)
110 struct hashenthead
*h
, *oldh
;
115 h
= emalloc(n
* sizeof *h
);
116 for (i
= 0; i
< n
; i
++)
120 for (i
= 0; i
< ht
->ht_size
; i
++) {
121 while ((p
= TAILQ_FIRST(&oldh
[i
])) != NULL
) {
122 TAILQ_REMOVE(&oldh
[i
], p
, h_next
);
123 // XXXLUKEM: really should be TAILQ_INSERT_TAIL
124 TAILQ_INSERT_HEAD(&h
[p
->h_hash
& n
], p
, h_next
);
131 ht
->ht_lim
= HASHFRACTION(n
);
135 * Make a new hash entry, setting its h_next to NULL.
136 * If the free list is not empty, use the first entry from there,
137 * otherwise allocate a new entry.
139 static inline struct hashent
*
140 newhashent(const char *name
, u_int h
)
144 hp
= ecalloc(1, sizeof(*hp
));
155 hash(const char *str
)
160 h
= (h
<< 5) + h
+ *str
++;
168 ht_init(&strings
, 128);
172 * Generate a single unique copy of the given string. We expect this
173 * function to be used frequently, so it should be fast.
176 intern(const char *s
)
180 struct hashenthead
*hpp
;
186 hpp
= &ht
->ht_tab
[h
& ht
->ht_mask
];
187 TAILQ_FOREACH(hp
, hpp
, h_next
) {
188 if (hp
->h_hash
== h
&& strcmp(hp
->h_name
, s
) == 0)
192 hp
= newhashent(p
, h
);
193 TAILQ_INSERT_TAIL(hpp
, hp
, h_next
);
194 if (++ht
->ht_used
> ht
->ht_lim
)
204 ht
= ecalloc(1, sizeof *ht
);
210 ht_free(struct hashtab
*ht
)
214 struct hashenthead
*hpp
;
216 for (i
= 0; i
< ht
->ht_size
; i
++) {
217 hpp
= &ht
->ht_tab
[i
];
218 while ((hp
= TAILQ_FIRST(hpp
)) != NULL
) {
219 TAILQ_REMOVE(hpp
, hp
, h_next
);
225 assert(ht
->ht_used
== 0);
231 * Insert and/or replace.
234 ht_insrep(struct hashtab
*ht
, const char *nam
, void *val
, int replace
)
237 struct hashenthead
*hpp
;
241 hpp
= &ht
->ht_tab
[h
& ht
->ht_mask
];
242 TAILQ_FOREACH(hp
, hpp
, h_next
) {
243 if (hp
->h_name
== nam
) {
249 hp
= newhashent(nam
, h
);
250 TAILQ_INSERT_TAIL(hpp
, hp
, h_next
);
252 if (++ht
->ht_used
> ht
->ht_lim
)
261 ht_remove(struct hashtab
*ht
, const char *name
)
264 struct hashenthead
*hpp
;
268 hpp
= &ht
->ht_tab
[h
& ht
->ht_mask
];
270 TAILQ_FOREACH(hp
, hpp
, h_next
) {
271 if (hp
->h_name
!= name
)
273 TAILQ_REMOVE(hpp
, hp
, h_next
);
283 ht_lookup(struct hashtab
*ht
, const char *nam
)
286 struct hashenthead
*hpp
;
290 hpp
= &ht
->ht_tab
[h
& ht
->ht_mask
];
291 TAILQ_FOREACH(hp
, hpp
, h_next
)
292 if (hp
->h_name
== nam
)
293 return (hp
->h_value
);
298 * first parameter to callback is the entry name from the hash table
299 * second parameter is the value from the hash table
300 * third argument is passed through from the "arg" parameter to ht_enumerate()
304 ht_enumerate(struct hashtab
*ht
, ht_callback cbfunc
, void *arg
)
307 struct hashenthead
*hpp
;
311 for (i
= 0; i
< ht
->ht_size
; i
++) {
312 hpp
= &ht
->ht_tab
[i
];
313 TAILQ_FOREACH(hp
, hpp
, h_next
)
314 rval
+= (*cbfunc
)(hp
->h_name
, hp
->h_value
, arg
);