A clone of btpd with my configuration changes.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

177 lines
3.7 KiB

  1. #include <stdlib.h>
  2. #include <inttypes.h>
  3. #include "hashtable.h"
  4. struct _htbl {
  5. int (*eq)(const void *, const void *);
  6. uint32_t (*hash)(const void *);
  7. struct _any **buckets;
  8. size_t buckcnt;
  9. size_t size;
  10. size_t keyoff;
  11. size_t chainoff;
  12. };
  13. #define KEYP(tbl, o) ((void *)(o) + (tbl)->keyoff)
  14. #define CHAINP(tbl, o) *(struct _any **)((void *)(o) + (tbl)->chainoff)
  15. struct _htbl *
  16. _htbl_create(int (*eq)(const void *, const void *),
  17. uint32_t (*hash)(const void *), size_t keyoff, size_t chainoff)
  18. {
  19. struct _htbl *tbl = calloc(1, sizeof(*tbl));
  20. if (tbl == NULL)
  21. return NULL;
  22. tbl->size = 0;
  23. tbl->buckcnt = 1;
  24. tbl->keyoff = keyoff;
  25. tbl->chainoff = chainoff;
  26. tbl->hash = hash;
  27. tbl->eq = eq;
  28. tbl->buckets = calloc(tbl->buckcnt, sizeof(*tbl->buckets));
  29. if (tbl->buckets == NULL) {
  30. free(tbl);
  31. return NULL;
  32. }
  33. return tbl;
  34. }
  35. void
  36. _htbl_free(struct _htbl *tbl)
  37. {
  38. free(tbl->buckets);
  39. free(tbl);
  40. }
  41. static struct _any *
  42. bucket_rev(struct _htbl *tbl, struct _any *p, struct _any *n)
  43. {
  44. while (n != NULL) {
  45. struct _any *s = CHAINP(tbl, n);
  46. CHAINP(tbl, n) = p;
  47. p = n;
  48. n = s;
  49. }
  50. return p;
  51. }
  52. static void
  53. bucket_insert(struct _htbl *tbl, struct _any *o)
  54. {
  55. size_t bi = tbl->hash(KEYP(tbl, o)) % tbl->buckcnt;
  56. CHAINP(tbl, o) = tbl->buckets[bi];
  57. tbl->buckets[bi] = o;
  58. }
  59. static void
  60. _htbl_grow(struct _htbl *tbl)
  61. {
  62. size_t ncnt = 2 * tbl->buckcnt + 1;
  63. size_t ocnt = tbl->buckcnt;
  64. struct _any **obuckets = tbl->buckets;
  65. struct _any **nbuckets = calloc(ncnt, sizeof(*nbuckets));
  66. if (nbuckets == NULL)
  67. return;
  68. tbl->buckcnt = ncnt;
  69. tbl->buckets = nbuckets;
  70. for (size_t i = 0; i < ocnt; i++) {
  71. struct _any *o = bucket_rev(tbl, NULL, obuckets[i]);
  72. while (o != NULL) {
  73. struct _any *s = CHAINP(tbl, o);
  74. bucket_insert(tbl, o);
  75. o = s;
  76. }
  77. }
  78. free(obuckets);
  79. }
  80. void
  81. _htbl_insert(struct _htbl *tbl, struct _any *o)
  82. {
  83. bucket_insert(tbl, o);
  84. tbl->size++;
  85. if (tbl->size > tbl->buckcnt * 4 / 5)
  86. _htbl_grow(tbl);
  87. }
  88. struct _any *
  89. _htbl_find(struct _htbl *tbl, const void *key)
  90. {
  91. struct _any *ret;
  92. size_t bi = tbl->hash(key) % tbl->buckcnt;
  93. for (ret = tbl->buckets[bi]; ret != NULL; ret = CHAINP(tbl, ret))
  94. if (tbl->eq(KEYP(tbl, ret), key))
  95. return ret;
  96. return NULL;
  97. }
  98. struct _any *
  99. _htbl_remove(struct _htbl *tbl, const void *key)
  100. {
  101. size_t bi = tbl->hash(key) % tbl->buckcnt;
  102. struct _any *p = NULL, *o = tbl->buckets[bi];
  103. while (o != NULL && !tbl->eq(KEYP(tbl, o), key)) {
  104. p = o;
  105. o = CHAINP(tbl, o);
  106. }
  107. if (o != NULL) {
  108. if (p == NULL)
  109. tbl->buckets[bi] = CHAINP(tbl, o);
  110. else
  111. CHAINP(tbl, p) = CHAINP(tbl, o);
  112. tbl->size--;
  113. }
  114. return o;
  115. }
  116. void
  117. _htbl_tov(struct _htbl *tbl, struct _any **v)
  118. {
  119. size_t vi = 0;
  120. size_t bi = 0;
  121. struct _any *o = tbl->buckets[bi];
  122. while (vi < tbl->size) {
  123. while (o == NULL) {
  124. bi++;
  125. o = tbl->buckets[bi];
  126. }
  127. v[vi] = o;
  128. vi++;
  129. o = CHAINP(tbl, o);
  130. }
  131. }
  132. size_t
  133. _htbl_size(struct _htbl *tbl)
  134. {
  135. return tbl->size;
  136. }
  137. void
  138. _htbl_iter_init(struct _htbl *tbl, struct htbl_iter *it)
  139. {
  140. it->tbl = tbl;
  141. it->bi = 0;
  142. it->cnt = 0;
  143. it->obj = NULL;
  144. }
  145. struct _any *
  146. _htbl_iter_next(struct htbl_iter *it)
  147. {
  148. if (it->cnt == it->tbl->size)
  149. return NULL;
  150. it->obj = it->cnt == 0 ?
  151. it->tbl->buckets[it->bi] : CHAINP(it->tbl, it->obj);
  152. while (it->obj == NULL) {
  153. it->bi++;
  154. it->obj = it->tbl->buckets[it->bi];
  155. }
  156. it->cnt++;
  157. return it->obj;
  158. }