Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
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
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);
00185
00186
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