00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 # include "lclintMacros.nf"
00037 # include "basic.h"
00038
00039
00040 # define hbucket_undefined 0
00041
00042 static bool hbucket_isNull ( hbucket h)
00043 {
00044 return (h == hbucket_undefined);
00045 }
00046
00047 static hentry
00048 hentry_create (cstring key, int val)
00049 {
00050 hentry h;
00051
00052 h.key = key;
00053 h.val = val;
00054 return (h);
00055 }
00056
00057 static bool
00058 hbucket_isEmpty (hbucket h)
00059 {
00060 return (h == hbucket_undefined || h->size == 0);
00061 }
00062
00063 static cstring
00064 hbucket_unparse (hbucket h)
00065 {
00066 cstring s = cstring_undefined;
00067
00068 if (!hbucket_isNull (h))
00069 {
00070 int i;
00071
00072 for (i = 0; i < h->size; i++)
00073 {
00074 s = message ("%q %s:%d", s, h->entries[i].key, h->entries[i].val);
00075 }
00076 }
00077
00078 return s;
00079 }
00080
00081 static hbucket
00082 hbucket_single (hentry e)
00083 {
00084 hbucket h = (hbucket) dmalloc (sizeof (*h));
00085
00086 h->size = 1;
00087 h->nspace = HBUCKET_BASESIZE - 1;
00088 h->entries = (hentry *) dmalloc (HBUCKET_BASESIZE * sizeof (*h->entries));
00089 h->entries[0] = e;
00090
00091 return (h);
00092 }
00093
00094 static void
00095 hbucket_grow ( hbucket h)
00096 {
00097 int i;
00098 hentry *newentries;
00099
00100 h->nspace += HBUCKET_BASESIZE;
00101
00102 newentries = (hentry *)
00103 dmalloc ((h->size + HBUCKET_BASESIZE) * sizeof (*newentries));
00104
00105 for (i = 0; i < h->size; i++)
00106 {
00107 newentries[i] = h->entries[i];
00108 }
00109
00110 sfree (h->entries);
00111 h->entries = newentries;
00112 }
00113
00114 static int hbucket_lookup (hbucket p_h, cstring p_key);
00115
00116
00117
00118
00119
00120
00121 static void
00122 hbucket_add ( hbucket h, hentry e)
00123 {
00124 int exloc = hbucket_lookup (h, e.key);
00125
00126
00127 if (exloc != HBUCKET_DNE)
00128 {
00129 h->entries[exloc].key = e.key;
00130 h->entries[exloc].val = e.val;
00131 return;
00132 }
00133
00134 if (h->nspace == 0)
00135 {
00136 hbucket_grow (h);
00137 }
00138
00139 h->entries[h->size] = e;
00140 h->size++;
00141 h->nspace--;
00142 }
00143
00144 static int
00145 hbucket_ncollisions (hbucket h)
00146 {
00147 if (!hbucket_isNull (h) && (h->size > 1))
00148 return (h->size - 1);
00149 else
00150 return 0;
00151 }
00152
00153 int
00154 hbucket_lookup (hbucket h, cstring key)
00155 {
00156 if (!hbucket_isNull (h))
00157 {
00158 int i;
00159
00160 for (i = 0; i < h->size; i++)
00161 {
00162 if (cstring_equal (h->entries[i].key, key))
00163 {
00164 return h->entries[i].val;
00165 }
00166 }
00167 }
00168
00169 return HBUCKET_DNE;
00170 }
00171
00172 static
00173 void hbucket_free ( hbucket h)
00174 {
00175 if (!hbucket_isNull (h))
00176 {
00177 sfree (h->entries);
00178 sfree (h);
00179 }
00180 }
00181
00182 void
00183 hashTable_free ( hashTable h)
00184 {
00185 int i;
00186
00187 for (i = 0; i < h->size; i++)
00188 {
00189 hbucket_free (h->buckets[i]);
00190 }
00191
00192 sfree (h->buckets);
00193 sfree (h);
00194 }
00195
00196 static int
00197 hashTable_countCollisions (hashTable h)
00198 {
00199 int nc = 0;
00200 int i;
00201
00202 for (i = 0; i < h->size; i++)
00203 {
00204 nc += hbucket_ncollisions (h->buckets[i]);
00205 }
00206
00207 return (nc);
00208 }
00209
00210
00211 static int
00212 hashTable_countEmpty (hashTable h)
00213 {
00214 int nc = 0;
00215 int i;
00216
00217 for (i = 0; i < h->size; i++)
00218 {
00219 if (hbucket_isEmpty (h->buckets[i]))
00220 {
00221 nc++;
00222 }
00223 }
00224
00225 return (nc);
00226 }
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238 static unsigned int RandomNumbers[256] =
00239 {
00240 #include "256_random_numbers.nf"
00241 };
00242
00243
00244 static unsigned int
00245 hashTable_hashValue (hashTable h, cstring key)
00246 {
00247 char *p;
00248 unsigned int hash_value = 0;
00249
00250 for (p = cstring_toCharsSafe (key); *p != '\0'; p++)
00251 {
00252 hash_value = (hash_value << 1) ^ RandomNumbers[*p % 256];
00253 }
00254
00255 return (hash_value % h->size);
00256 }
00257
00258 static hbucket
00259 hashTable_hash (hashTable h, cstring key)
00260 {
00261 return h->buckets[hashTable_hashValue (h, key)];
00262 }
00263
00264
00265 hashTable
00266 hashTable_create (int size)
00267 {
00268 int i;
00269 hashTable h = (hashTable) dmalloc (sizeof (*h));
00270
00271 h->size = size;
00272 h->nentries = 0;
00273 h->buckets = (hbucket *) dmalloc (sizeof (*h->buckets) * size);
00274
00275
00276 for (i = 0; i < size; i++)
00277 {
00278 h->buckets[i] = hbucket_undefined;
00279 }
00280
00281 return h;
00282 }
00283
00284
00285 static void
00286 hashTable_print (hashTable h)
00287 {
00288 int i;
00289
00290 for (i = 0; i < h->size; i++)
00291 {
00292 hbucket hb = h->buckets[i];
00293
00294 if (hb != NULL)
00295 {
00296 llmsg (message ("%d. %s\n", i, hbucket_unparse (hb)));
00297 }
00298 }
00299
00300 llmsg (message ("size: %d, collisions: %d, empty: %d",
00301 h->size,
00302 hashTable_countCollisions (h),
00303 hashTable_countEmpty (h)));
00304 }
00305
00306
00307 cstring
00308 hashTable_stats (hashTable h)
00309 {
00310 return (message ("size: %d, collisions: %d, empty: %d\n",
00311 h->size, hashTable_countCollisions (h),
00312 hashTable_countEmpty (h)));
00313 }
00314
00315 static void
00316 hashTable_addEntry (hashTable h, hentry e)
00317 {
00318 unsigned int hindex = hashTable_hashValue (h, e.key);
00319
00320
00321
00322
00323
00324
00325 h->nentries++;
00326
00327 if (hbucket_isNull (h->buckets[hindex]))
00328 {
00329 h->buckets[hindex] = hbucket_single (e);
00330 }
00331 else
00332 {
00333 hbucket_add (h->buckets[hindex], e);
00334 }
00335 }
00336
00337 void
00338 hashTable_insert (hashTable h, cstring key, int value)
00339 {
00340 unsigned int hindex;
00341 hbucket hb;
00342 hentry e;
00343
00344
00345 h->nentries++;
00346
00347
00348
00349
00350
00351 if (h->nentries * 162 > h->size * 100)
00352 {
00353 int i;
00354 int oldsize = h->size;
00355 int newsize = 1 + ((oldsize * 26244) / 10000);
00356 hbucket *oldbuckets = h->buckets;
00357
00358
00359 h->size = newsize;
00360 h->nentries = 0;
00361 h->buckets = (hbucket *) dmalloc (sizeof (*h->buckets) * newsize);
00362
00363
00364 for (i = 0; i < newsize; i++)
00365 {
00366 h->buckets[i] = hbucket_undefined;
00367 }
00368
00369
00370 for (i = 0; i < oldsize; i++)
00371 {
00372 hbucket bucket = oldbuckets[i];
00373
00374 if (!hbucket_isNull (bucket))
00375 {
00376 int j;
00377
00378 for (j = 0; j < bucket->size; j++)
00379 {
00380 hashTable_addEntry (h, bucket->entries[j]);
00381 }
00382
00383 sfree (bucket);
00384 }
00385 }
00386
00387 sfree (oldbuckets);
00388 }
00389
00390
00391 e = hentry_create (key, value);
00392 hindex = hashTable_hashValue (h, key);
00393 hb = h->buckets[hindex];
00394
00395 if (hbucket_isNull (hb))
00396 {
00397 h->buckets[hindex] = hbucket_single (e);
00398 }
00399 else
00400 {
00401 hbucket_add (hb, e);
00402 }
00403
00404 }
00405
00406 int
00407 hashTable_lookup (hashTable h, cstring key)
00408 {
00409 hbucket hb = hashTable_hash (h, key);
00410
00411 return (hbucket_lookup (hb, key));
00412 }
00413
00414
00415
00416
00417
00418 void
00419 hashTable_replaceKey (hashTable h, cstring oldkey, cstring newkey)
00420 {
00421 hbucket hb = hashTable_hash (h, oldkey);
00422
00423 llassert (cstring_equal (oldkey, newkey));
00424
00425 if (!hbucket_isNull (hb))
00426 {
00427 int i;
00428
00429 for (i = 0; i < hb->size; i++)
00430 {
00431 if (cstring_equal (hb->entries[i].key, oldkey))
00432 {
00433 hb->entries[i].key = newkey;
00434 return;
00435 }
00436 }
00437 }
00438
00439 llbug (message ("hashTable_replaceKey: %s not found", oldkey));
00440 }
00441
00442 void
00443 hashTable_remove (hashTable h, cstring key)
00444 {
00445 hbucket hb = hashTable_hash (h, key);
00446
00447 if (!hbucket_isNull (hb))
00448 {
00449 int i;
00450
00451 for (i = 0; i < hb->size; i++)
00452 {
00453 if (cstring_equal (hb->entries[i].key, key))
00454 {
00455 if (i < hb->size - 1)
00456 {
00457 hb->entries[i] = hb->entries[hb->size - 1];
00458 }
00459
00460 hb->size--;
00461 return;
00462 }
00463 }
00464 }
00465
00466 llbug (message ("hashTable_removeKey: %s not found", key));
00467 }
00468
00469