xref: /netbsd-src/external/gpl2/lvm2/dist/libdm/datastruct/hash.c (revision 7c604eea85b4f330dc75ffe65e947f4d73758aa0)
1*7c604eeaShaad /*	$NetBSD: hash.c,v 1.1.1.2 2009/12/02 00:26:11 haad Exp $	*/
256a34939Shaad 
356a34939Shaad /*
456a34939Shaad  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
556a34939Shaad  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
656a34939Shaad  *
756a34939Shaad  * This file is part of the device-mapper userspace tools.
856a34939Shaad  *
956a34939Shaad  * This copyrighted material is made available to anyone wishing to use,
1056a34939Shaad  * modify, copy, or redistribute it subject to the terms and conditions
1156a34939Shaad  * of the GNU Lesser General Public License v.2.1.
1256a34939Shaad  *
1356a34939Shaad  * You should have received a copy of the GNU Lesser General Public License
1456a34939Shaad  * along with this program; if not, write to the Free Software Foundation,
1556a34939Shaad  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
1656a34939Shaad  */
1756a34939Shaad 
1856a34939Shaad #include "dmlib.h"
1956a34939Shaad 
2056a34939Shaad struct dm_hash_node {
2156a34939Shaad 	struct dm_hash_node *next;
2256a34939Shaad 	void *data;
2356a34939Shaad 	unsigned keylen;
2456a34939Shaad 	char key[0];
2556a34939Shaad };
2656a34939Shaad 
2756a34939Shaad struct dm_hash_table {
2856a34939Shaad 	unsigned num_nodes;
2956a34939Shaad 	unsigned num_slots;
3056a34939Shaad 	struct dm_hash_node **slots;
3156a34939Shaad };
3256a34939Shaad 
3356a34939Shaad /* Permutation of the Integers 0 through 255 */
3456a34939Shaad static unsigned char _nums[] = {
3556a34939Shaad 	1, 14, 110, 25, 97, 174, 132, 119, 138, 170, 125, 118, 27, 233, 140, 51,
3656a34939Shaad 	87, 197, 177, 107, 234, 169, 56, 68, 30, 7, 173, 73, 188, 40, 36, 65,
3756a34939Shaad 	49, 213, 104, 190, 57, 211, 148, 223, 48, 115, 15, 2, 67, 186, 210, 28,
3856a34939Shaad 	12, 181, 103, 70, 22, 58, 75, 78, 183, 167, 238, 157, 124, 147, 172,
3956a34939Shaad 	144,
4056a34939Shaad 	176, 161, 141, 86, 60, 66, 128, 83, 156, 241, 79, 46, 168, 198, 41, 254,
4156a34939Shaad 	178, 85, 253, 237, 250, 154, 133, 88, 35, 206, 95, 116, 252, 192, 54,
4256a34939Shaad 	221,
4356a34939Shaad 	102, 218, 255, 240, 82, 106, 158, 201, 61, 3, 89, 9, 42, 155, 159, 93,
4456a34939Shaad 	166, 80, 50, 34, 175, 195, 100, 99, 26, 150, 16, 145, 4, 33, 8, 189,
4556a34939Shaad 	121, 64, 77, 72, 208, 245, 130, 122, 143, 55, 105, 134, 29, 164, 185,
4656a34939Shaad 	194,
4756a34939Shaad 	193, 239, 101, 242, 5, 171, 126, 11, 74, 59, 137, 228, 108, 191, 232,
4856a34939Shaad 	139,
4956a34939Shaad 	6, 24, 81, 20, 127, 17, 91, 92, 251, 151, 225, 207, 21, 98, 113, 112,
5056a34939Shaad 	84, 226, 18, 214, 199, 187, 13, 32, 94, 220, 224, 212, 247, 204, 196,
5156a34939Shaad 	43,
5256a34939Shaad 	249, 236, 45, 244, 111, 182, 153, 136, 129, 90, 217, 202, 19, 165, 231,
5356a34939Shaad 	71,
5456a34939Shaad 	230, 142, 96, 227, 62, 179, 246, 114, 162, 53, 160, 215, 205, 180, 47,
5556a34939Shaad 	109,
5656a34939Shaad 	44, 38, 31, 149, 135, 0, 216, 52, 63, 23, 37, 69, 39, 117, 146, 184,
5756a34939Shaad 	163, 200, 222, 235, 248, 243, 219, 10, 152, 131, 123, 229, 203, 76, 120,
5856a34939Shaad 	209
5956a34939Shaad };
6056a34939Shaad 
_create_node(const char * str,unsigned len)6156a34939Shaad static struct dm_hash_node *_create_node(const char *str, unsigned len)
6256a34939Shaad {
6356a34939Shaad 	struct dm_hash_node *n = dm_malloc(sizeof(*n) + len);
6456a34939Shaad 
6556a34939Shaad 	if (n) {
6656a34939Shaad 		memcpy(n->key, str, len);
6756a34939Shaad 		n->keylen = len;
6856a34939Shaad 	}
6956a34939Shaad 
7056a34939Shaad 	return n;
7156a34939Shaad }
7256a34939Shaad 
_hash(const char * str,unsigned len)7356a34939Shaad static unsigned long _hash(const char *str, unsigned len)
7456a34939Shaad {
7556a34939Shaad 	unsigned long h = 0, g;
7656a34939Shaad 	unsigned i;
7756a34939Shaad 
7856a34939Shaad 	for (i = 0; i < len; i++) {
7956a34939Shaad 		h <<= 4;
8056a34939Shaad 		h += _nums[(unsigned char) *str++];
8156a34939Shaad 		g = h & ((unsigned long) 0xf << 16u);
8256a34939Shaad 		if (g) {
8356a34939Shaad 			h ^= g >> 16u;
8456a34939Shaad 			h ^= g >> 5u;
8556a34939Shaad 		}
8656a34939Shaad 	}
8756a34939Shaad 
8856a34939Shaad 	return h;
8956a34939Shaad }
9056a34939Shaad 
dm_hash_create(unsigned size_hint)9156a34939Shaad struct dm_hash_table *dm_hash_create(unsigned size_hint)
9256a34939Shaad {
9356a34939Shaad 	size_t len;
9456a34939Shaad 	unsigned new_size = 16u;
9556a34939Shaad 	struct dm_hash_table *hc = dm_malloc(sizeof(*hc));
9656a34939Shaad 
9756a34939Shaad 	if (!hc) {
9856a34939Shaad 		stack;
9956a34939Shaad 		return 0;
10056a34939Shaad 	}
10156a34939Shaad 
10256a34939Shaad 	memset(hc, 0, sizeof(*hc));
10356a34939Shaad 
10456a34939Shaad 	/* round size hint up to a power of two */
10556a34939Shaad 	while (new_size < size_hint)
10656a34939Shaad 		new_size = new_size << 1;
10756a34939Shaad 
10856a34939Shaad 	hc->num_slots = new_size;
10956a34939Shaad 	len = sizeof(*(hc->slots)) * new_size;
11056a34939Shaad 	if (!(hc->slots = dm_malloc(len))) {
11156a34939Shaad 		stack;
11256a34939Shaad 		goto bad;
11356a34939Shaad 	}
11456a34939Shaad 	memset(hc->slots, 0, len);
11556a34939Shaad 	return hc;
11656a34939Shaad 
11756a34939Shaad       bad:
11856a34939Shaad 	dm_free(hc->slots);
11956a34939Shaad 	dm_free(hc);
12056a34939Shaad 	return 0;
12156a34939Shaad }
12256a34939Shaad 
_free_nodes(struct dm_hash_table * t)12356a34939Shaad static void _free_nodes(struct dm_hash_table *t)
12456a34939Shaad {
12556a34939Shaad 	struct dm_hash_node *c, *n;
12656a34939Shaad 	unsigned i;
12756a34939Shaad 
12856a34939Shaad 	for (i = 0; i < t->num_slots; i++)
12956a34939Shaad 		for (c = t->slots[i]; c; c = n) {
13056a34939Shaad 			n = c->next;
13156a34939Shaad 			dm_free(c);
13256a34939Shaad 		}
13356a34939Shaad }
13456a34939Shaad 
dm_hash_destroy(struct dm_hash_table * t)13556a34939Shaad void dm_hash_destroy(struct dm_hash_table *t)
13656a34939Shaad {
13756a34939Shaad 	_free_nodes(t);
13856a34939Shaad 	dm_free(t->slots);
13956a34939Shaad 	dm_free(t);
14056a34939Shaad }
14156a34939Shaad 
_find(struct dm_hash_table * t,const char * key,uint32_t len)14256a34939Shaad static struct dm_hash_node **_find(struct dm_hash_table *t, const char *key,
14356a34939Shaad 				   uint32_t len)
14456a34939Shaad {
14556a34939Shaad 	unsigned h = _hash(key, len) & (t->num_slots - 1);
14656a34939Shaad 	struct dm_hash_node **c;
14756a34939Shaad 
148*7c604eeaShaad 	for (c = &t->slots[h]; *c; c = &((*c)->next)) {
149*7c604eeaShaad 		if ((*c)->keylen != len)
150*7c604eeaShaad 			continue;
151*7c604eeaShaad 
15256a34939Shaad 		if (!memcmp(key, (*c)->key, len))
15356a34939Shaad 			break;
154*7c604eeaShaad 	}
15556a34939Shaad 
15656a34939Shaad 	return c;
15756a34939Shaad }
15856a34939Shaad 
dm_hash_lookup_binary(struct dm_hash_table * t,const char * key,uint32_t len)15956a34939Shaad void *dm_hash_lookup_binary(struct dm_hash_table *t, const char *key,
16056a34939Shaad 			 uint32_t len)
16156a34939Shaad {
16256a34939Shaad 	struct dm_hash_node **c = _find(t, key, len);
16356a34939Shaad 
16456a34939Shaad 	return *c ? (*c)->data : 0;
16556a34939Shaad }
16656a34939Shaad 
dm_hash_insert_binary(struct dm_hash_table * t,const char * key,uint32_t len,void * data)16756a34939Shaad int dm_hash_insert_binary(struct dm_hash_table *t, const char *key,
16856a34939Shaad 			  uint32_t len, void *data)
16956a34939Shaad {
17056a34939Shaad 	struct dm_hash_node **c = _find(t, key, len);
17156a34939Shaad 
17256a34939Shaad 	if (*c)
17356a34939Shaad 		(*c)->data = data;
17456a34939Shaad 	else {
17556a34939Shaad 		struct dm_hash_node *n = _create_node(key, len);
17656a34939Shaad 
17756a34939Shaad 		if (!n)
17856a34939Shaad 			return 0;
17956a34939Shaad 
18056a34939Shaad 		n->data = data;
18156a34939Shaad 		n->next = 0;
18256a34939Shaad 		*c = n;
18356a34939Shaad 		t->num_nodes++;
18456a34939Shaad 	}
18556a34939Shaad 
18656a34939Shaad 	return 1;
18756a34939Shaad }
18856a34939Shaad 
dm_hash_remove_binary(struct dm_hash_table * t,const char * key,uint32_t len)18956a34939Shaad void dm_hash_remove_binary(struct dm_hash_table *t, const char *key,
19056a34939Shaad 			uint32_t len)
19156a34939Shaad {
19256a34939Shaad 	struct dm_hash_node **c = _find(t, key, len);
19356a34939Shaad 
19456a34939Shaad 	if (*c) {
19556a34939Shaad 		struct dm_hash_node *old = *c;
19656a34939Shaad 		*c = (*c)->next;
19756a34939Shaad 		dm_free(old);
19856a34939Shaad 		t->num_nodes--;
19956a34939Shaad 	}
20056a34939Shaad }
20156a34939Shaad 
dm_hash_lookup(struct dm_hash_table * t,const char * key)20256a34939Shaad void *dm_hash_lookup(struct dm_hash_table *t, const char *key)
20356a34939Shaad {
20456a34939Shaad 	return dm_hash_lookup_binary(t, key, strlen(key) + 1);
20556a34939Shaad }
20656a34939Shaad 
dm_hash_insert(struct dm_hash_table * t,const char * key,void * data)20756a34939Shaad int dm_hash_insert(struct dm_hash_table *t, const char *key, void *data)
20856a34939Shaad {
20956a34939Shaad 	return dm_hash_insert_binary(t, key, strlen(key) + 1, data);
21056a34939Shaad }
21156a34939Shaad 
dm_hash_remove(struct dm_hash_table * t,const char * key)21256a34939Shaad void dm_hash_remove(struct dm_hash_table *t, const char *key)
21356a34939Shaad {
21456a34939Shaad 	dm_hash_remove_binary(t, key, strlen(key) + 1);
21556a34939Shaad }
21656a34939Shaad 
dm_hash_get_num_entries(struct dm_hash_table * t)21756a34939Shaad unsigned dm_hash_get_num_entries(struct dm_hash_table *t)
21856a34939Shaad {
21956a34939Shaad 	return t->num_nodes;
22056a34939Shaad }
22156a34939Shaad 
dm_hash_iter(struct dm_hash_table * t,dm_hash_iterate_fn f)22256a34939Shaad void dm_hash_iter(struct dm_hash_table *t, dm_hash_iterate_fn f)
22356a34939Shaad {
22456a34939Shaad 	struct dm_hash_node *c, *n;
22556a34939Shaad 	unsigned i;
22656a34939Shaad 
22756a34939Shaad 	for (i = 0; i < t->num_slots; i++)
22856a34939Shaad 		for (c = t->slots[i]; c; c = n) {
22956a34939Shaad 			n = c->next;
23056a34939Shaad 			f(c->data);
23156a34939Shaad 		}
23256a34939Shaad }
23356a34939Shaad 
dm_hash_wipe(struct dm_hash_table * t)23456a34939Shaad void dm_hash_wipe(struct dm_hash_table *t)
23556a34939Shaad {
23656a34939Shaad 	_free_nodes(t);
23756a34939Shaad 	memset(t->slots, 0, sizeof(struct dm_hash_node *) * t->num_slots);
23856a34939Shaad 	t->num_nodes = 0u;
23956a34939Shaad }
24056a34939Shaad 
dm_hash_get_key(struct dm_hash_table * t __attribute ((unused)),struct dm_hash_node * n)24156a34939Shaad char *dm_hash_get_key(struct dm_hash_table *t __attribute((unused)),
24256a34939Shaad 		      struct dm_hash_node *n)
24356a34939Shaad {
24456a34939Shaad 	return n->key;
24556a34939Shaad }
24656a34939Shaad 
dm_hash_get_data(struct dm_hash_table * t __attribute ((unused)),struct dm_hash_node * n)24756a34939Shaad void *dm_hash_get_data(struct dm_hash_table *t __attribute((unused)),
24856a34939Shaad 		       struct dm_hash_node *n)
24956a34939Shaad {
25056a34939Shaad 	return n->data;
25156a34939Shaad }
25256a34939Shaad 
_next_slot(struct dm_hash_table * t,unsigned s)25356a34939Shaad static struct dm_hash_node *_next_slot(struct dm_hash_table *t, unsigned s)
25456a34939Shaad {
25556a34939Shaad 	struct dm_hash_node *c = NULL;
25656a34939Shaad 	unsigned i;
25756a34939Shaad 
25856a34939Shaad 	for (i = s; i < t->num_slots && !c; i++)
25956a34939Shaad 		c = t->slots[i];
26056a34939Shaad 
26156a34939Shaad 	return c;
26256a34939Shaad }
26356a34939Shaad 
dm_hash_get_first(struct dm_hash_table * t)26456a34939Shaad struct dm_hash_node *dm_hash_get_first(struct dm_hash_table *t)
26556a34939Shaad {
26656a34939Shaad 	return _next_slot(t, 0);
26756a34939Shaad }
26856a34939Shaad 
dm_hash_get_next(struct dm_hash_table * t,struct dm_hash_node * n)26956a34939Shaad struct dm_hash_node *dm_hash_get_next(struct dm_hash_table *t, struct dm_hash_node *n)
27056a34939Shaad {
27156a34939Shaad 	unsigned h = _hash(n->key, n->keylen) & (t->num_slots - 1);
27256a34939Shaad 
27356a34939Shaad 	return n->next ? n->next : _next_slot(t, h + 1);
27456a34939Shaad }
275