1 /*--------------------------------------------------------------------------*\
2 * -----===== HashTable =====-----
3 *
4 * Author: Keith Pomakis (pomakis@pobox.com)
5 * Date: August, 1998
6 * Released to the public domain.
7 *
8 *--------------------------------------------------------------------------
9 * $Id: hashtable.c,v 9999.42 2019/12/05 03:05:37 cvs Exp $
10 \*--------------------------------------------------------------------------*/
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <assert.h>
16 #include <pthread.h>
17 #include "hashtable.h"
18 #include "core.h"
19 #include "input-files.h"
20
21 static int pointercmp(const void *pointer1, const void *pointer2);
22 static srUInt_64 pointerHashFunction(const void *pointer);
23 static int isProbablePrime(srInt_64 number);
24 static srInt_64 calculateIdealNumOfBuckets(HashTable *hashTable);
25
long_random_val()26 srInt_64 long_random_val(){
27 srInt_64 ret = 0;
28 if(RAND_MAX<255){
29 SUBREADprintf("Is this a embedded computer????\n");
30 return -1;
31 }
32 int i;
33 for(i=0;i<8;i++){
34 if(i>0)ret = (ret << 8) ^ (myrand_rand() & 0xff);
35 else ret = (ret << 8) ^ (myrand_rand() & 0x7f);
36 }
37 return ret;
38 }
39
ArrayListToLookupTable_Int(ArrayList * arr)40 HashTable * ArrayListToLookupTable_Int(ArrayList * arr){
41 srInt_64 x1;
42 HashTable * ret = HashTableCreate( max(1,arr -> numOfElements / 6) );
43 for(x1 = 0; x1 < arr->numOfElements; x1++) HashTablePut(ret, ArrayListGet(arr, x1)+1, NULL+x1+1);
44 return ret;
45 }
46
ArrayListContainsPtr(ArrayList * list,void * who)47 int ArrayListContainsPtr(ArrayList * list, void * who){
48 srInt_64 x1;
49 for(x1 = 0; x1 < list->numOfElements; x1++) if(list->elementList [ x1 ]==who) return 1;
50 return 0;
51 }
52
ArrayListShift(ArrayList * list)53 void * ArrayListShift(ArrayList * list){
54 if(list->numOfElements<1) return NULL;
55 void *ret = list->elementList [0];
56 srInt_64 xx;
57 list->numOfElements -- ;
58 for(xx=0; xx<list->numOfElements; xx++) list->elementList [ xx ] = list->elementList [ xx+1 ];
59 return ret;
60 }
61
ArrayListPop(ArrayList * list)62 void * ArrayListPop(ArrayList * list){
63 if(list->numOfElements<1) return NULL;
64 return list->elementList [ -- list->numOfElements];
65 }
66
67
ArrayListRandom(ArrayList * list)68 void * ArrayListRandom(ArrayList * list){
69 srInt_64 ii = long_random_val() % list -> numOfElements;
70 return list -> elementList[ii];
71 }
72
73
ArrayListCreate(int init_capacity)74 ArrayList * ArrayListCreate(int init_capacity){
75 ArrayList * ret = malloc(sizeof(ArrayList));
76 memset(ret,0,sizeof(ArrayList));
77 ret -> capacityOfElements = init_capacity;
78 ret -> elementList = malloc(sizeof(void *)*init_capacity);
79 return ret;
80 }
81
ArrayListDuplicate(ArrayList * ori)82 ArrayList * ArrayListDuplicate(ArrayList * ori){
83 ArrayList * ret = malloc(sizeof(ArrayList));
84 memset(ret,0,sizeof(ArrayList));
85 ret -> capacityOfElements = ori -> numOfElements;
86 ret -> numOfElements = ori -> numOfElements;
87 ret -> elementList = malloc(sizeof(void *)*ret -> capacityOfElements);
88 memcpy(ret -> elementList, ori -> elementList, sizeof(void *)*ret -> capacityOfElements);
89 ret -> elemDeallocator = ori -> elemDeallocator;
90 return ret;
91 }
92
ArrayListDestroy(ArrayList * list)93 void ArrayListDestroy(ArrayList * list){
94 srInt_64 x1;
95 if(list -> elemDeallocator)
96 for(x1 = 0;x1 < list->numOfElements; x1++)
97 list -> elemDeallocator(list -> elementList[x1]);
98
99 free(list -> elementList);
100 free(list);
101 }
102
ArrayListGet(ArrayList * list,srInt_64 n)103 void * ArrayListGet(ArrayList * list, srInt_64 n){
104 if(n<0 || n >= list->numOfElements)return NULL;
105 return list -> elementList[n];
106 }
107
ArrayListPush_NoRepeatedPtr(ArrayList * list,void * new_elem)108 int ArrayListPush_NoRepeatedPtr(ArrayList * list, void * new_elem){
109 srInt_64 ii;
110 for(ii = 0; ii < list->numOfElements; ii++){
111 if(list -> elementList[ii] == new_elem) return -1;
112 }
113 return ArrayListPush(list,new_elem);
114 }
115
ArrayListPush(ArrayList * list,void * new_elem)116 int ArrayListPush(ArrayList * list, void * new_elem){
117 if(list -> capacityOfElements <= list->numOfElements){
118 if(list -> capacityOfElements *1.3 > list -> capacityOfElements + 10)
119 list -> capacityOfElements = list -> capacityOfElements *1.3;
120 else list -> capacityOfElements = list -> capacityOfElements + 10;
121
122 list -> elementList=realloc(list -> elementList, sizeof(void *) * list -> capacityOfElements);
123 assert(list -> elementList);
124 }
125 list->elementList[list->numOfElements++] = new_elem;
126 return list->numOfElements;
127 }
ArrayListSetDeallocationFunction(ArrayList * list,void (* elem_deallocator)(void * elem))128 void ArrayListSetDeallocationFunction(ArrayList * list, void (*elem_deallocator)(void *elem)){
129 list -> elemDeallocator = elem_deallocator;
130 }
131
ArrayListSort_comp_pntr(void * L_elem,void * R_elem,ArrayList * me)132 int ArrayListSort_comp_pntr( void * L_elem, void * R_elem, ArrayList * me ){
133 if( L_elem > R_elem )return 1;
134 if( L_elem < R_elem )return -1;
135 return 0;
136 }
137
ArrayListSort_compare(void * sortdata0,int L,int R)138 int ArrayListSort_compare(void * sortdata0, int L, int R){
139 void ** sortdata = sortdata0;
140 ArrayList * list = sortdata[0];
141 int (*comp_elems)(void * L_elem, void * R_elem, ArrayList * me) = sortdata[1];
142
143 void * L_elem = list -> elementList[L];
144 void * R_elem = list -> elementList[R];
145 return comp_elems(L_elem, R_elem, list);
146 }
147
ArrayListSort_exchange(void * sortdata0,int L,int R)148 void ArrayListSort_exchange(void * sortdata0, int L, int R){
149 void ** sortdata = sortdata0;
150 ArrayList * list = sortdata[0];
151
152 void * tmpp = list -> elementList[L];
153 list -> elementList[L] = list -> elementList[R];
154 list -> elementList[R] = tmpp;
155 }
156
ArrayListSort_merge(void * sortdata0,int start,int items,int items2)157 void ArrayListSort_merge(void * sortdata0, int start, int items, int items2){
158 void ** sortdata = sortdata0;
159 ArrayList * list = sortdata[0];
160 int (*comp_elems)(void * L_elem, void * R_elem, ArrayList * me) = sortdata[1];
161
162 void ** merged = malloc(sizeof(void *)*(items + items2));
163 int write_cursor, read1=start, read2=start+items;
164
165 for(write_cursor = 0; write_cursor < items + items2; write_cursor++){
166 void * Elm1 = (read1 == start + items)? NULL:list -> elementList[read1];
167 void * Elm2 = (read2 == start + items + items2)?NULL:list -> elementList[read2];
168
169 int select_1 = (read1 == start + items)?0:( read2 == start + items + items2 || comp_elems(Elm1, Elm2, list) < 0 );
170 if(select_1) merged[write_cursor] = list -> elementList[read1++];
171 else merged[write_cursor] = list -> elementList[read2++];
172 if(read2 > start + items + items2){
173 SUBREADprintf("R1: %d < %d ; R2: %d < %d\n", read1, start + items, read2, start + items + items2);
174 }
175 assert(read2 <=start + items + items2);
176 assert(read1 <=start + items);
177 }
178
179 memcpy(list -> elementList + start, merged, sizeof(void *) * (items + items2));
180 free(merged);
181 }
182
ArrayListSort(ArrayList * list,int compare_L_minus_R (void * L_elem,void * R_elem,ArrayList * me))183 void ArrayListSort(ArrayList * list, int compare_L_minus_R(void * L_elem, void * R_elem, ArrayList * me)){
184 void * sortdata[2];
185 sortdata[0] = list;
186 sortdata[1] = compare_L_minus_R?compare_L_minus_R:ArrayListSort_comp_pntr;
187
188 if(list -> numOfElements > 20)
189 merge_sort(sortdata, list -> numOfElements, ArrayListSort_compare, ArrayListSort_exchange, ArrayListSort_merge);
190 else
191 basic_sort(sortdata, list -> numOfElements, ArrayListSort_compare, ArrayListSort_exchange);
192 }
193
ArrayListLLUComparison(void * L_elem,void * R_elem)194 int ArrayListLLUComparison(void * L_elem, void * R_elem){
195 srUInt_64 lint = L_elem-NULL;
196 srUInt_64 rint = R_elem-NULL;
197 if(lint<rint)return -1;
198 if(lint>rint)return 1;
199 return 0;
200 }
201
ArrayListFindNextDent(ArrayList * list,srUInt_64 value_less_than_dent)202 srInt_64 ArrayListFindNextDent(ArrayList * list, srUInt_64 value_less_than_dent){
203 srInt_64 h=list->numOfElements-1,l=0,m=-1l;
204 if( list -> elementList[h]- NULL <= value_less_than_dent )return -1l;
205 while(h>l){
206 m=(h+l)/2;
207 srUInt_64 mv = list -> elementList[m] - NULL;
208 if(mv < value_less_than_dent) l=m+1;
209 else if(mv > value_less_than_dent) h=m-1;
210 else break;
211 }
212 if(m<2)m=0;
213 else m-=2;
214
215 for(; m>=0 && list -> elementList[m] - NULL >= value_less_than_dent; m--);
216
217 for(m = max(0, m); m < list->numOfElements ; m++){
218 if( list -> elementList[m] - NULL > value_less_than_dent )return m;
219 }
220 SUBREADprintf("ALGORITHM ERROR!! DID YOU SORT THE LIST???\n");
221 return -2l;
222 }
223
224 /*--------------------------------------------------------------------------*\
225 * NAME:
226 * HashTableCreate() - creates a new HashTable
227 * DESCRIPTION:
228 * Creates a new HashTable. When finished with this HashTable, it
229 * should be explicitly destroyed by calling the HashTableDestroy()
230 * function.
231 * EFFICIENCY:
232 * O(1)
233 * ARGUMENTS:
234 * numOfBuckets - the number of buckets to start the HashTable out with.
235 * Must be greater than zero, and should be prime.
236 * Ideally, the number of buckets should between 1/5
237 * and 1 times the expected number of elements in the
238 * HashTable. Values much more or less than this will
239 * result in wasted memory or decreased performance
240 * respectively. The number of buckets in a HashTable
241 * can be re-calculated to an appropriate number by
242 * calling the HashTableRehash() function once the
243 * HashTable has been populated. The number of buckets
244 * in a HashTable may also be re-calculated
245 * automatically if the ratio of elements to buckets
246 * passes the thresholds set by HashTableSetIdealRatio().
247 * RETURNS:
248 * HashTable - a new Hashtable, or NULL on error
249 \*--------------------------------------------------------------------------*/
250
StringTableCreate(srInt_64 numOfBuckets)251 HashTable * StringTableCreate(srInt_64 numOfBuckets){
252 HashTable * ret = HashTableCreate(numOfBuckets);
253 HashTableSetHashFunction(ret, HashTableStringHashFunction);
254 HashTableSetKeyComparisonFunction(ret , my_strcmp);
255 return ret;
256 }
257
StringTableReverse_Run(void * ky,void * va,HashTable * tab)258 void StringTableReverse_Run(void * ky, void * va, HashTable * tab){
259 HashTable * res = tab -> appendix1;
260 HashTablePut(res, va, ky);
261 }
262
StringTableReverse(HashTable * ori)263 HashTable * StringTableReverse(HashTable * ori){
264 HashTable * res = StringTableCreate(ori -> numOfBuckets);
265 void * oriap1 = ori -> appendix1;
266 ori -> appendix1 = res;
267
268 HashTableIteration(ori, StringTableReverse_Run);
269 ori -> appendix1 = oriap1;
270 return res;
271 }
272
HashTableKeys(HashTable * tab)273 ArrayList * HashTableKeys(HashTable * tab){
274 int i;
275 ArrayList * ret = ArrayListCreate(tab -> numOfElements);
276 for (i=0; i< tab ->numOfBuckets; i++) {
277 KeyValuePair *pair = tab ->bucketArray[i];
278 while (pair != NULL) {
279 ArrayListPush(ret, pair -> key);
280 KeyValuePair *nextPair = pair->next;
281 pair = nextPair;
282 }
283 }
284 return ret;
285 }
286
HashTableCreate(srInt_64 numOfBuckets)287 HashTable *HashTableCreate(srInt_64 numOfBuckets) {
288 HashTable *hashTable;
289 int i;
290
291
292 assert(numOfBuckets > 0);
293
294 hashTable = (HashTable *) malloc(sizeof(HashTable));
295 if (hashTable == NULL)
296 return NULL;
297
298 hashTable->appendix1=NULL;
299 hashTable->appendix2=NULL;
300 hashTable->appendix3=NULL;
301
302 hashTable->counter1=0;
303 hashTable->counter2=0;
304 hashTable->counter3=0;
305
306 hashTable->bucketArray = (KeyValuePair **)
307 malloc(numOfBuckets * sizeof(KeyValuePair *));
308 if (hashTable->bucketArray == NULL) {
309 free(hashTable);
310 return NULL;
311 }
312
313 hashTable->numOfBuckets = numOfBuckets;
314 hashTable->numOfElements = 0;
315
316 for (i=0; i<numOfBuckets; i++)
317 hashTable->bucketArray[i] = NULL;
318
319 hashTable->idealRatio = 3.0;
320 hashTable->lowerRehashThreshold = 0.0;
321 hashTable->upperRehashThreshold = 15.0;
322
323 hashTable->keycmp = pointercmp;
324 hashTable->valuecmp = pointercmp;
325 hashTable->hashFunction = pointerHashFunction;
326 hashTable->keyDeallocator = NULL;
327 hashTable->valueDeallocator = NULL;
328
329 return hashTable;
330 }
331
332
333 /*--------------------------------------------------------------------------*\
334 * NAME:
335 * HashTableDestroy() - destroys an existing HashTable
336 * DESCRIPTION:
337 * Destroys an existing HashTable.
338 * EFFICIENCY:
339 * O(n)
340 * ARGUMENTS:
341 * hashTable - the HashTable to destroy
342 * RETURNS:
343 * <nothing>
344 \*--------------------------------------------------------------------------*/
345
HashTableDestroy(HashTable * hashTable)346 void HashTableDestroy(HashTable *hashTable) {
347 int i;
348
349 for (i=0; i<hashTable->numOfBuckets; i++) {
350 KeyValuePair *pair = hashTable->bucketArray[i];
351 while (pair != NULL) {
352 KeyValuePair *nextPair = pair->next;
353
354 if (hashTable->keyDeallocator != NULL)
355 hashTable->keyDeallocator((void *) pair->key);
356 if (hashTable->valueDeallocator != NULL){
357 // fprintf(stderr,"FREE %p\n", pair->value);
358 hashTable->valueDeallocator(pair->value);
359 }
360 free(pair);
361 pair = nextPair;
362 }
363 }
364
365 free(hashTable->bucketArray);
366 free(hashTable);
367 }
368
369 /*--------------------------------------------------------------------------*\
370 * NAME:
371 * HashTableContainsKey() - checks the existence of a key in a HashTable
372 * DESCRIPTION:
373 * Determines whether or not the specified HashTable contains the
374 * specified key. Uses the comparison function specified by
375 * HashTableSetKeyComparisonFunction().
376 * EFFICIENCY:
377 * O(1), assuming a good hash function and element-to-bucket ratio
378 * ARGUMENTS:
379 * hashTable - the HashTable to search
380 * key - the key to search for
381 * RETURNS:
382 * bool - whether or not the specified HashTable contains the
383 * specified key.
384 \*--------------------------------------------------------------------------*/
385
HashTableContainsKey(const HashTable * hashTable,const void * key)386 int HashTableContainsKey(const HashTable *hashTable, const void *key) {
387 return (HashTableGet(hashTable, key) != NULL);
388 }
389
390 /*--------------------------------------------------------------------------*\
391 * NAME:
392 * HashTableContainsValue()
393 * - checks the existence of a value in a HashTable
394 * DESCRIPTION:
395 * Determines whether or not the specified HashTable contains the
396 * specified value. Unlike HashTableContainsKey(), this function is
397 * not very efficient, since it has to scan linearly looking for a
398 * match. Uses the comparison function specified by
399 * HashTableSetValueComparisonFunction().
400 * EFFICIENCY:
401 * O(n)
402 * ARGUMENTS:
403 * hashTable - the HashTable to search
404 * value - the value to search for
405 * RETURNS:
406 * bool - whether or not the specified HashTable contains the
407 * specified value.
408 \*--------------------------------------------------------------------------*/
409
HashTableContainsValue(const HashTable * hashTable,const void * value)410 int HashTableContainsValue(const HashTable *hashTable, const void *value) {
411 int i;
412
413 for (i=0; i<hashTable->numOfBuckets; i++) {
414 KeyValuePair *pair = hashTable->bucketArray[i];
415 while (pair != NULL) {
416 if (hashTable->valuecmp(value, pair->value) == 0)
417 return 1;
418 pair = pair->next;
419 }
420 }
421
422 return 0;
423 }
424
425 /*--------------------------------------------------------------------------*\
426 * NAME:
427 * HashTablePut() - adds a key/value pair to a HashTable
428 * DESCRIPTION:
429 * Adds the specified key/value pair to the specified HashTable. If
430 * the key already exists in the HashTable (determined by the comparison
431 * function specified by HashTableSetKeyComparisonFunction()), its value
432 * is replaced by the new value. May trigger an auto-rehash (see
433 * HashTableSetIdealRatio()). It is illegal to specify NULL as the
434 * key or value.
435 * EFFICIENCY:
436 * O(1), assuming a good hash function and element-to-bucket ratio
437 * ARGUMENTS:
438 * hashTable - the HashTable to add to
439 * key - the key to add or whose value to replace
440 * value - the value associated with the key
441 * RETURNS:
442 * err - 0 if successful, -1 if an error was encountered
443 \*--------------------------------------------------------------------------*/
444
HashTablePut(HashTable * hashTable,const void * key,void * value)445 int HashTablePut(HashTable *hashTable, const void *key, void *value) {
446 return HashTablePutReplace(hashTable, key, value, 1);
447 }
448
HashTablePutReplaceEx(HashTable * hashTable,const void * key,void * value,int replace_key,int dealloc_key,int dealloc_value)449 int HashTablePutReplaceEx(HashTable *hashTable, const void *key, void *value, int replace_key, int dealloc_key, int dealloc_value) {
450 srInt_64 hashValue;
451 KeyValuePair *pair;
452
453 assert(key != NULL);
454 assert(value != NULL);
455
456 hashValue = hashTable->hashFunction(key) % hashTable->numOfBuckets;
457
458
459 pair = hashTable->bucketArray[hashValue];
460
461 while (pair != NULL && hashTable->keycmp(key, pair->key) != 0)
462 pair = pair->next;
463
464 if (pair) {
465 if (pair->key != key) {
466 if(replace_key) {
467 if(hashTable->keyDeallocator && dealloc_key)
468 hashTable->keyDeallocator((void *) pair->key);
469 pair->key = (void *)key;
470 }
471 }
472 if (pair->value != value) {
473 if (hashTable->valueDeallocator != NULL && dealloc_value)
474 hashTable->valueDeallocator(pair->value);
475 pair->value = (void *)value;
476 }
477 }
478 else {
479 KeyValuePair *newPair = (KeyValuePair *) malloc(sizeof(KeyValuePair));
480 if (newPair == NULL) {
481 return -1;
482 }
483 else {
484 newPair->key = (void *)key;
485 newPair->value = (void *)value;
486 newPair->next = hashTable->bucketArray[hashValue];
487 hashTable->bucketArray[hashValue] = newPair;
488 hashTable->numOfElements++;
489
490 if (hashTable->upperRehashThreshold > hashTable->idealRatio) {
491 float elementToBucketRatio = (float) hashTable->numOfElements /
492 (float) hashTable->numOfBuckets;
493 if (elementToBucketRatio > hashTable->upperRehashThreshold)
494 HashTableRehash(hashTable, 0);
495 }
496 }
497 }
498
499 return 0;
500 }
HashTablePutReplace(HashTable * hashTable,const void * key,void * value,int replace_key)501 int HashTablePutReplace(HashTable *hashTable, const void *key, void *value, int replace_key) {
502 return HashTablePutReplaceEx(hashTable, key, value, replace_key, 1, 1);
503 }
504
505 /*--------------------------------------------------------------------------*\
506 * NAME:
507 * HashTableGet() - retrieves the value of a key in a HashTable
508 * DESCRIPTION:
509 * Retrieves the value of the specified key in the specified HashTable.
510 * Uses the comparison function specified by
511 * HashTableSetKeyComparisonFunction().
512 * EFFICIENCY:
513 * O(1), assuming a good hash function and element-to-bucket ratio
514 * ARGUMENTS:
515 * hashTable - the HashTable to search
516 * key - the key whose value is desired
517 * RETURNS:
518 * void * - the value of the specified key, or NULL if the key
519 * doesn't exist in the HashTable
520 \*--------------------------------------------------------------------------*/
521
HashTableGetKey(const HashTable * hashTable,const void * key)522 void *HashTableGetKey(const HashTable *hashTable, const void *key) {
523 srInt_64 hashValue = hashTable->hashFunction(key) % hashTable->numOfBuckets;
524
525 KeyValuePair *pair = hashTable->bucketArray[hashValue];
526
527 while (pair != NULL && hashTable->keycmp(key, pair->key) != 0)
528 pair = pair->next;
529
530 return (pair == NULL)? NULL : pair->key;
531 }
532
533
HashTableGet(const HashTable * hashTable,const void * key)534 void *HashTableGet(const HashTable *hashTable, const void *key) {
535 srInt_64 hashValue = hashTable->hashFunction(key) % hashTable->numOfBuckets;
536
537 KeyValuePair *pair = hashTable->bucketArray[hashValue];
538
539 while (pair != NULL && hashTable->keycmp(key, pair->key) != 0)
540 pair = pair->next;
541
542 return (pair == NULL)? NULL : pair->value;
543 }
544
545 /*--------------------------------------------------------------------------*\
546 * NAME:
547 * HashTableRemove() - removes a key/value pair from a HashTable
548 * DESCRIPTION:
549 * Removes the key/value pair identified by the specified key from the
550 * specified HashTable if the key exists in the HashTable. May trigger
551 * an auto-rehash (see HashTableSetIdealRatio()).
552 * EFFICIENCY:
553 * O(1), assuming a good hash function and element-to-bucket ratio
554 * ARGUMENTS:
555 * hashTable - the HashTable to remove the key/value pair from
556 * key - the key specifying the key/value pair to be removed
557 * RETURNS:
558 * <nothing>
559 \*--------------------------------------------------------------------------*/
560
HashTableRemove(HashTable * hashTable,const void * key)561 void HashTableRemove(HashTable *hashTable, const void *key) {
562 srInt_64 hashValue = hashTable->hashFunction(key) % hashTable->numOfBuckets;
563
564
565 KeyValuePair *pair = hashTable->bucketArray[hashValue];
566 KeyValuePair *previousPair = NULL;
567
568 while (pair != NULL && hashTable->keycmp(key, pair->key) != 0) {
569 previousPair = pair;
570 pair = pair->next;
571 }
572
573 if (pair != NULL) {
574 if (hashTable->keyDeallocator != NULL)
575 hashTable->keyDeallocator((void *) pair->key);
576 if (hashTable->valueDeallocator != NULL)
577 hashTable->valueDeallocator(pair->value);
578 if (previousPair != NULL)
579 previousPair->next = pair->next;
580 else
581 hashTable->bucketArray[hashValue] = pair->next;
582 free(pair);
583 hashTable->numOfElements--;
584
585 if (hashTable->lowerRehashThreshold > 0.0) {
586 float elementToBucketRatio = (float) hashTable->numOfElements /
587 (float) hashTable->numOfBuckets;
588 if (elementToBucketRatio < hashTable->lowerRehashThreshold)
589 HashTableRehash(hashTable, 0);
590 }
591 }
592
593
594 }
595
596 /*--------------------------------------------------------------------------*\
597 * NAME:
598 * HashTableRemoveAll() - removes all key/value pairs from a HashTable
599 * DESCRIPTION:
600 * Removes all key/value pairs from the specified HashTable. May trigger
601 * an auto-rehash (see HashTableSetIdealRatio()).
602 * EFFICIENCY:
603 * O(n)
604 * ARGUMENTS:
605 * hashTable - the HashTable to remove all key/value pairs from
606 * RETURNS:
607 * <nothing>
608 \*--------------------------------------------------------------------------*/
609
HashTableRemoveAll(HashTable * hashTable)610 void HashTableRemoveAll(HashTable *hashTable) {
611 int i;
612
613 for (i=0; i<hashTable->numOfBuckets; i++) {
614 KeyValuePair *pair = hashTable->bucketArray[i];
615 while (pair != NULL) {
616 KeyValuePair *nextPair = pair->next;
617 if (hashTable->keyDeallocator != NULL)
618 hashTable->keyDeallocator((void *) pair->key);
619 if (hashTable->valueDeallocator != NULL)
620 hashTable->valueDeallocator(pair->value);
621 free(pair);
622 pair = nextPair;
623 }
624 hashTable->bucketArray[i] = NULL;
625 }
626
627 hashTable->numOfElements = 0;
628 HashTableRehash(hashTable, 5);
629 }
630
631 /*--------------------------------------------------------------------------*\
632 * NAME:
633 * HashTableIsEmpty() - determines if a HashTable is empty
634 * DESCRIPTION:
635 * Determines whether or not the specified HashTable contains any
636 * key/value pairs.
637 * EFFICIENCY:
638 * O(1)
639 * ARGUMENTS:
640 * hashTable - the HashTable to check
641 * RETURNS:
642 * bool - whether or not the specified HashTable contains any
643 * key/value pairs
644 \*--------------------------------------------------------------------------*/
645
HashTableIsEmpty(const HashTable * hashTable)646 int HashTableIsEmpty(const HashTable *hashTable) {
647 return (hashTable->numOfElements == 0);
648 }
649
650 /*--------------------------------------------------------------------------*\
651 * NAME:
652 * HashTableSize() - returns the number of elements in a HashTable
653 * DESCRIPTION:
654 * Returns the number of key/value pairs that are present in the
655 * specified HashTable.
656 * EFFICIENCY:
657 * O(1)
658 * ARGUMENTS:
659 * hashTable - the HashTable whose size is requested
660 * RETURNS:
661 * long - the number of key/value pairs that are present in
662 * the specified HashTable
663 \*--------------------------------------------------------------------------*/
664
HashTableSize(const HashTable * hashTable)665 srInt_64 HashTableSize(const HashTable *hashTable) {
666 return hashTable->numOfElements;
667 }
668
669 /*--------------------------------------------------------------------------*\
670 * NAME:
671 * HashTableGetNumBuckets() - returns the number of buckets in a HashTable
672 * DESCRIPTION:
673 * Returns the number of buckets that are in the specified HashTable.
674 * This may change dynamically throughout the life of a HashTable if
675 * automatic or manual rehashing is performed.
676 * EFFICIENCY:
677 * O(1)
678 * ARGUMENTS:
679 * hashTable - the HashTable whose number of buckets is requested
680 * RETURNS:
681 * long - the number of buckets that are in the specified
682 * HashTable
683 \*--------------------------------------------------------------------------*/
684
HashTableGetNumBuckets(const HashTable * hashTable)685 srInt_64 HashTableGetNumBuckets(const HashTable *hashTable) {
686 return hashTable->numOfBuckets;
687 }
688
689 /*--------------------------------------------------------------------------*\
690 * NAME:
691 * HashTableSetKeyComparisonFunction()
692 * - specifies the function used to compare keys in a HashTable
693 * DESCRIPTION:
694 * Specifies the function used to compare keys in the specified
695 * HashTable. The specified function should return zero if the two
696 * keys are considered equal, and non-zero otherwise. The default
697 * function is one that simply compares pointers.
698 * ARGUMENTS:
699 * hashTable - the HashTable whose key comparison function is being
700 * specified
701 * keycmp - a function which returns zero if the two arguments
702 * passed to it are considered "equal" keys and non-zero
703 * otherwise
704 * RETURNS:
705 * <nothing>
706 \*--------------------------------------------------------------------------*/
707
HashTableSetKeyComparisonFunction(HashTable * hashTable,int (* keycmp)(const void * key1,const void * key2))708 void HashTableSetKeyComparisonFunction(HashTable *hashTable,
709 int (*keycmp)(const void *key1, const void *key2)) {
710 assert(keycmp != NULL);
711 hashTable->keycmp = keycmp;
712 }
713
714 /*--------------------------------------------------------------------------*\
715 * NAME:
716 * HashTableSetValueComparisonFunction()
717 * - specifies the function used to compare values in a HashTable
718 * DESCRIPTION:
719 * Specifies the function used to compare values in the specified
720 * HashTable. The specified function should return zero if the two
721 * values are considered equal, and non-zero otherwise. The default
722 * function is one that simply compares pointers.
723 * ARGUMENTS:
724 * hashTable - the HashTable whose value comparison function is being
725 * specified
726 * valuecmp - a function which returns zero if the two arguments
727 * passed to it are considered "equal" values and non-zero
728 * otherwise
729 * RETURNS:
730 * <nothing>
731 \*--------------------------------------------------------------------------*/
732
HashTableSetValueComparisonFunction(HashTable * hashTable,int (* valuecmp)(const void * value1,const void * value2))733 void HashTableSetValueComparisonFunction(HashTable *hashTable,
734 int (*valuecmp)(const void *value1, const void *value2)) {
735 assert(valuecmp != NULL);
736 hashTable->valuecmp = valuecmp;
737 }
738
739 /*--------------------------------------------------------------------------*\
740 * NAME:
741 * HashTableSetHashFunction()
742 * - specifies the hash function used by a HashTable
743 * DESCRIPTION:
744 * Specifies the function used to determine the hash value for a key
745 * in the specified HashTable (before modulation). An ideal hash
746 * function is one which is easy to compute and approximates a
747 * "random" function. The default function is one that works
748 * relatively well for pointers. If the HashTable keys are to be
749 * strings (which is probably the case), then this default function
750 * will not suffice, in which case consider using the provided
751 * HashTableStringHashFunction() function.
752 * ARGUMENTS:
753 * hashTable - the HashTable whose hash function is being specified
754 * hashFunction - a function which returns an appropriate hash code
755 * for a given key
756 * RETURNS:
757 * <nothing>
758 \*--------------------------------------------------------------------------*/
759
HashTableSetHashFunction(HashTable * hashTable,srUInt_64 (* hashFunction)(const void * key))760 void HashTableSetHashFunction(HashTable *hashTable,
761 srUInt_64 (*hashFunction)(const void *key))
762 {
763 assert(hashFunction != NULL);
764 hashTable->hashFunction = hashFunction;
765 }
766
767 /*--------------------------------------------------------------------------*\
768 * NAME:
769 * HashTableRehash() - reorganizes a HashTable to be more efficient
770 * DESCRIPTION:
771 * Reorganizes a HashTable to be more efficient. If a number of
772 * buckets is specified, the HashTable is rehashed to that number of
773 * buckets. If 0 is specified, the HashTable is rehashed to a number
774 * of buckets which is automatically calculated to be a prime number
775 * that achieves (as closely as possible) the ideal element-to-bucket
776 * ratio specified by the HashTableSetIdealRatio() function.
777 * EFFICIENCY:
778 * O(n)
779 * ARGUMENTS:
780 * hashTable - the HashTable to be reorganized
781 * numOfBuckets - the number of buckets to rehash the HashTable to.
782 * Should be prime. Ideally, the number of buckets
783 * should be between 1/5 and 1 times the expected
784 * number of elements in the HashTable. Values much
785 * more or less than this will result in wasted memory
786 * or decreased performance respectively. If 0 is
787 * specified, an appropriate number of buckets is
788 * automatically calculated.
789 * RETURNS:
790 * <nothing>
791 \*--------------------------------------------------------------------------*/
792
HashTableRehash(HashTable * hashTable,srInt_64 numOfBuckets)793 void HashTableRehash(HashTable *hashTable, srInt_64 numOfBuckets) {
794 KeyValuePair **newBucketArray;
795 int i;
796
797 assert(numOfBuckets >= 0);
798 if (numOfBuckets == 0)
799 numOfBuckets = calculateIdealNumOfBuckets(hashTable);
800
801 if (numOfBuckets == hashTable->numOfBuckets)
802 return; /* already the right size! */
803
804 newBucketArray = (KeyValuePair **)
805 malloc(numOfBuckets * sizeof(KeyValuePair *));
806 if (newBucketArray == NULL) {
807 /* Couldn't allocate memory for the new array. This isn't a fatal
808 * error; we just can't perform the rehash. */
809 return;
810 }
811
812 for (i=0; i<numOfBuckets; i++)
813 newBucketArray[i] = NULL;
814
815 for (i=0; i<hashTable->numOfBuckets; i++) {
816 KeyValuePair *pair = hashTable->bucketArray[i];
817 while (pair != NULL) {
818 KeyValuePair *nextPair = pair->next;
819 srInt_64 hashValue = hashTable->hashFunction(pair->key) % numOfBuckets;
820 pair->next = newBucketArray[hashValue];
821 newBucketArray[hashValue] = pair;
822 pair = nextPair;
823 }
824 }
825
826 free(hashTable->bucketArray);
827 hashTable->bucketArray = newBucketArray;
828 hashTable->numOfBuckets = numOfBuckets;
829 }
830
831 /*--------------------------------------------------------------------------*\
832 * NAME:
833 * HashTableSetIdealRatio()
834 * - sets the ideal element-to-bucket ratio of a HashTable
835 * DESCRIPTION:
836 * Sets the ideal element-to-bucket ratio, as well as the lower and
837 * upper auto-rehash thresholds, of the specified HashTable. Note
838 * that this function doesn't actually perform a rehash.
839 *
840 * The default values for these properties are 3.0, 0.0 and 15.0
841 * respectively. This is likely fine for most situations, so there
842 * is probably no need to call this function.
843 * ARGUMENTS:
844 * hashTable - a HashTable
845 * idealRatio - the ideal element-to-bucket ratio. When a rehash
846 * occurs (either manually via a call to the
847 * HashTableRehash() function or automatically due the
848 * the triggering of one of the thresholds below), the
849 * number of buckets in the HashTable will be
850 * recalculated to be a prime number that achieves (as
851 * closely as possible) this ideal ratio. Must be a
852 * positive number.
853 * lowerRehashThreshold
854 * - the element-to-bucket ratio that is considered
855 * unacceptably low (i.e., too few elements per bucket).
856 * If the actual ratio falls below this number, a
857 * rehash will automatically be performed. Must be
858 * lower than the value of idealRatio. If no ratio
859 * is considered unacceptably low, a value of 0.0 can
860 * be specified.
861 * upperRehashThreshold
862 * - the element-to-bucket ratio that is considered
863 * unacceptably high (i.e., too many elements per bucket).
864 * If the actual ratio rises above this number, a
865 * rehash will automatically be performed. Must be
866 * higher than idealRatio. However, if no ratio
867 * is considered unacceptably high, a value of 0.0 can
868 * be specified.
869 * RETURNS:
870 * <nothing>
871 \*--------------------------------------------------------------------------*/
872
HashTableSetIdealRatio(HashTable * hashTable,float idealRatio,float lowerRehashThreshold,float upperRehashThreshold)873 void HashTableSetIdealRatio(HashTable *hashTable, float idealRatio,
874 float lowerRehashThreshold, float upperRehashThreshold) {
875 assert(idealRatio > 0.0);
876 assert(lowerRehashThreshold < idealRatio);
877 assert(upperRehashThreshold == 0.0 || upperRehashThreshold > idealRatio);
878
879 hashTable->idealRatio = idealRatio;
880 hashTable->lowerRehashThreshold = lowerRehashThreshold;
881 hashTable->upperRehashThreshold = upperRehashThreshold;
882 }
883
884 /*--------------------------------------------------------------------------*\
885 * NAME:
886 * HashTableSetDeallocationFunctions()
887 * - sets the key and value deallocation functions of a HashTable
888 * DESCRIPTION:
889 * Sets the key and value deallocation functions of the specified
890 * HashTable. This determines what happens to a key or a value when it
891 * is removed from the HashTable. If the deallocation function is NULL
892 * (the default if this function is never called), its reference is
893 * simply dropped and it is up to the calling program to perform the
894 * proper memory management. If the deallocation function is non-NULL,
895 * it is called to free the memory used by the object. E.g., for simple
896 * objects, an appropriate deallocation function may be free().
897 *
898 * This affects the behaviour of the HashTableDestroy(), HashTablePut(),
899 * HashTableRemove() and HashTableRemoveAll() functions.
900 * ARGUMENTS:
901 * hashTable - a HashTable
902 * keyDeallocator
903 * - if non-NULL, the function to be called when a key is
904 * removed from the HashTable.
905 * valueDeallocator
906 * - if non-NULL, the function to be called when a value is
907 * removed from the HashTable.
908 * RETURNS:
909 * <nothing>
910 \*--------------------------------------------------------------------------*/
911
HashTableSetDeallocationFunctions(HashTable * hashTable,void (* keyDeallocator)(void * key),void (* valueDeallocator)(void * value))912 void HashTableSetDeallocationFunctions(HashTable *hashTable,
913 void (*keyDeallocator)(void *key),
914 void (*valueDeallocator)(void *value)) {
915 hashTable->keyDeallocator = keyDeallocator;
916 hashTable->valueDeallocator = valueDeallocator;
917 }
918
919 /*--------------------------------------------------------------------------*\
920 * NAME:
921 * HashTableStringHashFunction() - a good hash function for strings
922 * DESCRIPTION:
923 * A hash function that is appropriate for hashing strings. Note that
924 * this is not the default hash function. To make it the default hash
925 * function, call HashTableSetHashFunction(hashTable,
926 * HashTableStringHashFunction).
927 * ARGUMENTS:
928 * key - the key to be hashed
929 * RETURNS:
930 * unsigned long - the unmodulated hash value of the key
931 \*--------------------------------------------------------------------------*/
932
HashTableStringHashFunction(const void * key)933 srUInt_64 HashTableStringHashFunction(const void *key) {
934 const unsigned char *str = (const unsigned char *) key;
935 srUInt_64 hashValue = 0;
936 int i;
937
938 for (i=0; str[i] != '\0'; i++)
939 hashValue = hashValue * 37 + str[i];
940
941 return hashValue;
942 }
943
pointercmp(const void * pointer1,const void * pointer2)944 static int pointercmp(const void *pointer1, const void *pointer2) {
945 return (pointer1 != pointer2);
946 }
947
pointerHashFunction(const void * pointer)948 static srUInt_64 pointerHashFunction(const void *pointer) {
949 return (srUInt_64)(pointer - NULL);
950 }
951
isProbablePrime(srInt_64 oddNumber)952 static int isProbablePrime(srInt_64 oddNumber) {
953 srInt_64 i;
954
955 for (i=3; i<51; i+=2)
956 if (oddNumber == i)
957 return 1;
958 else if (oddNumber%i == 0)
959 return 0;
960
961 return 1; /* maybe */
962 }
963
calculateIdealNumOfBuckets(HashTable * hashTable)964 static srInt_64 calculateIdealNumOfBuckets(HashTable *hashTable) {
965 srInt_64 idealNumOfBuckets = hashTable->numOfElements / hashTable->idealRatio;
966 if (idealNumOfBuckets < 5)
967 idealNumOfBuckets = 5;
968 else
969 idealNumOfBuckets |= 0x01; /* make it an odd number */
970 while (!isProbablePrime(idealNumOfBuckets))
971 idealNumOfBuckets += 2;
972
973 return idealNumOfBuckets;
974 }
975
976
free_values_destroy(HashTable * tab)977 void free_values_destroy(HashTable * tab)
978 {
979
980 KeyValuePair * cursor;
981 int bucket;
982
983 for(bucket=0; bucket< tab -> numOfBuckets; bucket++)
984 {
985 cursor = tab -> bucketArray[bucket];
986 while (1)
987 {
988 if(!cursor) break;
989 char * read_txt = (char *) cursor ->value;
990 free(read_txt);
991 cursor = cursor->next;
992 }
993 }
994
995 HashTableDestroy(tab);
996 }
997
HashTableKeyArray(HashTable * tab)998 ArrayList * HashTableKeyArray(HashTable * tab){
999 ArrayList *ret = ArrayListCreate(20);
1000 int i;
1001 for (i=0; i< tab ->numOfBuckets; i++) {
1002 KeyValuePair *pair = tab ->bucketArray[i];
1003 while (pair != NULL) {
1004 ArrayListPush(ret, (void *)pair -> key);
1005 KeyValuePair *nextPair = pair->next;
1006 pair = nextPair;
1007 }
1008 }
1009 return ret;
1010 }
1011
HashTableIteration(HashTable * tab,void process_item (void * key,void * hashed_obj,HashTable * tab))1012 void HashTableIteration(HashTable * tab, void process_item(void * key, void * hashed_obj, HashTable * tab) )
1013 {
1014 int i;
1015 for (i=0; i< tab ->numOfBuckets; i++) {
1016 KeyValuePair *pair = tab ->bucketArray[i];
1017 while (pair != NULL) {
1018 process_item(( void * )pair -> key, pair -> value, tab);
1019 KeyValuePair *nextPair = pair->next;
1020 pair = nextPair;
1021 }
1022 }
1023 }
1024
HashTableSortedIndexes_copy_idx(void * k,void * v,HashTable * k2int_tab)1025 void HashTableSortedIndexes_copy_idx( void *k, void *v, HashTable * k2int_tab ){
1026 ArrayList * dsta = k2int_tab -> appendix1;
1027 ArrayListPush(dsta, k);
1028 }
1029
HashTableSortedIndexes_cmp_idx(void * Lv,void * Rv,ArrayList * me)1030 int HashTableSortedIndexes_cmp_idx( void * Lv, void * Rv, ArrayList * me ){
1031 void ** appdx = me -> appendix1;
1032 HashTable * k2int_tab = appdx[0];
1033 void * Lhash = HashTableGet(k2int_tab, Lv);
1034 void * Rhash = HashTableGet(k2int_tab, Rv);
1035 void * large_first = appdx[1];
1036 if(large_first){
1037 if(Lhash > Rhash) return -1;
1038 if(Lhash < Rhash) return 1;
1039 }else{
1040 if(Lhash > Rhash) return 1;
1041 if(Lhash < Rhash) return -1;
1042 }
1043 return 0;
1044 }
1045
HashTableSortedIndexes(HashTable * k2int_tab,int larger_value_first)1046 ArrayList * HashTableSortedIndexes(HashTable * k2int_tab, int larger_value_first){
1047 ArrayList *ret = HashTableKeys(k2int_tab);
1048 void * appx[2];
1049 ret -> appendix1 = appx;
1050 appx[0]=k2int_tab;
1051 appx[1]=NULL+larger_value_first;
1052 ArrayListSort(ret, HashTableSortedIndexes_cmp_idx);
1053 return ret;
1054 }
1055