PageRenderTime 75ms CodeModel.GetById 37ms app.highlight 34ms RepoModel.GetById 1ms app.codeStats 0ms

/src/maxflowhelper/tablefixed.c

http://github.com/webblue/maxflow
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}