00001
00002
00003
00004
00005
00006
00007 #include <stdio.h>
00008 #include <stdlib.h>
00009 #include <string.h>
00010 #include "hash.h"
00011
00012 #define HASH_LIMIT 0.5
00013
00014
00015
00016
00017 typedef struct hash_node_t
00018 {
00019 void *data;
00020 char * key;
00021 struct hash_node_t *next;
00022 } hash_node_t;
00023
00024
00025
00026
00027
00028
00029
00030 static int
00031 hash (const hash_t *tptr, const char *key)
00032 {
00033 int i = 0;
00034 int hashvalue;
00035
00036 while (*key != '\0')
00037 i = (i<<3) + (*key++ - '0');
00038
00039 hashvalue = (((i*1103515249) >> tptr->downshift) & tptr->mask);
00040 if (hashvalue < 0) {
00041 hashvalue = 0;
00042 }
00043
00044 return hashvalue;
00045 }
00046
00047
00048
00049
00050
00051
00052 static void
00053 rebuild_table (hash_t *tptr)
00054 {
00055 hash_node_t **old_bucket;
00056 hash_node_t *old_hash;
00057 hash_node_t *tmp;
00058
00059 int old_size;
00060 int h;
00061 int i;
00062
00063 old_bucket = tptr->bucket;
00064 old_size = tptr->size;
00065
00066
00067 hash_init (tptr, old_size << 1);
00068
00069 for (i=0; i<old_size; i++)
00070 {
00071 old_hash = old_bucket[i];
00072
00073 while (old_hash)
00074 {
00075 tmp = old_hash;
00076 old_hash = old_hash->next;
00077 h = hash (tptr, tmp->key);
00078 tmp->next = tptr->bucket[h];
00079 tptr->bucket[h] = tmp;
00080 tptr->entries++;
00081 }
00082 }
00083
00084
00085 free (old_bucket);
00086
00087 return;
00088 }
00089
00090
00091
00092
00093
00094
00095
00096 void
00097 hash_init (hash_t *tptr, int buckets)
00098 {
00099
00100
00101 if (buckets == 0)
00102 buckets = 16;
00103
00104
00105 tptr->entries = 0;
00106 tptr->size = 2;
00107 tptr->mask = 1;
00108 tptr->downshift = 29;
00109
00110
00111 while (tptr->size < buckets)
00112 {
00113 tptr->size <<= 1;
00114 tptr->mask = (tptr->mask << 1) + 1;
00115 tptr->downshift--;
00116 }
00117
00118
00119 tptr->bucket = (hash_node_t **) calloc (tptr->size, sizeof (hash_node_t *));
00120
00121 return;
00122 }
00123
00124
00125
00126
00127
00128
00129
00130
00131 void *
00132 hash_lookup(const hash_t *tptr, const char *key)
00133 {
00134 int h;
00135 hash_node_t *node;
00136
00137
00138
00139 h = hash (tptr, key);
00140 for (node = tptr->bucket[h]; node != NULL; node = node->next)
00141 {
00142 if (!strcmp (node->key, key))
00143 break;
00144 }
00145
00146
00147 return (node ? node->data : NULL);
00148 }
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158 void *
00159 hash_insert (hash_t *tptr, const char *key, void *data)
00160 {
00161 void *tmp;
00162 hash_node_t *node;
00163 int h;
00164
00165
00166
00167 if ((tmp = hash_lookup (tptr, key)) != NULL)
00168 return (tmp);
00169
00170
00171 while (tptr->entries >= HASH_LIMIT * tptr->size)
00172 rebuild_table (tptr);
00173
00174
00175 h = hash (tptr, key);
00176 node = (struct hash_node_t *) malloc (sizeof (hash_node_t));
00177 node->data = data;
00178 node->key = strdup (key);
00179 node->next = tptr->bucket[h];
00180 tptr->bucket[h] = node;
00181 tptr->entries++;
00182
00183 return NULL;
00184 }
00185
00186
00187
00188
00189
00190
00191
00192
00193 void *
00194 hash_delete(hash_t *tptr, const char *key)
00195 {
00196 hash_node_t *node;
00197 hash_node_t *last;
00198 void *data;
00199 int h;
00200
00201
00202 h = hash (tptr, key);
00203 for (node = tptr->bucket[h]; node; node = node->next)
00204 {
00205 if (!strcmp (node->key, key))
00206 break;
00207 }
00208
00209
00210 if (node == NULL)
00211 return NULL;
00212
00213
00214 if (node == tptr->bucket[h])
00215 tptr->bucket[h] = node->next;
00216 else
00217 {
00218
00219 for (last = tptr->bucket[h]; last && last->next; last = last->next)
00220 {
00221 if (last->next == node)
00222 break;
00223 }
00224 last->next = node->next;
00225 }
00226
00227
00228 data = node->data;
00229 free (node->key);
00230 free (node);
00231
00232 return (data);
00233 }
00234
00235
00236
00237
00238
00239
00240
00241 void
00242 hash_destroy (hash_t *tptr, void (*free_data)(void *))
00243 {
00244 hash_node_t *node;
00245 hash_node_t *last;
00246 int i;
00247
00248 for (i = 0; i < tptr->size; i++)
00249 {
00250 node = tptr->bucket[i];
00251 while (node != NULL)
00252 {
00253 last = node;
00254 node = node->next;
00255 free_data (last->data);
00256 free (last->key);
00257 free (last);
00258 }
00259 }
00260
00261
00262 if (tptr->bucket != NULL)
00263 {
00264 free (tptr->bucket);
00265 memset (tptr, 0, sizeof (hash_t));
00266 }
00267 }
00268
00269
00270
00271
00272
00273
00274 static float alos(hash_t *tptr) {
00275 int i,j;
00276 float alos=0;
00277 hash_node_t *node;
00278
00279
00280 for (i=0; i<tptr->size; i++) {
00281 for (node=tptr->bucket[i], j=0; node!=NULL; node=node->next, j++);
00282 if (j)
00283 alos+=((j*(j+1))>>1);
00284 }
00285
00286 return(tptr->entries ? alos/tptr->entries : 0);
00287 }
00288
00289
00290
00291
00292
00293
00294
00295 char * hash_stats(hash_t *tptr) {
00296 static char buf[1024];
00297
00298 sprintf(buf, "%u slots, %u entries, and %1.2f ALOS",
00299 (int)tptr->size, (int)tptr->entries, alos(tptr));
00300
00301 return(buf);
00302 }
00303