00001
00002
00003
00004
00005
00006 #include "common.h"
00007 #include "localmem.h"
00008 #include "hash.h"
00009 #include "obscure.h"
00010 #include "dystring.h"
00011
00012 static char const rcsid[] = "$Id: hash.c,v 1.36 2007/04/14 17:07:27 markd Exp $";
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042 bits32 hashString(char *string)
00043
00044 {
00045 char *keyStr = string;
00046 unsigned int result = 0;
00047 int c;
00048
00049 while ((c = *keyStr++) != '\0')
00050 {
00051 result += (result<<3) + c;
00052 }
00053 return result;
00054 }
00055
00056 bits32 hashCrc(char *string)
00057
00058 {
00059 unsigned char *us = (unsigned char *)string;
00060 unsigned char c;
00061 bits32 shiftAcc = 0;
00062 bits32 addAcc = 0;
00063
00064 while ((c = *us++) != 0)
00065 {
00066 shiftAcc <<= 2;
00067 shiftAcc += c;
00068 addAcc += c;
00069 }
00070 return shiftAcc + addAcc;
00071 }
00072
00073 struct hashEl *hashLookup(struct hash *hash, char *name)
00074
00075
00076 {
00077 struct hashEl *el = hash->table[hashString(name)&hash->mask];
00078 while (el != NULL)
00079 {
00080 if (strcmp(el->name, name) == 0)
00081 break;
00082 el = el->next;
00083 }
00084 return el;
00085 }
00086
00087 struct hashEl *hashLookupUpperCase(struct hash *hash, char *name)
00088
00089
00090 {
00091 char s[256];
00092 safef(s, sizeof(s), "%s", name);
00093 touppers(s);
00094 return hashLookup(hash, s);
00095 }
00096
00097
00098 struct hashEl *hashLookupNext(struct hashEl *hashEl)
00099
00100
00101 {
00102 struct hashEl *el = hashEl->next;
00103 while (el != NULL)
00104 {
00105 if (strcmp(el->name, hashEl->name) == 0)
00106 break;
00107 el = el->next;
00108 }
00109 return el;
00110 }
00111
00112 struct hashEl *hashAddN(struct hash *hash, char *name, int nameSize, void *val)
00113
00114 {
00115 struct hashEl *el = lmAlloc(hash->lm, sizeof(*el));
00116 int hashVal = (hashString(name)&hash->mask);
00117 el->name = lmAlloc(hash->lm, nameSize+1);
00118 memcpy(el->name, name, nameSize);
00119 el->val = val;
00120 el->next = hash->table[hashVal];
00121 hash->table[hashVal] = el;
00122 hash->elCount += 1;
00123 return el;
00124 }
00125
00126 struct hashEl *hashAdd(struct hash *hash, char *name, void *val)
00127
00128 {
00129 return hashAddN(hash, name, strlen(name), val);
00130 }
00131
00132 boolean hashMayRemove(struct hash *hash, char *name)
00133
00134
00135 {
00136 return (hashRemove(hash, name) != NULL);
00137 }
00138
00139 void hashMustRemove(struct hash *hash, char *name)
00140
00141
00142 {
00143 if (hashRemove(hash, name) == NULL)
00144 errAbort("attempt to remove non-existant %s from hash", name);
00145 }
00146
00147 void *hashRemove(struct hash *hash, char *name)
00148
00149
00150 {
00151 struct hashEl *hel;
00152 void *ret;
00153 struct hashEl **pBucket = &hash->table[hashString(name)&hash->mask];
00154 for (hel = *pBucket; hel != NULL; hel = hel->next)
00155 if (sameString(hel->name, name))
00156 break;
00157 if (hel == NULL)
00158 return NULL;
00159 ret = hel->val;
00160 if (slRemoveEl(pBucket, hel))
00161 hash->elCount -= 1;
00162 return ret;
00163 }
00164
00165 struct hashEl *hashAddUnique(struct hash *hash, char *name, void *val)
00166
00167 {
00168 if (hashLookup(hash, name) != NULL)
00169 errAbort("%s duplicated, aborting", name);
00170 return hashAdd(hash, name, val);
00171 }
00172
00173 struct hashEl *hashAddSaveName(struct hash *hash, char *name, void *val, char **saveName)
00174
00175
00176
00177
00178
00179 {
00180 struct hashEl *hel = hashAdd(hash, name, val);
00181 *saveName = hel->name;
00182 return hel;
00183 }
00184
00185 struct hashEl *hashStore(struct hash *hash, char *name)
00186
00187
00188 {
00189 struct hashEl *hel;
00190 if ((hel = hashLookup(hash, name)) != NULL)
00191 return hel;
00192 return hashAdd(hash, name, NULL);
00193 }
00194
00195 char *hashStoreName(struct hash *hash, char *name)
00196
00197
00198 {
00199 struct hashEl *hel;
00200 if (name == NULL)
00201 return NULL;
00202 if ((hel = hashLookup(hash, name)) != NULL)
00203 return hel->name;
00204 return hashAdd(hash, name, NULL)->name;
00205 }
00206
00207 int hashIntVal(struct hash *hash, char *name)
00208
00209 {
00210 void *val = hashMustFindVal(hash, name);
00211 return ptToInt(val);
00212 }
00213
00214 int hashIntValDefault(struct hash *hash, char *name, int defaultInt)
00215
00216
00217 {
00218 struct hashEl *hel = hashLookup(hash, name);
00219 if(hel == NULL)
00220 return defaultInt;
00221 return ptToInt(hel->val);
00222 }
00223
00224 void *hashMustFindVal(struct hash *hash, char *name)
00225
00226 {
00227 struct hashEl *hel = hashLookup(hash, name);
00228 if (hel == NULL)
00229 errAbort("%s not found", name);
00230 return hel->val;
00231 }
00232
00233 void *hashFindVal(struct hash *hash, char *name)
00234
00235 {
00236 struct hashEl *hel = hashLookup(hash, name);
00237 if (hel == NULL)
00238 return NULL;
00239 return hel->val;
00240 }
00241
00242 void *hashOptionalVal(struct hash *hash, char *name, void *usual)
00243
00244 {
00245 struct hashEl *hel = hashLookup(hash, name);
00246 if (hel == NULL)
00247 return usual;
00248 else
00249 return hel->val;
00250 }
00251
00252 char *hashMustFindName(struct hash *hash, char *name)
00253
00254
00255 {
00256 struct hashEl *hel = hashLookup(hash, name);
00257 if (hel == NULL)
00258 errAbort("%s not found", name);
00259 return hel->name;
00260 }
00261
00262 struct hashEl *hashAddInt(struct hash *hash, char *name, int val)
00263
00264 {
00265 char *pt = NULL;
00266 return hashAdd(hash, name, pt + val);
00267 }
00268
00269 long long hashIntSum(struct hash *hash)
00270
00271 {
00272 long long sum = 0;
00273 int i;
00274 struct hashEl *hel;
00275 for (i=0; i<hash->size; ++i)
00276 {
00277 for (hel = hash->table[i]; hel != NULL; hel = hel->next)
00278 {
00279 int num = ptToInt(hel->val);
00280 sum += (long long)num;
00281 }
00282 }
00283 return sum;
00284 }
00285
00286 struct hash *newHash(int powerOfTwoSize)
00287
00288 {
00289 struct hash *hash = needMem(sizeof(*hash));
00290 int memBlockPower = 16;
00291 if (powerOfTwoSize == 0)
00292 powerOfTwoSize = 12;
00293 assert(powerOfTwoSize <= hashMaxSize && powerOfTwoSize > 0);
00294 hash->powerOfTwoSize = powerOfTwoSize;
00295 hash->size = (1<<powerOfTwoSize);
00296
00297
00298 if (powerOfTwoSize < 8)
00299 memBlockPower = 8;
00300 else if (powerOfTwoSize < 16)
00301 memBlockPower = powerOfTwoSize;
00302 hash->lm = lmInit(1<<memBlockPower);
00303 hash->mask = hash->size-1;
00304 hash->table = lmAlloc(hash->lm, sizeof(struct hashEl *) * hash->size);
00305 return hash;
00306 }
00307
00308 struct hash *hashFromSlNameList(void *list)
00309
00310
00311 {
00312 struct hash *hash = NULL;
00313 struct slName *namedList = list, *item;
00314 if (!list)
00315 return NULL;
00316 hash = newHash(0);
00317 for (item = namedList; item != NULL; item = item->next)
00318 hashAdd(hash, item->name, item);
00319 return hash;
00320 }
00321
00322 void hashTraverseEls(struct hash *hash, void (*func)(struct hashEl *hel))
00323
00324 {
00325 int i;
00326 struct hashEl *hel;
00327 for (i=0; i<hash->size; ++i)
00328 {
00329 for (hel = hash->table[i]; hel != NULL; hel = hel->next)
00330 func(hel);
00331 }
00332 }
00333
00334 void hashTraverseVals(struct hash *hash, void (*func)(void *val))
00335
00336 {
00337 int i;
00338 struct hashEl *hel;
00339 for (i=0; i<hash->size; ++i)
00340 {
00341 for (hel = hash->table[i]; hel != NULL; hel = hel->next)
00342 func(hel->val);
00343 }
00344 }
00345
00346 int hashElCmp(const void *va, const void *vb)
00347
00348 {
00349 const struct hashEl *a = *((struct hashEl **)va);
00350 const struct hashEl *b = *((struct hashEl **)vb);
00351 return strcmp(a->name, b->name);
00352 }
00353
00354 void *hashElFindVal(struct hashEl *list, char *name)
00355
00356 {
00357 struct hashEl *el;
00358 for (el = list; el != NULL; el = el->next)
00359 {
00360 if (strcmp(el->name, name) == 0)
00361 return el->val;
00362 }
00363 return NULL;
00364 }
00365
00366 struct hashEl *hashElListHash(struct hash *hash)
00367
00368 {
00369 int i;
00370 struct hashEl *hel, *dupe, *list = NULL;
00371 for (i=0; i<hash->size; ++i)
00372 {
00373 for (hel = hash->table[i]; hel != NULL; hel = hel->next)
00374 {
00375 dupe = CloneVar(hel);
00376 slAddHead(&list, dupe);
00377 }
00378 }
00379 return list;
00380 }
00381
00382
00383 void hashElFree(struct hashEl **pEl)
00384
00385
00386 {
00387 freez(pEl);
00388 }
00389
00390 void hashElFreeList(struct hashEl **pList)
00391
00392
00393 {
00394 slFreeList(pList);
00395 }
00396
00397 struct hashCookie hashFirst(struct hash *hash)
00398
00399
00400 {
00401 struct hashCookie cookie;
00402 cookie.hash = hash;
00403 cookie.idx = 0;
00404 cookie.nextEl = NULL;
00405
00406
00407 for (cookie.idx = 0;
00408 (cookie.idx < hash->size) && (hash->table[cookie.idx] == NULL);
00409 cookie.idx++)
00410 continue;
00411 if (cookie.idx < hash->size)
00412 cookie.nextEl = hash->table[cookie.idx];
00413 return cookie;
00414 }
00415
00416 struct hashEl* hashNext(struct hashCookie *cookie)
00417
00418
00419 {
00420
00421
00422
00423 struct hashEl *retEl = cookie->nextEl;
00424 if (retEl == NULL)
00425 return NULL;
00426
00427
00428 cookie->nextEl = retEl->next;
00429 if (cookie->nextEl == NULL)
00430 {
00431 for (cookie->idx++; (cookie->idx < cookie->hash->size)
00432 && (cookie->hash->table[cookie->idx] == NULL); cookie->idx++)
00433 continue;
00434 if (cookie->idx < cookie->hash->size)
00435 cookie->nextEl = cookie->hash->table[cookie->idx];
00436 }
00437 return retEl;
00438 }
00439
00440 void* hashNextVal(struct hashCookie *cookie)
00441
00442
00443 {
00444 struct hashEl *hel = hashNext(cookie);
00445 if (hel == NULL)
00446 return NULL;
00447 else
00448 return hel->val;
00449 }
00450
00451 char *hashNextName(struct hashCookie *cookie)
00452
00453
00454 {
00455 struct hashEl *hel = hashNext(cookie);
00456 if (hel == NULL)
00457 return NULL;
00458 else
00459 return hel->name;
00460 }
00461
00462 void freeHash(struct hash **pHash)
00463
00464 {
00465 struct hash *hash = *pHash;
00466 if (hash == NULL)
00467 return;
00468 lmCleanup(&hash->lm);
00469 freez(pHash);
00470 }
00471
00472
00473 void freeHashAndVals(struct hash **pHash)
00474
00475
00476 {
00477 struct hash *hash;
00478 if ((hash = *pHash) != NULL)
00479 {
00480 hashTraverseVals(hash, freeMem);
00481 freeHash(pHash);
00482 }
00483 }
00484
00485 void hashFreeWithVals(struct hash **pHash, void (freeFunc)())
00486
00487
00488
00489 {
00490 struct hash *hash = *pHash;
00491 if (hash != NULL)
00492 {
00493 struct hashCookie cookie = hashFirst(hash);
00494 struct hashEl *hel;
00495 while ((hel = hashNext(&cookie)) != NULL)
00496 freeFunc(&hel->val);
00497 hashFree(pHash);
00498 }
00499 }
00500
00501 void hashFreeList(struct hash **pList)
00502
00503 {
00504 struct hash *el, *next;
00505
00506 for (el = *pList; el != NULL; el = next)
00507 {
00508 next = el->next;
00509 hashFree(&el);
00510 }
00511 *pList = NULL;
00512 }
00513
00514 static int bucketLen(struct hashEl *hel)
00515
00516 {
00517 int nel = 0;
00518 for (; hel != NULL; hel = hel->next)
00519 nel++;
00520 return nel;
00521 }
00522
00523 void hashHisto(struct hash *hash, char *fname)
00524
00525 {
00526 FILE* fh = mustOpen(fname, "w");
00527 int i;
00528
00529 for (i=0; i<hash->size; ++i)
00530 fprintf(fh, "%d\n", bucketLen(hash->table[i]));
00531 carefulClose(&fh);
00532 }
00533
00534 struct hashEl *hashReplace(struct hash *hash, char *name, void *val)
00535
00536 {
00537 if (hashLookup(hash, name))
00538 hashRemove(hash, name);
00539 return hashAdd(hash, name, val);
00540 }
00541
00542 char *hashToRaString(struct hash *hash)
00543
00544 {
00545 struct hashEl *el, *list = hashElListHash(hash);
00546 struct dyString *dy = dyStringNew(0);
00547 slSort(&list, hashElCmp);
00548 for (el = list; el != NULL; el = el->next)
00549 {
00550 dyStringAppend(dy, el->name);
00551 dyStringAppendC(dy, ' ');
00552 dyStringAppend(dy, el->val);
00553 dyStringAppendC(dy, '\n');
00554 }
00555 hashElFreeList(&list);
00556 return dyStringCannibalize(&dy);
00557 }