1 : /*
2 : * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
3 : * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
4 : *
5 : * This file is part of the device-mapper userspace tools.
6 : *
7 : * This copyrighted material is made available to anyone wishing to use,
8 : * modify, copy, or redistribute it subject to the terms and conditions
9 : * of the GNU Lesser General Public License v.2.1.
10 : *
11 : * You should have received a copy of the GNU Lesser General Public License
12 : * along with this program; if not, write to the Free Software Foundation,
13 : * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14 : */
15 :
16 : #include "dmlib.h"
17 :
18 : struct dm_hash_node {
19 : struct dm_hash_node *next;
20 : void *data;
21 : unsigned keylen;
22 : char key[0];
23 : };
24 :
25 : struct dm_hash_table {
26 : unsigned num_nodes;
27 : unsigned num_slots;
28 : struct dm_hash_node **slots;
29 : };
30 :
31 : /* Permutation of the Integers 0 through 255 */
32 : static unsigned char _nums[] = {
33 : 1, 14, 110, 25, 97, 174, 132, 119, 138, 170, 125, 118, 27, 233, 140, 51,
34 : 87, 197, 177, 107, 234, 169, 56, 68, 30, 7, 173, 73, 188, 40, 36, 65,
35 : 49, 213, 104, 190, 57, 211, 148, 223, 48, 115, 15, 2, 67, 186, 210, 28,
36 : 12, 181, 103, 70, 22, 58, 75, 78, 183, 167, 238, 157, 124, 147, 172,
37 : 144,
38 : 176, 161, 141, 86, 60, 66, 128, 83, 156, 241, 79, 46, 168, 198, 41, 254,
39 : 178, 85, 253, 237, 250, 154, 133, 88, 35, 206, 95, 116, 252, 192, 54,
40 : 221,
41 : 102, 218, 255, 240, 82, 106, 158, 201, 61, 3, 89, 9, 42, 155, 159, 93,
42 : 166, 80, 50, 34, 175, 195, 100, 99, 26, 150, 16, 145, 4, 33, 8, 189,
43 : 121, 64, 77, 72, 208, 245, 130, 122, 143, 55, 105, 134, 29, 164, 185,
44 : 194,
45 : 193, 239, 101, 242, 5, 171, 126, 11, 74, 59, 137, 228, 108, 191, 232,
46 : 139,
47 : 6, 24, 81, 20, 127, 17, 91, 92, 251, 151, 225, 207, 21, 98, 113, 112,
48 : 84, 226, 18, 214, 199, 187, 13, 32, 94, 220, 224, 212, 247, 204, 196,
49 : 43,
50 : 249, 236, 45, 244, 111, 182, 153, 136, 129, 90, 217, 202, 19, 165, 231,
51 : 71,
52 : 230, 142, 96, 227, 62, 179, 246, 114, 162, 53, 160, 215, 205, 180, 47,
53 : 109,
54 : 44, 38, 31, 149, 135, 0, 216, 52, 63, 23, 37, 69, 39, 117, 146, 184,
55 : 163, 200, 222, 235, 248, 243, 219, 10, 152, 131, 123, 229, 203, 76, 120,
56 : 209
57 : };
58 :
59 1700 : static struct dm_hash_node *_create_node(const char *str, unsigned len)
60 : {
61 1700 : struct dm_hash_node *n = dm_malloc(sizeof(*n) + len);
62 :
63 1700 : if (n) {
64 1700 : memcpy(n->key, str, len);
65 1700 : n->keylen = len;
66 : }
67 :
68 1700 : return n;
69 : }
70 :
71 3931 : static unsigned long _hash(const char *str, unsigned len)
72 : {
73 3931 : unsigned long h = 0, g;
74 : unsigned i;
75 :
76 63037 : for (i = 0; i < len; i++) {
77 59106 : h <<= 4;
78 59106 : h += _nums[(unsigned char) *str++];
79 59106 : g = h & ((unsigned long) 0xf << 16u);
80 59106 : if (g) {
81 45233 : h ^= g >> 16u;
82 45233 : h ^= g >> 5u;
83 : }
84 : }
85 :
86 3931 : return h;
87 : }
88 :
89 18 : struct dm_hash_table *dm_hash_create(unsigned size_hint)
90 : {
91 : size_t len;
92 18 : unsigned new_size = 16u;
93 18 : struct dm_hash_table *hc = dm_malloc(sizeof(*hc));
94 :
95 18 : if (!hc) {
96 0 : stack;
97 0 : return 0;
98 : }
99 :
100 18 : memset(hc, 0, sizeof(*hc));
101 :
102 : /* round size hint up to a power of two */
103 90 : while (new_size < size_hint)
104 54 : new_size = new_size << 1;
105 :
106 18 : hc->num_slots = new_size;
107 18 : len = sizeof(*(hc->slots)) * new_size;
108 18 : if (!(hc->slots = dm_malloc(len))) {
109 0 : stack;
110 0 : goto bad;
111 : }
112 18 : memset(hc->slots, 0, len);
113 18 : return hc;
114 :
115 : bad:
116 0 : dm_free(hc->slots);
117 0 : dm_free(hc);
118 0 : return 0;
119 : }
120 :
121 18 : static void _free_nodes(struct dm_hash_table *t)
122 : {
123 : struct dm_hash_node *c, *n;
124 : unsigned i;
125 :
126 2322 : for (i = 0; i < t->num_slots; i++)
127 3994 : for (c = t->slots[i]; c; c = n) {
128 1690 : n = c->next;
129 1690 : dm_free(c);
130 : }
131 18 : }
132 :
133 18 : void dm_hash_destroy(struct dm_hash_table *t)
134 : {
135 18 : _free_nodes(t);
136 18 : dm_free(t->slots);
137 18 : dm_free(t);
138 18 : }
139 :
140 3931 : static struct dm_hash_node **_find(struct dm_hash_table *t, const char *key,
141 : uint32_t len)
142 : {
143 3931 : unsigned h = _hash(key, len) & (t->num_slots - 1);
144 : struct dm_hash_node **c;
145 :
146 19368 : for (c = &t->slots[h]; *c; c = &((*c)->next)) {
147 15508 : if ((*c)->keylen != len)
148 4337 : continue;
149 :
150 11171 : if (!memcmp(key, (*c)->key, len))
151 71 : break;
152 : }
153 :
154 3931 : return c;
155 : }
156 :
157 2220 : void *dm_hash_lookup_binary(struct dm_hash_table *t, const char *key,
158 : uint32_t len)
159 : {
160 2220 : struct dm_hash_node **c = _find(t, key, len);
161 :
162 2220 : return *c ? (*c)->data : 0;
163 : }
164 :
165 1701 : int dm_hash_insert_binary(struct dm_hash_table *t, const char *key,
166 : uint32_t len, void *data)
167 : {
168 1701 : struct dm_hash_node **c = _find(t, key, len);
169 :
170 1701 : if (*c)
171 1 : (*c)->data = data;
172 : else {
173 1700 : struct dm_hash_node *n = _create_node(key, len);
174 :
175 1700 : if (!n)
176 0 : return 0;
177 :
178 1700 : n->data = data;
179 1700 : n->next = 0;
180 1700 : *c = n;
181 1700 : t->num_nodes++;
182 : }
183 :
184 1701 : return 1;
185 : }
186 :
187 10 : void dm_hash_remove_binary(struct dm_hash_table *t, const char *key,
188 : uint32_t len)
189 : {
190 10 : struct dm_hash_node **c = _find(t, key, len);
191 :
192 10 : if (*c) {
193 10 : struct dm_hash_node *old = *c;
194 10 : *c = (*c)->next;
195 10 : dm_free(old);
196 10 : t->num_nodes--;
197 : }
198 10 : }
199 :
200 2220 : void *dm_hash_lookup(struct dm_hash_table *t, const char *key)
201 : {
202 2220 : return dm_hash_lookup_binary(t, key, strlen(key) + 1);
203 : }
204 :
205 1701 : int dm_hash_insert(struct dm_hash_table *t, const char *key, void *data)
206 : {
207 1701 : return dm_hash_insert_binary(t, key, strlen(key) + 1, data);
208 : }
209 :
210 10 : void dm_hash_remove(struct dm_hash_table *t, const char *key)
211 : {
212 10 : dm_hash_remove_binary(t, key, strlen(key) + 1);
213 10 : }
214 :
215 2 : unsigned dm_hash_get_num_entries(struct dm_hash_table *t)
216 : {
217 2 : return t->num_nodes;
218 : }
219 :
220 14 : void dm_hash_iter(struct dm_hash_table *t, dm_hash_iterate_fn f)
221 : {
222 : struct dm_hash_node *c, *n;
223 : unsigned i;
224 :
225 1806 : for (i = 0; i < t->num_slots; i++)
226 2841 : for (c = t->slots[i]; c; c = n) {
227 1049 : n = c->next;
228 1049 : f(c->data);
229 : }
230 14 : }
231 :
232 0 : void dm_hash_wipe(struct dm_hash_table *t)
233 : {
234 0 : _free_nodes(t);
235 0 : memset(t->slots, 0, sizeof(struct dm_hash_node *) * t->num_slots);
236 0 : t->num_nodes = 0u;
237 0 : }
238 :
239 0 : char *dm_hash_get_key(struct dm_hash_table *t __attribute((unused)),
240 : struct dm_hash_node *n)
241 : {
242 0 : return n->key;
243 : }
244 :
245 0 : void *dm_hash_get_data(struct dm_hash_table *t __attribute((unused)),
246 : struct dm_hash_node *n)
247 : {
248 0 : return n->data;
249 : }
250 :
251 3 : static struct dm_hash_node *_next_slot(struct dm_hash_table *t, unsigned s)
252 : {
253 3 : struct dm_hash_node *c = NULL;
254 : unsigned i;
255 :
256 387 : for (i = s; i < t->num_slots && !c; i++)
257 384 : c = t->slots[i];
258 :
259 3 : return c;
260 : }
261 :
262 3 : struct dm_hash_node *dm_hash_get_first(struct dm_hash_table *t)
263 : {
264 3 : return _next_slot(t, 0);
265 : }
266 :
267 0 : struct dm_hash_node *dm_hash_get_next(struct dm_hash_table *t, struct dm_hash_node *n)
268 : {
269 0 : unsigned h = _hash(n->key, n->keylen) & (t->num_slots - 1);
270 :
271 0 : return n->next ? n->next : _next_slot(t, h + 1);
272 : }
|