linkhash.c
Go to the documentation of this file.
00001 /*
00002  * $Id: linkhash.c,v 1.4 2006/01/26 02:16:28 mclark Exp $
00003  *
00004  * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
00005  * Michael Clark <michael@metaparadigm.com>
00006  *
00007  * This library is free software; you can redistribute it and/or modify
00008  * it under the terms of the MIT license. See COPYING for details.
00009  *
00010  */
00011 
00012 #include "config.h"
00013 
00014 #include <stdio.h>
00015 #include <string.h>
00016 #include <stdlib.h>
00017 #include <stdarg.h>
00018 #include <stddef.h>
00019 #include <limits.h>
00020 
00021 #include "linkhash.h"
00022 
00023 void lh_abort(const char *msg, ...)
00024 {
00025         va_list ap;
00026         va_start(ap, msg);
00027         vprintf(msg, ap);
00028         exit(1);
00029 }
00030 
00031 unsigned long lh_ptr_hash(void *k)
00032 {
00033         /* CAW: refactored to be 64bit nice */
00034         return (unsigned long)((((ptrdiff_t)k * LH_PRIME) >> 4) & ULONG_MAX);
00035 }
00036 
00037 int lh_ptr_equal(void *k1, void *k2)
00038 {
00039         return (k1 == k2);
00040 }
00041 
00042 unsigned long lh_char_hash(void *k)
00043 {
00044         unsigned int h = 0;
00045         const char* data = k;
00046  
00047         while( *data!=0 ) h = h*129 + (unsigned int)(*data++) + LH_PRIME;
00048 
00049         return h;
00050 }
00051 
00052 int lh_char_equal(void *k1, void *k2)
00053 {
00054         return (strcmp((char*)k1, (char*)k2) == 0);
00055 }
00056 
00057 struct lh_table* lh_table_new(int size, char *name,
00058                               lh_entry_free_fn *free_fn,
00059                               lh_hash_fn *hash_fn,
00060                               lh_equal_fn *equal_fn)
00061 {
00062         int i;
00063         struct lh_table *t;
00064 
00065         t = calloc(1, sizeof(struct lh_table));
00066         if(!t) lh_abort("lh_table_new: calloc failed\n");
00067         t->count = 0;
00068         t->size = size;
00069         t->name = name;
00070         t->table = calloc( (size_t) size,sizeof(struct lh_entry));
00071         if(!t->table) lh_abort("lh_table_new: calloc failed\n");
00072         t->free_fn = free_fn;
00073         t->hash_fn = hash_fn;
00074         t->equal_fn = equal_fn;
00075         for(i = 0; i < size; i++) t->table[i].k = LH_EMPTY;
00076         return t;
00077 }
00078 
00079 struct lh_table* lh_kchar_table_new(int size, char *name,
00080                                     lh_entry_free_fn *free_fn)
00081 {
00082         return lh_table_new(size, name, free_fn, lh_char_hash, lh_char_equal);
00083 }
00084 
00085 struct lh_table* lh_kptr_table_new(int size, char *name,
00086                                    lh_entry_free_fn *free_fn)
00087 {
00088         return lh_table_new(size, name, free_fn, lh_ptr_hash, lh_ptr_equal);
00089 }
00090 
00091 void lh_table_resize(struct lh_table *t, int new_size)
00092 {
00093         struct lh_table *new_t;
00094         struct lh_entry *ent;
00095 
00096         new_t = lh_table_new(new_size, t->name, NULL, t->hash_fn, t->equal_fn);
00097         ent = t->head;
00098         while(ent) {
00099                 lh_table_insert(new_t, ent->k, ent->v);
00100                 ent = ent->next;
00101         }
00102         free(t->table);
00103         t->table = new_t->table;
00104         t->size = new_size;
00105         t->head = new_t->head;
00106         t->tail = new_t->tail;
00107         t->resizes++;
00108         free(new_t);
00109 }
00110 
00111 void lh_table_free(struct lh_table *t)
00112 {
00113         struct lh_entry *c;
00114         for(c = t->head; c != NULL; c = c->next) {
00115                 if(t->free_fn) {
00116                         t->free_fn(c);
00117                 }
00118         }
00119         free(t->table);
00120         free(t);
00121 }
00122 
00123 
00124 int lh_table_insert(struct lh_table *t, void *k, void *v)
00125 {
00126         unsigned long h, n;
00127 
00128         t->inserts++;
00129         if(t->count > t->size * 0.66) lh_table_resize(t, t->size * 2);
00130 
00131         h = t->hash_fn(k);
00132         n = h % t->size;
00133 
00134         while( 1 ) {
00135                 if(t->table[n].k == LH_EMPTY || t->table[n].k == LH_FREED) break;
00136                 t->collisions++;
00137                 if(++n ==  (size_t) t->size) n = 0;
00138         }
00139 
00140         t->table[n].k = k;
00141         t->table[n].v = v;
00142         t->count++;
00143 
00144         if(t->head == NULL) {
00145                 t->head = t->tail = &t->table[n];
00146                 t->table[n].next = t->table[n].prev = NULL;
00147         } else {
00148                 t->tail->next = &t->table[n];
00149                 t->table[n].prev = t->tail;
00150                 t->table[n].next = NULL;
00151                 t->tail = &t->table[n];
00152         }
00153 
00154         return 0;
00155 }
00156 
00157 
00158 struct lh_entry* lh_table_lookup_entry(struct lh_table *t, void *k)
00159 {
00160         unsigned long h = t->hash_fn(k);
00161         unsigned long n = h % t->size;
00162 
00163         t->lookups++;
00164         while( 1 ) {
00165                 if(t->table[n].k == LH_EMPTY) return NULL;
00166                 if(t->table[n].k != LH_FREED &&
00167                    t->equal_fn(t->table[n].k, k)) return &t->table[n];
00168                 if(++n ==  (size_t) t->size) n = 0;
00169         }
00170         return NULL;
00171 }
00172 
00173 
00174 void* lh_table_lookup(struct lh_table *t, void *k)
00175 {
00176         struct lh_entry *e = lh_table_lookup_entry(t, k);
00177         if(e) return e->v;
00178         return NULL;
00179 }
00180 
00181 
00182 int lh_table_delete_entry(struct lh_table *t, struct lh_entry *e)
00183 {
00184         ptrdiff_t n = (ptrdiff_t)(e - t->table); /* CAW: fixed to be 64bit nice, still need the crazy negative case... */
00185 
00186         /* CAW: this is bad, really bad, maybe stack goes other direction on this machine... */
00187         if(n < 0) { return -2; }
00188 
00189         if(t->table[n].k == LH_EMPTY || t->table[n].k == LH_FREED) return -1;
00190         t->count--;
00191         if(t->free_fn) t->free_fn(e);
00192         t->table[n].v = NULL;
00193         t->table[n].k = LH_FREED;
00194         if(t->tail == &t->table[n] && t->head == &t->table[n]) {
00195                 t->head = t->tail = NULL;
00196         } else if (t->head == &t->table[n]) {
00197                 t->head->next->prev = NULL;
00198                 t->head = t->head->next;
00199         } else if (t->tail == &t->table[n]) {
00200                 t->tail->prev->next = NULL;
00201                 t->tail = t->tail->prev;
00202         } else {
00203                 t->table[n].prev->next = t->table[n].next;
00204                 t->table[n].next->prev = t->table[n].prev;
00205         }
00206         t->table[n].next = t->table[n].prev = NULL;
00207         return 0;
00208 }
00209 
00210 
00211 int lh_table_delete(struct lh_table *t, void *k)
00212 {
00213         struct lh_entry *e = lh_table_lookup_entry(t, k);
00214         if(!e) return -1;
00215         return lh_table_delete_entry(t, e);
00216 }
00217 


csm_ros
Author(s): Gaƫl Ecorchard , Ivan Dryanovski, William Morris, Andrea Censi
autogenerated on Sat Jun 8 2019 19:52:42