hcreate.c revision 1.3.4.2 1 1.3.4.2 he /* $NetBSD: hcreate.c,v 1.3.4.2 2001/03/13 21:19:36 he Exp $ */
2 1.3.4.2 he
3 1.3.4.2 he /*
4 1.3.4.2 he * Copyright (c) 2001 Christopher G. Demetriou
5 1.3.4.2 he * All rights reserved.
6 1.3.4.2 he *
7 1.3.4.2 he * Redistribution and use in source and binary forms, with or without
8 1.3.4.2 he * modification, are permitted provided that the following conditions
9 1.3.4.2 he * are met:
10 1.3.4.2 he * 1. Redistributions of source code must retain the above copyright
11 1.3.4.2 he * notice, this list of conditions and the following disclaimer.
12 1.3.4.2 he * 2. Redistributions in binary form must reproduce the above copyright
13 1.3.4.2 he * notice, this list of conditions and the following disclaimer in the
14 1.3.4.2 he * documentation and/or other materials provided with the distribution.
15 1.3.4.2 he * 3. All advertising materials mentioning features or use of this software
16 1.3.4.2 he * must display the following acknowledgement:
17 1.3.4.2 he * This product includes software developed for the
18 1.3.4.2 he * NetBSD Project. See http://www.netbsd.org/ for
19 1.3.4.2 he * information about NetBSD.
20 1.3.4.2 he * 4. The name of the author may not be used to endorse or promote products
21 1.3.4.2 he * derived from this software without specific prior written permission.
22 1.3.4.2 he *
23 1.3.4.2 he * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 1.3.4.2 he * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 1.3.4.2 he * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 1.3.4.2 he * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 1.3.4.2 he * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 1.3.4.2 he * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 1.3.4.2 he * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 1.3.4.2 he * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 1.3.4.2 he * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 1.3.4.2 he * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 1.3.4.2 he *
34 1.3.4.2 he * <<Id: LICENSE,v 1.2 2000/06/14 15:57:33 cgd Exp>>
35 1.3.4.2 he */
36 1.3.4.2 he
37 1.3.4.2 he /*
38 1.3.4.2 he * hcreate() / hsearch() / hdestroy()
39 1.3.4.2 he *
40 1.3.4.2 he * SysV/XPG4 hash table functions.
41 1.3.4.2 he *
42 1.3.4.2 he * Implementation done based on NetBSD manual page and Solaris manual page,
43 1.3.4.2 he * plus my own personal experience about how they're supposed to work.
44 1.3.4.2 he *
45 1.3.4.2 he * I tried to look at Knuth (as cited by the Solaris manual page), but
46 1.3.4.2 he * nobody had a copy in the office, so...
47 1.3.4.2 he */
48 1.3.4.2 he
49 1.3.4.2 he #include <sys/cdefs.h>
50 1.3.4.2 he #if defined(LIBC_SCCS) && !defined(lint)
51 1.3.4.2 he __RCSID("$NetBSD: hcreate.c,v 1.3.4.2 2001/03/13 21:19:36 he Exp $");
52 1.3.4.2 he #endif /* LIBC_SCCS and not lint */
53 1.3.4.2 he
54 1.3.4.2 he #if !defined(lint)
55 1.3.4.2 he __COPYRIGHT(
56 1.3.4.2 he "@(#) Copyright (c) 2001 Christopher G. Demetriou. All rights reserved.\n");
57 1.3.4.2 he #endif /* not lint */
58 1.3.4.2 he
59 1.3.4.2 he #include "namespace.h"
60 1.3.4.2 he #include <assert.h>
61 1.3.4.2 he #include <errno.h>
62 1.3.4.2 he #include <inttypes.h>
63 1.3.4.2 he #include <search.h>
64 1.3.4.2 he #include <stdlib.h>
65 1.3.4.2 he #include <string.h>
66 1.3.4.2 he #include <sys/queue.h>
67 1.3.4.2 he
68 1.3.4.2 he /*
69 1.3.4.2 he * DO NOT MAKE THIS STRUCTURE LARGER THAN 32 BYTES (4 ptrs on 64-bit
70 1.3.4.2 he * ptr machine) without adjusting MAX_BUCKETS_LG2 below.
71 1.3.4.2 he */
72 1.3.4.2 he struct internal_entry {
73 1.3.4.2 he SLIST_ENTRY(internal_entry) link;
74 1.3.4.2 he ENTRY ent;
75 1.3.4.2 he };
76 1.3.4.2 he SLIST_HEAD(internal_head, internal_entry);
77 1.3.4.2 he
78 1.3.4.2 he #define MIN_BUCKETS_LG2 4
79 1.3.4.2 he #define MIN_BUCKETS (1 << MIN_BUCKETS_LG2)
80 1.3.4.2 he
81 1.3.4.2 he /*
82 1.3.4.2 he * max * sizeof internal_entry must fit into size_t.
83 1.3.4.2 he * assumes internal_entry is <= 32 (2^5) bytes.
84 1.3.4.2 he */
85 1.3.4.2 he #define MAX_BUCKETS_LG2 (sizeof (size_t) * 8 - 1 - 5)
86 1.3.4.2 he #define MAX_BUCKETS ((size_t)1 << MAX_BUCKETS_LG2)
87 1.3.4.2 he
88 1.3.4.2 he /* Default hash function, from db/hash/hash_func.c */
89 1.3.4.2 he extern u_int32_t (*__default_hash)(const void *, size_t);
90 1.3.4.2 he
91 1.3.4.2 he static struct internal_head *htable;
92 1.3.4.2 he static size_t htablesize;
93 1.3.4.2 he
94 1.3.4.2 he int
95 1.3.4.2 he hcreate(size_t nel)
96 1.3.4.2 he {
97 1.3.4.2 he size_t idx;
98 1.3.4.2 he unsigned int p2;
99 1.3.4.2 he
100 1.3.4.2 he /* Make sure this this isn't called when a table already exists. */
101 1.3.4.2 he _DIAGASSERT(htable == NULL);
102 1.3.4.2 he if (htable != NULL) {
103 1.3.4.2 he errno = EINVAL;
104 1.3.4.2 he return 0;
105 1.3.4.2 he }
106 1.3.4.2 he
107 1.3.4.2 he /* If nel is too small, make it min sized. */
108 1.3.4.2 he if (nel < MIN_BUCKETS)
109 1.3.4.2 he nel = MIN_BUCKETS;
110 1.3.4.2 he
111 1.3.4.2 he /* If it's too large, cap it. */
112 1.3.4.2 he if (nel > MAX_BUCKETS)
113 1.3.4.2 he nel = MAX_BUCKETS;
114 1.3.4.2 he
115 1.3.4.2 he /* If it's is not a power of two in size, round up. */
116 1.3.4.2 he if ((nel & (nel - 1)) != 0) {
117 1.3.4.2 he for (p2 = 0; nel != 0; p2++)
118 1.3.4.2 he nel >>= 1;
119 1.3.4.2 he _DIAGASSERT(p2 <= MAX_BUCKETS_LG2);
120 1.3.4.2 he nel = 1 << p2;
121 1.3.4.2 he }
122 1.3.4.2 he
123 1.3.4.2 he /* Allocate the table. */
124 1.3.4.2 he htablesize = nel;
125 1.3.4.2 he htable = malloc(htablesize * sizeof htable[0]);
126 1.3.4.2 he if (htable == NULL) {
127 1.3.4.2 he errno = ENOMEM;
128 1.3.4.2 he return 0;
129 1.3.4.2 he }
130 1.3.4.2 he
131 1.3.4.2 he /* Initialize it. */
132 1.3.4.2 he for (idx = 0; idx < htablesize; idx++)
133 1.3.4.2 he SLIST_INIT(&htable[idx]);
134 1.3.4.2 he
135 1.3.4.2 he return 1;
136 1.3.4.2 he }
137 1.3.4.2 he
138 1.3.4.2 he void
139 1.3.4.2 he hdestroy(void)
140 1.3.4.2 he {
141 1.3.4.2 he struct internal_entry *ie;
142 1.3.4.2 he size_t idx;
143 1.3.4.2 he
144 1.3.4.2 he _DIAGASSERT(htable != NULL);
145 1.3.4.2 he if (htable == NULL)
146 1.3.4.2 he return;
147 1.3.4.2 he
148 1.3.4.2 he for (idx = 0; idx < htablesize; idx++) {
149 1.3.4.2 he while (!SLIST_EMPTY(&htable[idx])) {
150 1.3.4.2 he ie = SLIST_FIRST(&htable[idx]);
151 1.3.4.2 he SLIST_REMOVE_HEAD(&htable[idx], link);
152 1.3.4.2 he free(ie->ent.key);
153 1.3.4.2 he free(ie);
154 1.3.4.2 he }
155 1.3.4.2 he }
156 1.3.4.2 he free(htable);
157 1.3.4.2 he htable = NULL;
158 1.3.4.2 he }
159 1.3.4.2 he
160 1.3.4.2 he ENTRY *
161 1.3.4.2 he hsearch(ENTRY item, ACTION action)
162 1.3.4.2 he {
163 1.3.4.2 he struct internal_head *head;
164 1.3.4.2 he struct internal_entry *ie;
165 1.3.4.2 he uint32_t hashval;
166 1.3.4.2 he size_t len;
167 1.3.4.2 he
168 1.3.4.2 he _DIAGASSERT(htable != NULL);
169 1.3.4.2 he _DIAGASSERT(item.key != NULL);
170 1.3.4.2 he _DIAGASSERT(action == ENTER || action == FIND);
171 1.3.4.2 he
172 1.3.4.2 he len = strlen(item.key);
173 1.3.4.2 he hashval = (*__default_hash)(item.key, len);
174 1.3.4.2 he
175 1.3.4.2 he head = &htable[hashval & (htablesize - 1)];
176 1.3.4.2 he ie = SLIST_FIRST(head);
177 1.3.4.2 he while (ie != NULL) {
178 1.3.4.2 he if (strcmp(ie->ent.key, item.key) == 0)
179 1.3.4.2 he break;
180 1.3.4.2 he ie = SLIST_NEXT(ie, link);
181 1.3.4.2 he }
182 1.3.4.2 he
183 1.3.4.2 he if (ie != NULL)
184 1.3.4.2 he return &ie->ent;
185 1.3.4.2 he else if (action == FIND)
186 1.3.4.2 he return NULL;
187 1.3.4.2 he
188 1.3.4.2 he ie = malloc(sizeof *ie);
189 1.3.4.2 he if (ie == NULL)
190 1.3.4.2 he return NULL;
191 1.3.4.2 he ie->ent.key = item.key;
192 1.3.4.2 he ie->ent.data = item.data;
193 1.3.4.2 he
194 1.3.4.2 he SLIST_INSERT_HEAD(head, ie, link);
195 1.3.4.2 he return &ie->ent;
196 1.3.4.2 he }
197