/* * Copyright (C) 2001 Sistina Software * * This file is released under the LGPL. */ #include "dbg_malloc.h" #include "hash.h" #include "log.h" struct hash_node { struct hash_node *next; void *data; char key[1]; }; struct hash_table { int num_nodes; int num_slots; struct hash_node **slots; }; /* Permutation of the Integers 0 through 255 */ static unsigned char _nums[] = { 1, 14,110, 25, 97,174,132,119,138,170,125,118, 27,233,140, 51, 87,197,177,107,234,169, 56, 68, 30, 7,173, 73,188, 40, 36, 65, 49,213,104,190, 57,211,148,223, 48,115, 15, 2, 67,186,210, 28, 12,181,103, 70, 22, 58, 75, 78,183,167,238,157,124,147,172,144, 176,161,141, 86, 60, 66,128, 83,156,241, 79, 46,168,198, 41,254, 178, 85,253,237,250,154,133, 88, 35,206, 95,116,252,192, 54,221, 102,218,255,240, 82,106,158,201, 61, 3, 89, 9, 42,155,159, 93, 166, 80, 50, 34,175,195,100, 99, 26,150, 16,145, 4, 33, 8,189, 121, 64, 77, 72,208,245,130,122,143, 55,105,134, 29,164,185,194, 193,239,101,242, 5,171,126, 11, 74, 59,137,228,108,191,232,139, 6, 24, 81, 20,127, 17, 91, 92,251,151,225,207, 21, 98,113,112, 84,226, 18,214,199,187, 13, 32, 94,220,224,212,247,204,196, 43, 249,236, 45,244,111,182,153,136,129, 90,217,202, 19,165,231, 71, 230,142, 96,227, 62,179,246,114,162, 53,160,215,205,180, 47,109, 44, 38, 31,149,135, 0,216, 52, 63, 23, 37, 69, 39,117,146,184, 163,200,222,235,248,243,219, 10,152,131,123,229,203, 76,120,209 }; static struct hash_node *_create_node(const char *str) { /* remember sizeof(n) includes an extra char from key[1], so not adding 1 to the strlen as you would expect */ struct hash_node *n = dbg_malloc(sizeof(*n) + strlen(str)); if (n) strcpy(n->key, str); return n; } static unsigned _hash(const char *str) { unsigned long int h = 0, g; while (*str) { h <<= 4; h += _nums[(int) *str++]; g = h & ((unsigned long) 0xf << 16u); if (g) { h ^= g >> 16u; h ^= g >> 5u; } } return h; } struct hash_table *hash_create(unsigned size_hint) { size_t len; unsigned new_size = 16u; struct hash_table *hc = dbg_malloc(sizeof(*hc)); if (!hc) { stack; return 0; } memset(hc, 0, sizeof(*hc)); /* round size hint up to a power of two */ while (new_size < size_hint) new_size = new_size << 1; hc->num_slots = new_size; len = sizeof(*(hc->slots)) * new_size; if (!(hc->slots = dbg_malloc(len))) { stack; goto bad; } memset(hc->slots, 0, len); return hc; bad: dbg_free(hc->slots); dbg_free(hc); return 0; } static void _free_nodes(struct hash_table *t) { struct hash_node *c, *n; int i; for (i = 0; i < t->num_slots; i++) for (c = t->slots[i]; c; c = n) { n = c->next; dbg_free(c); } } void hash_destroy(struct hash_table *t) { _free_nodes(t); dbg_free(t->slots); dbg_free(t); } static inline struct hash_node **_find(struct hash_table *t, const char *key) { unsigned h = _hash(key) & (t->num_slots - 1); struct hash_node **c; for(c = &t->slots[h]; *c; c = &((*c)->next)) if(!strcmp(key, (*c)->key)) break; return c; } void *hash_lookup(struct hash_table *t, const char *key) { struct hash_node **c = _find(t, key); return *c ? (*c)->data : 0; } int hash_insert(struct hash_table *t, const char *key, void *data) { struct hash_node **c = _find(t, key); if(*c) (*c)->data = data; else { struct hash_node *n = _create_node(key); if (!n) return 0; n->data = data; n->next = 0; *c = n; t->num_nodes++; } return 1; } void hash_remove(struct hash_table *t, const char *key) { struct hash_node **c = _find(t, key); if (*c) { struct hash_node *old = *c; *c = (*c)->next; dbg_free(old); t->num_nodes--; } } unsigned hash_get_num_entries(struct hash_table *t) { return t->num_nodes; } void hash_iter(struct hash_table *t, iterate_fn f) { struct hash_node *c; int i; for (i = 0; i < t->num_slots; i++) for (c = t->slots[i]; c; c = c->next) f(c->data); } void hash_wipe(struct hash_table *t) { _free_nodes(t); memset(t->slots, 0, sizeof(struct hash_node *) * t->num_slots); t->num_nodes = 0; } char *hash_get_key(struct hash_table *t, struct hash_node *n) { return n->key; } void *hash_get_data(struct hash_table *t, struct hash_node *n) { return n->data; } static struct hash_node *_next_slot(struct hash_table *t, unsigned int s) { struct hash_node *c = NULL; int i; for (i = s; i < t->num_slots && !c; i++) c = t->slots[i]; return c; } struct hash_node *hash_get_first(struct hash_table *t) { return _next_slot(t, 0); } struct hash_node *hash_get_next(struct hash_table *t, struct hash_node *n) { unsigned int h = _hash(n->key) & (t->num_slots - 1); return n->next ? n->next : _next_slot(t, h + 1); }