/src/maxflowhelper/tablefixed.c
C | 671 lines | 392 code | 196 blank | 83 comment | 138 complexity | 7d73d583ce1f198f15d6a309c4503a8c MD5 | raw file
1#include "tablefixed.h" 2#include <stdlib.h> 3#include <limits.h> 4#include <assert.h> 5 6 7/***************************************************************************/ 8/* Data structures */ 9/***************************************************************************/ 10 11 12struct TableFixed { 13 unsigned long ulNumBindings; 14 size_t uiKeySize; 15 unsigned long ulNumBuckets; 16 int (*compare)(const void *, const void *, size_t); 17 unsigned long (*hash)(const void *, size_t); 18 struct Node **ppnArray; 19}; 20 21struct Node { 22 const void *pvKey; 23 void *pvValue; 24 struct Node *next; 25}; 26 27struct TableFixedIter { 28 unsigned long ulCurrentBucket; 29 struct TableFixed *oTableFixed; 30 struct Node *pnCurrentNode; 31}; 32 33typedef struct Node *Node_L; 34 35 36/***************************************************************************/ 37/* Local function declarations */ 38/***************************************************************************/ 39 40 41static Node_L getNode(TableFixed_T oTableFixed, const void *pvKey); 42/* returns a pointer to the node with key pvKey, or NULL if there is no 43 such node */ 44 45static unsigned long calculateBuckets(unsigned long ulEstLength); 46/* returns the number of buckets that will be used in the hash table 47 based on the estimated length */ 48 49/* the following hash functions hash the key and return the hash code. hash8, 50 hash 12, and hash16 are optimized for keys of the respective size */ 51static unsigned long hashGeneric(const void *pvKey, size_t uiKeySize); 52static unsigned long hash8(const void *pvKey, size_t uiKeySize); 53static unsigned long hash12(const void *pvKey, size_t uiKeySize); 54static unsigned long hash16(const void *pvKey, size_t uiKeySize); 55 56/* the following compare functions return 0 if the two keys are equal, and 57 1 otherwise. compare8, compare12, and compare16 are optimized for keys 58 of the respective sizes */ 59static int compareGeneric(const void *pvKey1, const void *pvKey2, 60 size_t uiKeySize); 61static int compare8(const void *pvKey1, const void *pvKey2, size_t uiKeySize); 62static int compare12(const void *pvKey1, const void *pvKey2, size_t uiKeySize); 63static int compare16(const void *pvKey1, const void *pvKey2, size_t uiKeySize); 64 65 66/***************************************************************************/ 67/* TableFixed implementation */ 68/***************************************************************************/ 69 70 71TableFixed_T TableFixed_new(unsigned long ulEstLength, size_t uiKeySize) 72 73/* returns a new TableFixed_T. ulEstLength is an estimated max length of 74 the table, and each key must contain uiKeySize bytes */ 75 76{ 77 TableFixed_T oTableFixed; 78 79 oTableFixed = (TableFixed_T) malloc(sizeof(*oTableFixed)); 80 assert(oTableFixed != NULL); 81 82 /* initialize the fields */ 83 oTableFixed->ulNumBindings = 0; 84 oTableFixed->uiKeySize = uiKeySize; 85 oTableFixed->ulNumBuckets = calculateBuckets(ulEstLength); 86 87 /* "install" the appropriate compare and hash functions */ 88 switch(uiKeySize) { 89 case 8: 90 oTableFixed->compare = compare8; 91 oTableFixed->hash = hash8; 92 break; 93 case 12: 94 oTableFixed->compare = compare12; 95 oTableFixed->hash = hash12; 96 break; 97 case 16: 98 oTableFixed->compare = compare16; 99 oTableFixed->hash = hash16; 100 break; 101 default: 102 oTableFixed->compare = compareGeneric; 103 oTableFixed->hash = hashGeneric; 104 } 105 106 /* allocate memory for the array of pointers to bindings (nodes) */ 107 oTableFixed->ppnArray = (Node_L *) calloc(oTableFixed->ulNumBuckets, 108 sizeof(*oTableFixed->ppnArray)); 109 assert(oTableFixed->ppnArray != NULL); 110 111 return oTableFixed; 112} 113 114 115void TableFixed_free(TableFixed_T oTableFixed) 116 117/* frees all memory associated with oTableFixed */ 118 119{ 120 int i; 121 Node_L pn1, pn2; 122 123 assert(oTableFixed != NULL); 124 125 /* free the linked lists of bindings (nodes) */ 126 for(i = 0; i < oTableFixed->ulNumBuckets; i++) { 127 pn1 = oTableFixed->ppnArray[i]; 128 while(pn1 != NULL) { 129 pn2 = pn1->next; 130 free(pn1); 131 pn1 = pn2; 132 } 133 } 134 135 free(oTableFixed->ppnArray); 136 free(oTableFixed); 137} 138 139 140unsigned long TableFixed_length(TableFixed_T oTableFixed) 141 142/* returns the number of bindings in oTableFixed */ 143 144{ 145 assert(oTableFixed != NULL); 146 return oTableFixed->ulNumBindings; 147} 148 149 150int TableFixed_put(TableFixed_T oTableFixed, const void *pvKey, void *pvValue) 151 152/* adds a binding to oTableFixed with the specified pvKey and pvValue and 153 returns 1 if successful. rejects bindings with duplicate keys and returns 154 0 */ 155 156{ 157 unsigned long ulHashCode; 158 Node_L *ppnNode; 159 Node_L pnNewNode; 160 161 assert(oTableFixed != NULL); 162 assert(pvKey != NULL); 163 assert(pvValue != NULL); 164 165 /* return 0 if pvKey already exists in oTableFixed */ 166 if(getNode(oTableFixed, pvKey) != NULL) 167 return 0; 168 169 /* find appropriate bucket */ 170 ulHashCode = (*oTableFixed->hash)(pvKey, oTableFixed->uiKeySize); 171 ppnNode = oTableFixed->ppnArray + (ulHashCode % oTableFixed->ulNumBuckets); 172 173 /* create new node */ 174 pnNewNode = (Node_L) malloc(sizeof(*pnNewNode)); 175 assert(pnNewNode != NULL); 176 pnNewNode->pvKey = pvKey; 177 pnNewNode->pvValue = pvValue; 178 179 /* link new node into list */ 180 pnNewNode->next = *ppnNode; 181 *ppnNode = pnNewNode; 182 183 oTableFixed->ulNumBindings++; 184 185 return 1; 186} 187 188 189void *TableFixed_getValue(TableFixed_T oTableFixed, const void *pvKey) 190 191/* returns a pointer to the value of the binding with key pvKey. returns NULL 192 if no such binding exists */ 193 194{ 195 Node_L pnNode; 196 197 assert(oTableFixed != NULL); 198 assert(pvKey); 199 200 pnNode = getNode(oTableFixed, pvKey); 201 if(pnNode == NULL) 202 return NULL; 203 return pnNode->pvValue; 204} 205 206 207const void *TableFixed_getKey(TableFixed_T oTableFixed, const void *pvKey) 208 209/* returns a pointer to the key of the binding with key pvKey. returns NULL 210 if no such binding exists */ 211 212{ 213 Node_L pnNode; 214 215 assert(oTableFixed != NULL); 216 assert(pvKey != NULL); 217 218 pnNode = getNode(oTableFixed, pvKey); 219 if(pnNode == NULL) 220 return NULL; 221 return pnNode->pvKey; 222} 223 224 225int TableFixed_remove(TableFixed_T oTableFixed, const void *pvKey) 226 227/* removes binding from oTableFixed with a key of pvKey. returns 1 if 228 successful and 0 otherwise (such as if no such key exists) */ 229 230{ 231 Node_L pnNode, pnNodeBefore; 232 Node_L *ppnArray; 233 size_t uiKeySize; 234 unsigned long ulHashCode; 235 236 assert(oTableFixed != NULL); 237 assert(pvKey != NULL); 238 239 ppnArray = oTableFixed->ppnArray; 240 uiKeySize = oTableFixed->uiKeySize; 241 ulHashCode = (*oTableFixed->hash)(pvKey, uiKeySize); 242 pnNodeBefore = ppnArray[ulHashCode % oTableFixed->ulNumBuckets]; 243 244 /* check if bucket is empty */ 245 if(pnNodeBefore == NULL) 246 return 0; 247 248 /* check if first node of list is to be removed */ 249 if((*oTableFixed->compare)(pvKey, pnNodeBefore->pvKey, uiKeySize) == 0) { 250 ppnArray[ulHashCode % oTableFixed->ulNumBuckets] = pnNodeBefore->next; 251 free(pnNodeBefore); 252 } 253 254 else { 255 /* make pnNodeBefore point to node before the node to be removed */ 256 while(pnNodeBefore->next != NULL && 257 (*oTableFixed->compare)(pvKey, pnNodeBefore->next->pvKey, 258 oTableFixed->uiKeySize) == 1) 259 pnNodeBefore = pnNodeBefore->next; 260 261 /* check if key is not in table */ 262 if(pnNodeBefore->next == NULL) 263 return 0; 264 265 /* remove binding */ 266 pnNode = pnNodeBefore->next; 267 pnNodeBefore->next = pnNode->next; 268 free(pnNode); 269 } 270 271 oTableFixed->ulNumBindings--; 272 273 return 1; 274} 275 276 277void TableFixed_toArrays(TableFixed_T oTableFixed, const void **ppvKeyArray, 278 void **ppvValueArray) 279 280/* fills ppvKeyArray with oTableFixed's keys and ppvValueArray with 281 oTableFixed's values. the arrays must have enough space allocated for all 282 the bindings (at least TableFixed_length() elements) */ 283 284{ 285 Node_L pnNode; 286 unsigned long i, ulLength; 287 unsigned long ulPosition; 288 289 assert(oTableFixed != NULL); 290 assert(ppvKeyArray != NULL); 291 assert(ppvValueArray != NULL); 292 293 ulLength = oTableFixed->ulNumBuckets; 294 295 ulPosition = 0; 296 for(i = 0; i < ulLength; i++) { 297 pnNode = oTableFixed->ppnArray[i]; 298 while(pnNode != NULL) { 299 ppvKeyArray[ulPosition] = pnNode->pvKey; 300 ppvValueArray[ulPosition++] = pnNode->pvValue; 301 pnNode = pnNode->next; 302 } 303 } 304} 305 306 307void TableFixed_map(TableFixed_T oTableFixed, 308 void (*pfApply)(const void *pvKey, void **ppvValue, 309 void *pvExtra), 310 void *pvExtra) 311 312/* applies function *pfApply to each binding in oTableFixed */ 313 314{ 315 Node_L pnNode; 316 unsigned long i, ulLength; 317 318 assert(oTableFixed != NULL); 319 assert(pfApply != NULL); 320 321 ulLength = oTableFixed->ulNumBuckets; 322 323 for(i = 0; i < ulLength; i++) { 324 pnNode = oTableFixed->ppnArray[i]; 325 while(pnNode != NULL) { 326 (*pfApply)(pnNode->pvKey, &pnNode->pvValue, pvExtra); 327 pnNode = pnNode->next; 328 } 329 } 330} 331 332 333 334/***************************************************************************/ 335/* Local function definitions */ 336/***************************************************************************/ 337 338 339static Node_L getNode(TableFixed_T oTableFixed, const void *pvKey) 340 341/* returns a pointer to the node with key pvKey, or NULL if there is no 342 such node */ 343 344{ 345 size_t uiKeySize; 346 unsigned long ulHashCode; 347 Node_L pnNode; 348 349 assert(oTableFixed != NULL); 350 assert(pvKey != NULL); 351 352 /* find appropriate bucket */ 353 uiKeySize = oTableFixed->uiKeySize; 354 ulHashCode = (*oTableFixed->hash)(pvKey, uiKeySize); 355 pnNode = oTableFixed->ppnArray[ulHashCode % oTableFixed->ulNumBuckets]; 356 357 /* find node in bucket (keep pnNode NULL if it does not exist) */ 358 while(pnNode != NULL && 359 (*oTableFixed->compare)(pvKey, pnNode->pvKey, uiKeySize) == 1) 360 pnNode = pnNode->next; 361 362 return pnNode; 363} 364 365 366static unsigned long calculateBuckets(unsigned long ulEstLength) 367 368/* returns the number of buckets that will be used in the hash table 369 based on the estimated length */ 370 371{ 372 /* this code taken from Hanson book */ 373 374 int i; 375 static unsigned long primes[] = { 509, 509, 1021, 2053, 4093, 8191, 16381, 376 32771, 65521, 130003, 260003, 520019, 377 1040021, 2080003, 4160003, 8320001, 378 16000057, 32000011, 64000031, 128000003, 379 256000001, 512000009, 1000000007, 380 1999999973, ULONG_MAX }; 381 382 for(i = 1; primes[i] < ulEstLength; i++); 383 return primes[i - 1]; 384} 385 386 387static unsigned long hashGeneric(const void *pvKey, size_t uiKeySize) 388 389/* hashes pvKey (returns the sum of its bytes) */ 390 391{ 392 unsigned long ulHashCode = 0; 393 char *pcKey = (char *) pvKey; 394 size_t i; 395 396 assert(pvKey != NULL); 397 398 for(i = 0; i < uiKeySize; i++) 399 ulHashCode += (unsigned long) pcKey[i]; 400 401 return ulHashCode; 402} 403 404 405static unsigned long hash8(const void *pvKey, size_t uiKeySize) 406 407/* same as hashGeneric, but optimized for keys 8 bytes long */ 408 409{ 410 char *pcKey = (char *) pvKey; 411 412 assert(pvKey != NULL); 413 414 return (unsigned long) pcKey[0] + (unsigned long) pcKey[1] + 415 (unsigned long) pcKey[2] + (unsigned long) pcKey[3] + 416 (unsigned long) pcKey[4] + (unsigned long) pcKey[5] + 417 (unsigned long) pcKey[6] + (unsigned long) pcKey[7]; 418} 419 420 421static unsigned long hash12(const void *pvKey, size_t uiKeySize) 422 423/* same as hashGeneric, but optimized for keys 12 bytes long */ 424 425{ 426 char *pcKey = (char *) pvKey; 427 428 assert(pvKey != NULL); 429 430 return (unsigned long) pcKey[0] + (unsigned long) pcKey[1] + 431 (unsigned long) pcKey[2] + (unsigned long) pcKey[3] + 432 (unsigned long) pcKey[4] + (unsigned long) pcKey[5] + 433 (unsigned long) pcKey[6] + (unsigned long) pcKey[7] + 434 (unsigned long) pcKey[8] + (unsigned long) pcKey[9] + 435 (unsigned long) pcKey[10] + (unsigned long) pcKey[11]; 436} 437 438 439static unsigned long hash16(const void *pvKey, size_t uiKeySize) 440 441/* same as hashGeneric, but optimized for keys 16 bytes long */ 442 443{ 444 char *pcKey = (char *) pvKey; 445 446 assert(pvKey != NULL); 447 448 return (unsigned long) pcKey[0] + (unsigned long) pcKey[1] + 449 (unsigned long) pcKey[2] + (unsigned long) pcKey[3] + 450 (unsigned long) pcKey[4] + (unsigned long) pcKey[5] + 451 (unsigned long) pcKey[6] + (unsigned long) pcKey[7] + 452 (unsigned long) pcKey[8] + (unsigned long) pcKey[9] + 453 (unsigned long) pcKey[10] + (unsigned long) pcKey[11] + 454 (unsigned long) pcKey[12] + (unsigned long) pcKey[13] + 455 (unsigned long) pcKey[14] + (unsigned long) pcKey[15]; 456} 457 458 459static int compareGeneric(const void *pvKey1, const void *pvKey2, 460 size_t uiKeySize) 461 462/* returns 0 if pvKey1 and pvKey2 are equal, 1 otherwise */ 463 464{ 465 char *pcKey1 = (char *) pvKey1, *pcKey2 = (char *) pvKey2; 466 size_t i; 467 468 assert(pvKey1 != NULL); 469 assert(pvKey2 != NULL); 470 471 for(i = 0; i < uiKeySize; i++) 472 if(pcKey1[i] != pcKey2[i]) 473 return 1; 474 return 0; 475} 476 477 478static int compare8(const void *pvKey1, const void *pvKey2, size_t uiKeySize) 479 480/* same as compareGeneric but optimized for keys 8 bytes long */ 481 482{ 483 char *pcKey1 = (char *) pvKey1, *pcKey2 = (char *) pvKey2; 484 485 assert(pvKey1 != NULL); 486 assert(pvKey2 != NULL); 487 488 if(pcKey1[0] == pcKey2[0] && pcKey1[1] == pcKey2[1] && 489 pcKey1[2] == pcKey2[2] && pcKey1[3] == pcKey2[3] && 490 pcKey1[4] == pcKey2[4] && pcKey1[5] == pcKey2[5] && 491 pcKey1[6] == pcKey2[6] && pcKey1[7] == pcKey2[7]) 492 return 0; 493 return 1; 494} 495 496 497static int compare12(const void *pvKey1, const void *pvKey2, size_t uiKeySize) 498 499/* same as compareGeneric but optimized for keys 12 bytes long */ 500 501{ 502 char *pcKey1 = (char *) pvKey1, *pcKey2 = (char *) pvKey2; 503 504 assert(pvKey1 != NULL); 505 assert(pvKey2 != NULL); 506 507 if(pcKey1[0] == pcKey2[0] && pcKey1[1] == pcKey2[1] && 508 pcKey1[2] == pcKey2[2] && pcKey1[3] == pcKey2[3] && 509 pcKey1[4] == pcKey2[4] && pcKey1[5] == pcKey2[5] && 510 pcKey1[6] == pcKey2[6] && pcKey1[7] == pcKey2[7] && 511 pcKey1[8] == pcKey2[8] && pcKey1[9] == pcKey2[9] && 512 pcKey1[10] == pcKey2[10] && pcKey1[11] == pcKey2[11]) 513 return 0; 514 return 1; 515} 516 517 518static int compare16(const void *pvKey1, const void *pvKey2, size_t uiKeySize) 519 520/* same as compareGeneric but optimized for keys 16 bytes long */ 521 522{ 523 char *pcKey1 = (char *) pvKey1, *pcKey2 = (char *) pvKey2; 524 525 assert(pvKey1 != NULL); 526 assert(pvKey2 != NULL); 527 528 if(pcKey1[0] == pcKey2[0] && pcKey1[1] == pcKey2[1] && 529 pcKey1[2] == pcKey2[2] && pcKey1[3] == pcKey2[3] && 530 pcKey1[4] == pcKey2[4] && pcKey1[5] == pcKey2[5] && 531 pcKey1[6] == pcKey2[6] && pcKey1[7] == pcKey2[7] && 532 pcKey1[8] == pcKey2[8] && pcKey1[9] == pcKey2[9] && 533 pcKey1[10] == pcKey2[10] && pcKey1[11] == pcKey2[11] && 534 pcKey1[12] == pcKey2[12] && pcKey1[13] == pcKey2[13] && 535 pcKey1[14] == pcKey2[14] && pcKey1[15] == pcKey2[15]) 536 return 0; 537 return 1; 538} 539 540 541 542/***************************************************************************/ 543/* TableFixedIter implementation */ 544/***************************************************************************/ 545 546 547TableFixedIter_T TableFixedIter_new(TableFixed_T oTableFixed) 548 549/* returns a new TableFixedIter_T, which is initially in an invalid state */ 550 551{ 552 TableFixedIter_T oTableFixedIter; 553 554 assert(oTableFixed != NULL); 555 556 oTableFixedIter = (TableFixedIter_T) malloc(sizeof(*oTableFixedIter)); 557 assert(oTableFixedIter != NULL); 558 559 /* initialize fields */ 560 oTableFixedIter->ulCurrentBucket = 0; 561 oTableFixedIter->oTableFixed = oTableFixed; 562 oTableFixedIter->pnCurrentNode = NULL; 563 564 return oTableFixedIter; 565} 566 567 568void TableFixedIter_free(TableFixedIter_T oTableFixedIter) 569 570/* frees all dynamically allocated memory associated with oTableFixedIter */ 571 572{ 573 assert(oTableFixedIter != NULL); 574 free(oTableFixedIter); 575} 576 577 578int TableFixedIter_valid(TableFixedIter_T oTableFixedIter) 579 580/* returns 1 if oTableFixedIter is in a valid state, 0 otherwise */ 581 582{ 583 assert(oTableFixedIter != NULL); 584 if(oTableFixedIter->pnCurrentNode == NULL) 585 return 0; 586 return 1; 587} 588 589 590void TableFixedIter_selectFirst(TableFixedIter_T oTableFixedIter) 591 592/* sets the first binding to the current binding and sets oTableFixedIter 593 to a valid state if and only if the table contains at least one binding */ 594 595{ 596 unsigned long i, ulLength; 597 TableFixed_T oTableFixed; 598 599 assert(oTableFixedIter != NULL); 600 601 oTableFixed = oTableFixedIter->oTableFixed; 602 ulLength = oTableFixed->ulNumBuckets; 603 oTableFixedIter->pnCurrentNode = NULL; 604 605 /* loop through buckets until a non-NULL one is found */ 606 for(i = 0; i < ulLength; i++) { 607 if(oTableFixed->ppnArray[i] != NULL) { 608 oTableFixedIter->pnCurrentNode = oTableFixed->ppnArray[i]; 609 oTableFixedIter->ulCurrentBucket = i; 610 return; 611 } 612 } 613} 614 615 616void TableFixedIter_selectNext(TableFixedIter_T oTableFixedIter) 617 618/* sets the next binding to the current binding. sets oTableFixedIter to an 619 invalid state if there is no next binding */ 620 621{ 622 unsigned long i, ulLength; 623 TableFixed_T oTableFixed; 624 625 assert(oTableFixedIter != NULL); 626 assert(oTableFixedIter->pnCurrentNode != NULL); 627 628 oTableFixed = oTableFixedIter->oTableFixed; 629 630 /* if the next binding is in the same bucket */ 631 if(oTableFixedIter->pnCurrentNode->next != NULL) { 632 oTableFixedIter->pnCurrentNode = oTableFixedIter->pnCurrentNode->next; 633 return; 634 } 635 636 ulLength = oTableFixed->ulNumBuckets; 637 638 /* otherwise, step through buckets until find a binding */ 639 for(i = oTableFixedIter->ulCurrentBucket + 1; i < ulLength; i++) { 640 if(oTableFixed->ppnArray[i] != NULL) { 641 oTableFixedIter->pnCurrentNode = oTableFixed->ppnArray[i]; 642 oTableFixedIter->ulCurrentBucket = i; 643 return; 644 } 645 } 646 647 /* if there are no bindings, state becomes invalid */ 648 oTableFixedIter->pnCurrentNode = NULL; 649} 650 651 652const void *TableFixedIter_selectedKey(TableFixedIter_T oTableFixedIter) 653 654/* returns a pointer to the current binding's key */ 655 656{ 657 assert(oTableFixedIter != NULL); 658 assert(oTableFixedIter->pnCurrentNode != NULL); 659 return oTableFixedIter->pnCurrentNode->pvKey; 660} 661 662 663void *TableFixedIter_selectedValue(TableFixedIter_T oTableFixedIter) 664 665/* returns a pointer to the current binding's value */ 666 667{ 668 assert(oTableFixedIter != NULL); 669 assert(oTableFixedIter->pnCurrentNode != NULL); 670 return oTableFixedIter->pnCurrentNode->pvValue; 671}