/src/maxflowhelper/tablefixed.c

http://github.com/webblue/maxflow · C · 671 lines · 392 code · 196 blank · 83 comment · 144 complexity · 7d73d583ce1f198f15d6a309c4503a8c MD5 · raw file

  1. #include "tablefixed.h"
  2. #include <stdlib.h>
  3. #include <limits.h>
  4. #include <assert.h>
  5. /***************************************************************************/
  6. /* Data structures */
  7. /***************************************************************************/
  8. struct TableFixed {
  9. unsigned long ulNumBindings;
  10. size_t uiKeySize;
  11. unsigned long ulNumBuckets;
  12. int (*compare)(const void *, const void *, size_t);
  13. unsigned long (*hash)(const void *, size_t);
  14. struct Node **ppnArray;
  15. };
  16. struct Node {
  17. const void *pvKey;
  18. void *pvValue;
  19. struct Node *next;
  20. };
  21. struct TableFixedIter {
  22. unsigned long ulCurrentBucket;
  23. struct TableFixed *oTableFixed;
  24. struct Node *pnCurrentNode;
  25. };
  26. typedef struct Node *Node_L;
  27. /***************************************************************************/
  28. /* Local function declarations */
  29. /***************************************************************************/
  30. static Node_L getNode(TableFixed_T oTableFixed, const void *pvKey);
  31. /* returns a pointer to the node with key pvKey, or NULL if there is no
  32. such node */
  33. static unsigned long calculateBuckets(unsigned long ulEstLength);
  34. /* returns the number of buckets that will be used in the hash table
  35. based on the estimated length */
  36. /* the following hash functions hash the key and return the hash code. hash8,
  37. hash 12, and hash16 are optimized for keys of the respective size */
  38. static unsigned long hashGeneric(const void *pvKey, size_t uiKeySize);
  39. static unsigned long hash8(const void *pvKey, size_t uiKeySize);
  40. static unsigned long hash12(const void *pvKey, size_t uiKeySize);
  41. static unsigned long hash16(const void *pvKey, size_t uiKeySize);
  42. /* the following compare functions return 0 if the two keys are equal, and
  43. 1 otherwise. compare8, compare12, and compare16 are optimized for keys
  44. of the respective sizes */
  45. static int compareGeneric(const void *pvKey1, const void *pvKey2,
  46. size_t uiKeySize);
  47. static int compare8(const void *pvKey1, const void *pvKey2, size_t uiKeySize);
  48. static int compare12(const void *pvKey1, const void *pvKey2, size_t uiKeySize);
  49. static int compare16(const void *pvKey1, const void *pvKey2, size_t uiKeySize);
  50. /***************************************************************************/
  51. /* TableFixed implementation */
  52. /***************************************************************************/
  53. TableFixed_T TableFixed_new(unsigned long ulEstLength, size_t uiKeySize)
  54. /* returns a new TableFixed_T. ulEstLength is an estimated max length of
  55. the table, and each key must contain uiKeySize bytes */
  56. {
  57. TableFixed_T oTableFixed;
  58. oTableFixed = (TableFixed_T) malloc(sizeof(*oTableFixed));
  59. assert(oTableFixed != NULL);
  60. /* initialize the fields */
  61. oTableFixed->ulNumBindings = 0;
  62. oTableFixed->uiKeySize = uiKeySize;
  63. oTableFixed->ulNumBuckets = calculateBuckets(ulEstLength);
  64. /* "install" the appropriate compare and hash functions */
  65. switch(uiKeySize) {
  66. case 8:
  67. oTableFixed->compare = compare8;
  68. oTableFixed->hash = hash8;
  69. break;
  70. case 12:
  71. oTableFixed->compare = compare12;
  72. oTableFixed->hash = hash12;
  73. break;
  74. case 16:
  75. oTableFixed->compare = compare16;
  76. oTableFixed->hash = hash16;
  77. break;
  78. default:
  79. oTableFixed->compare = compareGeneric;
  80. oTableFixed->hash = hashGeneric;
  81. }
  82. /* allocate memory for the array of pointers to bindings (nodes) */
  83. oTableFixed->ppnArray = (Node_L *) calloc(oTableFixed->ulNumBuckets,
  84. sizeof(*oTableFixed->ppnArray));
  85. assert(oTableFixed->ppnArray != NULL);
  86. return oTableFixed;
  87. }
  88. void TableFixed_free(TableFixed_T oTableFixed)
  89. /* frees all memory associated with oTableFixed */
  90. {
  91. int i;
  92. Node_L pn1, pn2;
  93. assert(oTableFixed != NULL);
  94. /* free the linked lists of bindings (nodes) */
  95. for(i = 0; i < oTableFixed->ulNumBuckets; i++) {
  96. pn1 = oTableFixed->ppnArray[i];
  97. while(pn1 != NULL) {
  98. pn2 = pn1->next;
  99. free(pn1);
  100. pn1 = pn2;
  101. }
  102. }
  103. free(oTableFixed->ppnArray);
  104. free(oTableFixed);
  105. }
  106. unsigned long TableFixed_length(TableFixed_T oTableFixed)
  107. /* returns the number of bindings in oTableFixed */
  108. {
  109. assert(oTableFixed != NULL);
  110. return oTableFixed->ulNumBindings;
  111. }
  112. int TableFixed_put(TableFixed_T oTableFixed, const void *pvKey, void *pvValue)
  113. /* adds a binding to oTableFixed with the specified pvKey and pvValue and
  114. returns 1 if successful. rejects bindings with duplicate keys and returns
  115. 0 */
  116. {
  117. unsigned long ulHashCode;
  118. Node_L *ppnNode;
  119. Node_L pnNewNode;
  120. assert(oTableFixed != NULL);
  121. assert(pvKey != NULL);
  122. assert(pvValue != NULL);
  123. /* return 0 if pvKey already exists in oTableFixed */
  124. if(getNode(oTableFixed, pvKey) != NULL)
  125. return 0;
  126. /* find appropriate bucket */
  127. ulHashCode = (*oTableFixed->hash)(pvKey, oTableFixed->uiKeySize);
  128. ppnNode = oTableFixed->ppnArray + (ulHashCode % oTableFixed->ulNumBuckets);
  129. /* create new node */
  130. pnNewNode = (Node_L) malloc(sizeof(*pnNewNode));
  131. assert(pnNewNode != NULL);
  132. pnNewNode->pvKey = pvKey;
  133. pnNewNode->pvValue = pvValue;
  134. /* link new node into list */
  135. pnNewNode->next = *ppnNode;
  136. *ppnNode = pnNewNode;
  137. oTableFixed->ulNumBindings++;
  138. return 1;
  139. }
  140. void *TableFixed_getValue(TableFixed_T oTableFixed, const void *pvKey)
  141. /* returns a pointer to the value of the binding with key pvKey. returns NULL
  142. if no such binding exists */
  143. {
  144. Node_L pnNode;
  145. assert(oTableFixed != NULL);
  146. assert(pvKey);
  147. pnNode = getNode(oTableFixed, pvKey);
  148. if(pnNode == NULL)
  149. return NULL;
  150. return pnNode->pvValue;
  151. }
  152. const void *TableFixed_getKey(TableFixed_T oTableFixed, const void *pvKey)
  153. /* returns a pointer to the key of the binding with key pvKey. returns NULL
  154. if no such binding exists */
  155. {
  156. Node_L pnNode;
  157. assert(oTableFixed != NULL);
  158. assert(pvKey != NULL);
  159. pnNode = getNode(oTableFixed, pvKey);
  160. if(pnNode == NULL)
  161. return NULL;
  162. return pnNode->pvKey;
  163. }
  164. int TableFixed_remove(TableFixed_T oTableFixed, const void *pvKey)
  165. /* removes binding from oTableFixed with a key of pvKey. returns 1 if
  166. successful and 0 otherwise (such as if no such key exists) */
  167. {
  168. Node_L pnNode, pnNodeBefore;
  169. Node_L *ppnArray;
  170. size_t uiKeySize;
  171. unsigned long ulHashCode;
  172. assert(oTableFixed != NULL);
  173. assert(pvKey != NULL);
  174. ppnArray = oTableFixed->ppnArray;
  175. uiKeySize = oTableFixed->uiKeySize;
  176. ulHashCode = (*oTableFixed->hash)(pvKey, uiKeySize);
  177. pnNodeBefore = ppnArray[ulHashCode % oTableFixed->ulNumBuckets];
  178. /* check if bucket is empty */
  179. if(pnNodeBefore == NULL)
  180. return 0;
  181. /* check if first node of list is to be removed */
  182. if((*oTableFixed->compare)(pvKey, pnNodeBefore->pvKey, uiKeySize) == 0) {
  183. ppnArray[ulHashCode % oTableFixed->ulNumBuckets] = pnNodeBefore->next;
  184. free(pnNodeBefore);
  185. }
  186. else {
  187. /* make pnNodeBefore point to node before the node to be removed */
  188. while(pnNodeBefore->next != NULL &&
  189. (*oTableFixed->compare)(pvKey, pnNodeBefore->next->pvKey,
  190. oTableFixed->uiKeySize) == 1)
  191. pnNodeBefore = pnNodeBefore->next;
  192. /* check if key is not in table */
  193. if(pnNodeBefore->next == NULL)
  194. return 0;
  195. /* remove binding */
  196. pnNode = pnNodeBefore->next;
  197. pnNodeBefore->next = pnNode->next;
  198. free(pnNode);
  199. }
  200. oTableFixed->ulNumBindings--;
  201. return 1;
  202. }
  203. void TableFixed_toArrays(TableFixed_T oTableFixed, const void **ppvKeyArray,
  204. void **ppvValueArray)
  205. /* fills ppvKeyArray with oTableFixed's keys and ppvValueArray with
  206. oTableFixed's values. the arrays must have enough space allocated for all
  207. the bindings (at least TableFixed_length() elements) */
  208. {
  209. Node_L pnNode;
  210. unsigned long i, ulLength;
  211. unsigned long ulPosition;
  212. assert(oTableFixed != NULL);
  213. assert(ppvKeyArray != NULL);
  214. assert(ppvValueArray != NULL);
  215. ulLength = oTableFixed->ulNumBuckets;
  216. ulPosition = 0;
  217. for(i = 0; i < ulLength; i++) {
  218. pnNode = oTableFixed->ppnArray[i];
  219. while(pnNode != NULL) {
  220. ppvKeyArray[ulPosition] = pnNode->pvKey;
  221. ppvValueArray[ulPosition++] = pnNode->pvValue;
  222. pnNode = pnNode->next;
  223. }
  224. }
  225. }
  226. void TableFixed_map(TableFixed_T oTableFixed,
  227. void (*pfApply)(const void *pvKey, void **ppvValue,
  228. void *pvExtra),
  229. void *pvExtra)
  230. /* applies function *pfApply to each binding in oTableFixed */
  231. {
  232. Node_L pnNode;
  233. unsigned long i, ulLength;
  234. assert(oTableFixed != NULL);
  235. assert(pfApply != NULL);
  236. ulLength = oTableFixed->ulNumBuckets;
  237. for(i = 0; i < ulLength; i++) {
  238. pnNode = oTableFixed->ppnArray[i];
  239. while(pnNode != NULL) {
  240. (*pfApply)(pnNode->pvKey, &pnNode->pvValue, pvExtra);
  241. pnNode = pnNode->next;
  242. }
  243. }
  244. }
  245. /***************************************************************************/
  246. /* Local function definitions */
  247. /***************************************************************************/
  248. static Node_L getNode(TableFixed_T oTableFixed, const void *pvKey)
  249. /* returns a pointer to the node with key pvKey, or NULL if there is no
  250. such node */
  251. {
  252. size_t uiKeySize;
  253. unsigned long ulHashCode;
  254. Node_L pnNode;
  255. assert(oTableFixed != NULL);
  256. assert(pvKey != NULL);
  257. /* find appropriate bucket */
  258. uiKeySize = oTableFixed->uiKeySize;
  259. ulHashCode = (*oTableFixed->hash)(pvKey, uiKeySize);
  260. pnNode = oTableFixed->ppnArray[ulHashCode % oTableFixed->ulNumBuckets];
  261. /* find node in bucket (keep pnNode NULL if it does not exist) */
  262. while(pnNode != NULL &&
  263. (*oTableFixed->compare)(pvKey, pnNode->pvKey, uiKeySize) == 1)
  264. pnNode = pnNode->next;
  265. return pnNode;
  266. }
  267. static unsigned long calculateBuckets(unsigned long ulEstLength)
  268. /* returns the number of buckets that will be used in the hash table
  269. based on the estimated length */
  270. {
  271. /* this code taken from Hanson book */
  272. int i;
  273. static unsigned long primes[] = { 509, 509, 1021, 2053, 4093, 8191, 16381,
  274. 32771, 65521, 130003, 260003, 520019,
  275. 1040021, 2080003, 4160003, 8320001,
  276. 16000057, 32000011, 64000031, 128000003,
  277. 256000001, 512000009, 1000000007,
  278. 1999999973, ULONG_MAX };
  279. for(i = 1; primes[i] < ulEstLength; i++);
  280. return primes[i - 1];
  281. }
  282. static unsigned long hashGeneric(const void *pvKey, size_t uiKeySize)
  283. /* hashes pvKey (returns the sum of its bytes) */
  284. {
  285. unsigned long ulHashCode = 0;
  286. char *pcKey = (char *) pvKey;
  287. size_t i;
  288. assert(pvKey != NULL);
  289. for(i = 0; i < uiKeySize; i++)
  290. ulHashCode += (unsigned long) pcKey[i];
  291. return ulHashCode;
  292. }
  293. static unsigned long hash8(const void *pvKey, size_t uiKeySize)
  294. /* same as hashGeneric, but optimized for keys 8 bytes long */
  295. {
  296. char *pcKey = (char *) pvKey;
  297. assert(pvKey != NULL);
  298. return (unsigned long) pcKey[0] + (unsigned long) pcKey[1] +
  299. (unsigned long) pcKey[2] + (unsigned long) pcKey[3] +
  300. (unsigned long) pcKey[4] + (unsigned long) pcKey[5] +
  301. (unsigned long) pcKey[6] + (unsigned long) pcKey[7];
  302. }
  303. static unsigned long hash12(const void *pvKey, size_t uiKeySize)
  304. /* same as hashGeneric, but optimized for keys 12 bytes long */
  305. {
  306. char *pcKey = (char *) pvKey;
  307. assert(pvKey != NULL);
  308. return (unsigned long) pcKey[0] + (unsigned long) pcKey[1] +
  309. (unsigned long) pcKey[2] + (unsigned long) pcKey[3] +
  310. (unsigned long) pcKey[4] + (unsigned long) pcKey[5] +
  311. (unsigned long) pcKey[6] + (unsigned long) pcKey[7] +
  312. (unsigned long) pcKey[8] + (unsigned long) pcKey[9] +
  313. (unsigned long) pcKey[10] + (unsigned long) pcKey[11];
  314. }
  315. static unsigned long hash16(const void *pvKey, size_t uiKeySize)
  316. /* same as hashGeneric, but optimized for keys 16 bytes long */
  317. {
  318. char *pcKey = (char *) pvKey;
  319. assert(pvKey != NULL);
  320. return (unsigned long) pcKey[0] + (unsigned long) pcKey[1] +
  321. (unsigned long) pcKey[2] + (unsigned long) pcKey[3] +
  322. (unsigned long) pcKey[4] + (unsigned long) pcKey[5] +
  323. (unsigned long) pcKey[6] + (unsigned long) pcKey[7] +
  324. (unsigned long) pcKey[8] + (unsigned long) pcKey[9] +
  325. (unsigned long) pcKey[10] + (unsigned long) pcKey[11] +
  326. (unsigned long) pcKey[12] + (unsigned long) pcKey[13] +
  327. (unsigned long) pcKey[14] + (unsigned long) pcKey[15];
  328. }
  329. static int compareGeneric(const void *pvKey1, const void *pvKey2,
  330. size_t uiKeySize)
  331. /* returns 0 if pvKey1 and pvKey2 are equal, 1 otherwise */
  332. {
  333. char *pcKey1 = (char *) pvKey1, *pcKey2 = (char *) pvKey2;
  334. size_t i;
  335. assert(pvKey1 != NULL);
  336. assert(pvKey2 != NULL);
  337. for(i = 0; i < uiKeySize; i++)
  338. if(pcKey1[i] != pcKey2[i])
  339. return 1;
  340. return 0;
  341. }
  342. static int compare8(const void *pvKey1, const void *pvKey2, size_t uiKeySize)
  343. /* same as compareGeneric but optimized for keys 8 bytes long */
  344. {
  345. char *pcKey1 = (char *) pvKey1, *pcKey2 = (char *) pvKey2;
  346. assert(pvKey1 != NULL);
  347. assert(pvKey2 != NULL);
  348. if(pcKey1[0] == pcKey2[0] && pcKey1[1] == pcKey2[1] &&
  349. pcKey1[2] == pcKey2[2] && pcKey1[3] == pcKey2[3] &&
  350. pcKey1[4] == pcKey2[4] && pcKey1[5] == pcKey2[5] &&
  351. pcKey1[6] == pcKey2[6] && pcKey1[7] == pcKey2[7])
  352. return 0;
  353. return 1;
  354. }
  355. static int compare12(const void *pvKey1, const void *pvKey2, size_t uiKeySize)
  356. /* same as compareGeneric but optimized for keys 12 bytes long */
  357. {
  358. char *pcKey1 = (char *) pvKey1, *pcKey2 = (char *) pvKey2;
  359. assert(pvKey1 != NULL);
  360. assert(pvKey2 != NULL);
  361. if(pcKey1[0] == pcKey2[0] && pcKey1[1] == pcKey2[1] &&
  362. pcKey1[2] == pcKey2[2] && pcKey1[3] == pcKey2[3] &&
  363. pcKey1[4] == pcKey2[4] && pcKey1[5] == pcKey2[5] &&
  364. pcKey1[6] == pcKey2[6] && pcKey1[7] == pcKey2[7] &&
  365. pcKey1[8] == pcKey2[8] && pcKey1[9] == pcKey2[9] &&
  366. pcKey1[10] == pcKey2[10] && pcKey1[11] == pcKey2[11])
  367. return 0;
  368. return 1;
  369. }
  370. static int compare16(const void *pvKey1, const void *pvKey2, size_t uiKeySize)
  371. /* same as compareGeneric but optimized for keys 16 bytes long */
  372. {
  373. char *pcKey1 = (char *) pvKey1, *pcKey2 = (char *) pvKey2;
  374. assert(pvKey1 != NULL);
  375. assert(pvKey2 != NULL);
  376. if(pcKey1[0] == pcKey2[0] && pcKey1[1] == pcKey2[1] &&
  377. pcKey1[2] == pcKey2[2] && pcKey1[3] == pcKey2[3] &&
  378. pcKey1[4] == pcKey2[4] && pcKey1[5] == pcKey2[5] &&
  379. pcKey1[6] == pcKey2[6] && pcKey1[7] == pcKey2[7] &&
  380. pcKey1[8] == pcKey2[8] && pcKey1[9] == pcKey2[9] &&
  381. pcKey1[10] == pcKey2[10] && pcKey1[11] == pcKey2[11] &&
  382. pcKey1[12] == pcKey2[12] && pcKey1[13] == pcKey2[13] &&
  383. pcKey1[14] == pcKey2[14] && pcKey1[15] == pcKey2[15])
  384. return 0;
  385. return 1;
  386. }
  387. /***************************************************************************/
  388. /* TableFixedIter implementation */
  389. /***************************************************************************/
  390. TableFixedIter_T TableFixedIter_new(TableFixed_T oTableFixed)
  391. /* returns a new TableFixedIter_T, which is initially in an invalid state */
  392. {
  393. TableFixedIter_T oTableFixedIter;
  394. assert(oTableFixed != NULL);
  395. oTableFixedIter = (TableFixedIter_T) malloc(sizeof(*oTableFixedIter));
  396. assert(oTableFixedIter != NULL);
  397. /* initialize fields */
  398. oTableFixedIter->ulCurrentBucket = 0;
  399. oTableFixedIter->oTableFixed = oTableFixed;
  400. oTableFixedIter->pnCurrentNode = NULL;
  401. return oTableFixedIter;
  402. }
  403. void TableFixedIter_free(TableFixedIter_T oTableFixedIter)
  404. /* frees all dynamically allocated memory associated with oTableFixedIter */
  405. {
  406. assert(oTableFixedIter != NULL);
  407. free(oTableFixedIter);
  408. }
  409. int TableFixedIter_valid(TableFixedIter_T oTableFixedIter)
  410. /* returns 1 if oTableFixedIter is in a valid state, 0 otherwise */
  411. {
  412. assert(oTableFixedIter != NULL);
  413. if(oTableFixedIter->pnCurrentNode == NULL)
  414. return 0;
  415. return 1;
  416. }
  417. void TableFixedIter_selectFirst(TableFixedIter_T oTableFixedIter)
  418. /* sets the first binding to the current binding and sets oTableFixedIter
  419. to a valid state if and only if the table contains at least one binding */
  420. {
  421. unsigned long i, ulLength;
  422. TableFixed_T oTableFixed;
  423. assert(oTableFixedIter != NULL);
  424. oTableFixed = oTableFixedIter->oTableFixed;
  425. ulLength = oTableFixed->ulNumBuckets;
  426. oTableFixedIter->pnCurrentNode = NULL;
  427. /* loop through buckets until a non-NULL one is found */
  428. for(i = 0; i < ulLength; i++) {
  429. if(oTableFixed->ppnArray[i] != NULL) {
  430. oTableFixedIter->pnCurrentNode = oTableFixed->ppnArray[i];
  431. oTableFixedIter->ulCurrentBucket = i;
  432. return;
  433. }
  434. }
  435. }
  436. void TableFixedIter_selectNext(TableFixedIter_T oTableFixedIter)
  437. /* sets the next binding to the current binding. sets oTableFixedIter to an
  438. invalid state if there is no next binding */
  439. {
  440. unsigned long i, ulLength;
  441. TableFixed_T oTableFixed;
  442. assert(oTableFixedIter != NULL);
  443. assert(oTableFixedIter->pnCurrentNode != NULL);
  444. oTableFixed = oTableFixedIter->oTableFixed;
  445. /* if the next binding is in the same bucket */
  446. if(oTableFixedIter->pnCurrentNode->next != NULL) {
  447. oTableFixedIter->pnCurrentNode = oTableFixedIter->pnCurrentNode->next;
  448. return;
  449. }
  450. ulLength = oTableFixed->ulNumBuckets;
  451. /* otherwise, step through buckets until find a binding */
  452. for(i = oTableFixedIter->ulCurrentBucket + 1; i < ulLength; i++) {
  453. if(oTableFixed->ppnArray[i] != NULL) {
  454. oTableFixedIter->pnCurrentNode = oTableFixed->ppnArray[i];
  455. oTableFixedIter->ulCurrentBucket = i;
  456. return;
  457. }
  458. }
  459. /* if there are no bindings, state becomes invalid */
  460. oTableFixedIter->pnCurrentNode = NULL;
  461. }
  462. const void *TableFixedIter_selectedKey(TableFixedIter_T oTableFixedIter)
  463. /* returns a pointer to the current binding's key */
  464. {
  465. assert(oTableFixedIter != NULL);
  466. assert(oTableFixedIter->pnCurrentNode != NULL);
  467. return oTableFixedIter->pnCurrentNode->pvKey;
  468. }
  469. void *TableFixedIter_selectedValue(TableFixedIter_T oTableFixedIter)
  470. /* returns a pointer to the current binding's value */
  471. {
  472. assert(oTableFixedIter != NULL);
  473. assert(oTableFixedIter->pnCurrentNode != NULL);
  474. return oTableFixedIter->pnCurrentNode->pvValue;
  475. }