/* $Id: hash.c,v 1.75 2011/06/28 00:13:48 sbajic Exp $ */ /* DSPAM COPYRIGHT (C) 2002-2012 DSPAM PROJECT This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include "hash.h" /* Read-only */ static unsigned long bnr_hash_prime_list[bnr_hash_num_primes] = { 53ul, 97ul, 193ul, 389ul, 769ul, 1543ul, 3079ul, 6151ul, 12289ul, 24593ul, 49157ul, 98317ul, 196613ul, 393241ul, 786433ul, 1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul, 50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul, 1610612741ul, 3221225473ul, 4294967291ul }; struct bnr_hash_node * bnr_hash_node_create (const char *name) { struct bnr_hash_node *node = (struct bnr_hash_node *) calloc (1, sizeof (struct bnr_hash_node)); if (node) node->name = strdup(name); return node; } struct bnr_hash * bnr_hash_create (unsigned long size) { unsigned long i = 0; struct bnr_hash *hash = (struct bnr_hash *) malloc (sizeof (struct bnr_hash)); if (hash == NULL) return NULL; while (bnr_hash_prime_list[i] < size) i++; hash->size = bnr_hash_prime_list[i]; hash->items = 0; hash->tbl = (struct bnr_hash_node **) calloc (hash->size, sizeof (struct bnr_hash_node *)); if (hash->tbl == NULL) { free (hash); return NULL; } return (hash); } int bnr_hash_destroy (struct bnr_hash *hash) { struct bnr_hash_node *node, *next; struct bnr_hash_c c; if (hash == NULL) return -1; node = c_bnr_hash_first (hash, &c); while (node != NULL) { char *x = node->name; next = c_bnr_hash_next (hash, &c); bnr_hash_delete (hash, node->name); free (x); node = next; } free (hash->tbl); free (hash); return 0; } int bnr_hash_delete (struct bnr_hash *hash, const char *name) { unsigned long hash_code; struct bnr_hash_node *node; struct bnr_hash_node *del_node = NULL; struct bnr_hash_node *parent = NULL; hash_code = bnr_hash_hashcode(hash, name); node = hash->tbl[hash_code]; while (node) { if (!strcmp(name, node->name)) { del_node = node; node = NULL; } else { parent = node; node = node->next; } } if (del_node == NULL) return -2; if (parent) parent->next = del_node->next; else hash->tbl[hash_code] = del_node->next; free (del_node); hash->items--; return 0; } struct bnr_hash_node * c_bnr_hash_first (struct bnr_hash *hash, struct bnr_hash_c *c) { c->iter_index = 0; c->iter_next = (struct bnr_hash_node *) NULL; return (c_bnr_hash_next (hash, c)); } struct bnr_hash_node * c_bnr_hash_next (struct bnr_hash *hash, struct bnr_hash_c *c) { unsigned long index; struct bnr_hash_node *node = c->iter_next; if (node) { c->iter_next = node->next; return (node); } while (c->iter_index < hash->size) { index = c->iter_index++; if (hash->tbl[index]) { c->iter_next = hash->tbl[index]->next; return (hash->tbl[index]); } } return NULL; } int bnr_hash_hit (struct bnr_hash *hash, const char *name) { unsigned long hash_code; struct bnr_hash_node *parent; struct bnr_hash_node *node; struct bnr_hash_node *new_node = NULL; hash_code = bnr_hash_hashcode(hash, name); parent = NULL; node = hash->tbl[hash_code]; while (node != NULL) { if (!strcmp(name, node->name)) { new_node = node; node = NULL; } else { parent = node; node = node->next; } } if (new_node != NULL) return 0; /* Create a new node */ new_node = bnr_hash_node_create(name); hash->items++; /* Insert */ if (parent) { parent->next = new_node; return 0; } /* No existing parent; add directly to hash table */ hash->tbl[hash_code] = new_node; return 0; } float bnr_hash_value (struct bnr_hash *hash, const char *name) { unsigned long hash_code; struct bnr_hash_node *node; hash_code = bnr_hash_hashcode(hash, name); node = hash->tbl[hash_code]; while (node != NULL) { if (!strcmp(node->name, name)) return node->value; node = node->next; } return 0.00000; } int bnr_hash_set (struct bnr_hash *hash, const char *name, float value) { unsigned long hash_code; struct bnr_hash_node *node; if (!name) return 0; hash_code = bnr_hash_hashcode(hash, name); node = hash->tbl[hash_code]; while (node != NULL) { if (!strcmp(node->name, name)) { node->value = value; return 0; } node = node->next; } return 0; } long bnr_hash_hashcode(struct bnr_hash *hash, const char *name) { unsigned long val = 0; if (!name) return 0; for (; *name; ++name) val = 5 * val + *name; return(val % hash->size); }