Source code pulled from OpenBSD for OpenNTPD. The place to contribute to this code is via the OpenBSD CVS tree.
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.

327 lines
6.7 KiB

  1. /* $OpenBSD: ohash.c,v 1.1 2014/06/02 18:52:03 deraadt Exp $ */
  2. /* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
  3. *
  4. * Permission to use, copy, modify, and distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #include <stddef.h>
  17. #include <stdint.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <limits.h>
  21. #include "ohash.h"
  22. struct _ohash_record {
  23. uint32_t hv;
  24. const char *p;
  25. };
  26. #define DELETED ((const char *)h)
  27. #define NONE (h->size)
  28. /* Don't bother changing the hash table if the change is small enough. */
  29. #define MINSIZE (1UL << 4)
  30. #define MINDELETED 4
  31. static void ohash_resize(struct ohash *);
  32. /* This handles the common case of variable length keys, where the
  33. * key is stored at the end of the record.
  34. */
  35. void *
  36. ohash_create_entry(struct ohash_info *i, const char *start, const char **end)
  37. {
  38. char *p;
  39. if (!*end)
  40. *end = start + strlen(start);
  41. p = (i->alloc)(i->key_offset + (*end - start) + 1, i->data);
  42. if (p) {
  43. memcpy(p+i->key_offset, start, *end-start);
  44. p[i->key_offset + (*end - start)] = '\0';
  45. }
  46. return (void *)p;
  47. }
  48. /* hash_delete only frees the hash structure. Use hash_first/hash_next
  49. * to free entries as well. */
  50. void
  51. ohash_delete(struct ohash *h)
  52. {
  53. (h->info.free)(h->t, h->info.data);
  54. #ifndef NDEBUG
  55. h->t = NULL;
  56. #endif
  57. }
  58. static void
  59. ohash_resize(struct ohash *h)
  60. {
  61. struct _ohash_record *n;
  62. size_t ns;
  63. unsigned int j;
  64. unsigned int i, incr;
  65. if (4 * h->deleted < h->total) {
  66. if (h->size >= (UINT_MAX >> 1U))
  67. ns = UINT_MAX;
  68. else
  69. ns = h->size << 1U;
  70. } else if (3 * h->deleted > 2 * h->total)
  71. ns = h->size >> 1U;
  72. else
  73. ns = h->size;
  74. if (ns < MINSIZE)
  75. ns = MINSIZE;
  76. #ifdef STATS_HASH
  77. STAT_HASH_EXPAND++;
  78. STAT_HASH_SIZE += ns - h->size;
  79. #endif
  80. n = (h->info.calloc)(ns, sizeof(struct _ohash_record), h->info.data);
  81. if (!n)
  82. return;
  83. for (j = 0; j < h->size; j++) {
  84. if (h->t[j].p != NULL && h->t[j].p != DELETED) {
  85. i = h->t[j].hv % ns;
  86. incr = ((h->t[j].hv % (ns - 2)) & ~1) + 1;
  87. while (n[i].p != NULL) {
  88. i += incr;
  89. if (i >= ns)
  90. i -= ns;
  91. }
  92. n[i].hv = h->t[j].hv;
  93. n[i].p = h->t[j].p;
  94. }
  95. }
  96. (h->info.free)(h->t, h->info.data);
  97. h->t = n;
  98. h->size = ns;
  99. h->total -= h->deleted;
  100. h->deleted = 0;
  101. }
  102. void *
  103. ohash_remove(struct ohash *h, unsigned int i)
  104. {
  105. void *result = (void *)h->t[i].p;
  106. if (result == NULL || result == DELETED)
  107. return NULL;
  108. #ifdef STATS_HASH
  109. STAT_HASH_ENTRIES--;
  110. #endif
  111. h->t[i].p = DELETED;
  112. h->deleted++;
  113. if (h->deleted >= MINDELETED && 4 * h->deleted > h->total)
  114. ohash_resize(h);
  115. return result;
  116. }
  117. void *
  118. ohash_find(struct ohash *h, unsigned int i)
  119. {
  120. if (h->t[i].p == DELETED)
  121. return NULL;
  122. else
  123. return (void *)h->t[i].p;
  124. }
  125. void *
  126. ohash_insert(struct ohash *h, unsigned int i, void *p)
  127. {
  128. #ifdef STATS_HASH
  129. STAT_HASH_ENTRIES++;
  130. #endif
  131. if (h->t[i].p == DELETED) {
  132. h->deleted--;
  133. h->t[i].p = p;
  134. } else {
  135. h->t[i].p = p;
  136. /* Arbitrary resize boundary. Tweak if not efficient enough. */
  137. if (++h->total * 4 > h->size * 3)
  138. ohash_resize(h);
  139. }
  140. return p;
  141. }
  142. unsigned int
  143. ohash_entries(struct ohash *h)
  144. {
  145. return h->total - h->deleted;
  146. }
  147. void *
  148. ohash_first(struct ohash *h, unsigned int *pos)
  149. {
  150. *pos = 0;
  151. return ohash_next(h, pos);
  152. }
  153. void *
  154. ohash_next(struct ohash *h, unsigned int *pos)
  155. {
  156. for (; *pos < h->size; (*pos)++)
  157. if (h->t[*pos].p != DELETED && h->t[*pos].p != NULL)
  158. return (void *)h->t[(*pos)++].p;
  159. return NULL;
  160. }
  161. void
  162. ohash_init(struct ohash *h, unsigned int size, struct ohash_info *info)
  163. {
  164. h->size = 1UL << size;
  165. if (h->size < MINSIZE)
  166. h->size = MINSIZE;
  167. #ifdef STATS_HASH
  168. STAT_HASH_CREATION++;
  169. STAT_HASH_SIZE += h->size;
  170. #endif
  171. /* Copy info so that caller may free it. */
  172. h->info.key_offset = info->key_offset;
  173. h->info.calloc = info->calloc;
  174. h->info.free = info->free;
  175. h->info.alloc = info->alloc;
  176. h->info.data = info->data;
  177. h->t = (h->info.calloc)(h->size, sizeof(struct _ohash_record),
  178. h->info.data);
  179. h->total = h->deleted = 0;
  180. }
  181. uint32_t
  182. ohash_interval(const char *s, const char **e)
  183. {
  184. uint32_t k;
  185. if (!*e)
  186. *e = s + strlen(s);
  187. if (s == *e)
  188. k = 0;
  189. else
  190. k = *s++;
  191. while (s != *e)
  192. k = ((k << 2) | (k >> 30)) ^ *s++;
  193. return k;
  194. }
  195. unsigned int
  196. ohash_lookup_interval(struct ohash *h, const char *start, const char *end,
  197. uint32_t hv)
  198. {
  199. unsigned int i, incr;
  200. unsigned int empty;
  201. #ifdef STATS_HASH
  202. STAT_HASH_LOOKUP++;
  203. #endif
  204. empty = NONE;
  205. i = hv % h->size;
  206. incr = ((hv % (h->size-2)) & ~1) + 1;
  207. while (h->t[i].p != NULL) {
  208. #ifdef STATS_HASH
  209. STAT_HASH_LENGTH++;
  210. #endif
  211. if (h->t[i].p == DELETED) {
  212. if (empty == NONE)
  213. empty = i;
  214. } else if (h->t[i].hv == hv &&
  215. strncmp(h->t[i].p+h->info.key_offset, start,
  216. end - start) == 0 &&
  217. (h->t[i].p+h->info.key_offset)[end-start] == '\0') {
  218. if (empty != NONE) {
  219. h->t[empty].hv = hv;
  220. h->t[empty].p = h->t[i].p;
  221. h->t[i].p = DELETED;
  222. return empty;
  223. } else {
  224. #ifdef STATS_HASH
  225. STAT_HASH_POSITIVE++;
  226. #endif
  227. return i;
  228. }
  229. }
  230. i += incr;
  231. if (i >= h->size)
  232. i -= h->size;
  233. }
  234. /* Found an empty position. */
  235. if (empty != NONE)
  236. i = empty;
  237. h->t[i].hv = hv;
  238. return i;
  239. }
  240. unsigned int
  241. ohash_lookup_memory(struct ohash *h, const char *k, size_t size, uint32_t hv)
  242. {
  243. unsigned int i, incr;
  244. unsigned int empty;
  245. #ifdef STATS_HASH
  246. STAT_HASH_LOOKUP++;
  247. #endif
  248. empty = NONE;
  249. i = hv % h->size;
  250. incr = ((hv % (h->size-2)) & ~1) + 1;
  251. while (h->t[i].p != NULL) {
  252. #ifdef STATS_HASH
  253. STAT_HASH_LENGTH++;
  254. #endif
  255. if (h->t[i].p == DELETED) {
  256. if (empty == NONE)
  257. empty = i;
  258. } else if (h->t[i].hv == hv &&
  259. memcmp(h->t[i].p+h->info.key_offset, k, size) == 0) {
  260. if (empty != NONE) {
  261. h->t[empty].hv = hv;
  262. h->t[empty].p = h->t[i].p;
  263. h->t[i].p = DELETED;
  264. return empty;
  265. } else {
  266. #ifdef STATS_HASH
  267. STAT_HASH_POSITIVE++;
  268. #endif
  269. } return i;
  270. }
  271. i += incr;
  272. if (i >= h->size)
  273. i -= h->size;
  274. }
  275. /* Found an empty position. */
  276. if (empty != NONE)
  277. i = empty;
  278. h->t[i].hv = hv;
  279. return i;
  280. }
  281. unsigned int
  282. ohash_qlookup(struct ohash *h, const char *s)
  283. {
  284. const char *e = NULL;
  285. return ohash_qlookupi(h, s, &e);
  286. }
  287. unsigned int
  288. ohash_qlookupi(struct ohash *h, const char *s, const char **e)
  289. {
  290. uint32_t hv;
  291. hv = ohash_interval(s, e);
  292. return ohash_lookup_interval(h, s, *e, hv);
  293. }