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