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