uint-hash.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
  9. *
  10. * This software is licensed as described in the file COPYING, which
  11. * you should have received as part of this distribution. The terms
  12. * are also available at https://curl.se/docs/copyright.html.
  13. *
  14. * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  15. * copies of the Software, and permit persons to whom the Software is
  16. * furnished to do so, under the terms of the COPYING file.
  17. *
  18. * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  19. * KIND, either express or implied.
  20. *
  21. * SPDX-License-Identifier: curl
  22. *
  23. ***************************************************************************/
  24. #include "curl_setup.h"
  25. #include <curl/curl.h>
  26. #include "uint-hash.h"
  27. #include "curl_memory.h"
  28. /* The last #include file should be: */
  29. #include "memdebug.h"
  30. /* random patterns for API verification */
  31. #ifdef DEBUGBUILD
  32. #define CURL_UINTHASHINIT 0x7117e779
  33. #endif
  34. static unsigned int uint_hash_hash(unsigned int id, unsigned int slots)
  35. {
  36. return (id % slots);
  37. }
  38. struct uint_hash_entry {
  39. struct uint_hash_entry *next;
  40. void *value;
  41. unsigned int id;
  42. };
  43. void Curl_uint_hash_init(struct uint_hash *h,
  44. unsigned int slots,
  45. Curl_uint_hash_dtor *dtor)
  46. {
  47. DEBUGASSERT(h);
  48. DEBUGASSERT(slots);
  49. h->table = NULL;
  50. h->dtor = dtor;
  51. h->size = 0;
  52. h->slots = slots;
  53. #ifdef DEBUGBUILD
  54. h->init = CURL_UINTHASHINIT;
  55. #endif
  56. }
  57. static struct uint_hash_entry *uint_hash_mk_entry(unsigned int id, void *value)
  58. {
  59. struct uint_hash_entry *e;
  60. /* allocate the struct for the hash entry */
  61. e = malloc(sizeof(*e));
  62. if(e) {
  63. e->id = id;
  64. e->next = NULL;
  65. e->value = value;
  66. }
  67. return e;
  68. }
  69. static void uint_hash_entry_clear(struct uint_hash *h,
  70. struct uint_hash_entry *e)
  71. {
  72. DEBUGASSERT(h);
  73. DEBUGASSERT(e);
  74. if(e->value) {
  75. if(h->dtor)
  76. h->dtor(e->id, e->value);
  77. e->value = NULL;
  78. }
  79. }
  80. static void uint_hash_entry_destroy(struct uint_hash *h,
  81. struct uint_hash_entry *e)
  82. {
  83. uint_hash_entry_clear(h, e);
  84. free(e);
  85. }
  86. static void uint_hash_entry_unlink(struct uint_hash *h,
  87. struct uint_hash_entry **he_anchor,
  88. struct uint_hash_entry *he)
  89. {
  90. *he_anchor = he->next;
  91. --h->size;
  92. }
  93. static void uint_hash_elem_link(struct uint_hash *h,
  94. struct uint_hash_entry **he_anchor,
  95. struct uint_hash_entry *he)
  96. {
  97. he->next = *he_anchor;
  98. *he_anchor = he;
  99. ++h->size;
  100. }
  101. #define CURL_UINT_HASH_SLOT(h,id) h->table[uint_hash_hash(id, h->slots)]
  102. #define CURL_UINT_HASH_SLOT_ADDR(h,id) &CURL_UINT_HASH_SLOT(h,id)
  103. bool Curl_uint_hash_set(struct uint_hash *h, unsigned int id, void *value)
  104. {
  105. struct uint_hash_entry *he, **slot;
  106. DEBUGASSERT(h);
  107. DEBUGASSERT(h->slots);
  108. DEBUGASSERT(h->init == CURL_UINTHASHINIT);
  109. if(!h->table) {
  110. h->table = calloc(h->slots, sizeof(*he));
  111. if(!h->table)
  112. return FALSE; /* OOM */
  113. }
  114. slot = CURL_UINT_HASH_SLOT_ADDR(h, id);
  115. for(he = *slot; he; he = he->next) {
  116. if(he->id == id) {
  117. /* existing key entry, overwrite by clearing old pointer */
  118. uint_hash_entry_clear(h, he);
  119. he->value = value;
  120. return TRUE;
  121. }
  122. }
  123. he = uint_hash_mk_entry(id, value);
  124. if(!he)
  125. return FALSE; /* OOM */
  126. uint_hash_elem_link(h, slot, he);
  127. return TRUE;
  128. }
  129. bool Curl_uint_hash_remove(struct uint_hash *h, unsigned int id)
  130. {
  131. DEBUGASSERT(h);
  132. DEBUGASSERT(h->slots);
  133. DEBUGASSERT(h->init == CURL_UINTHASHINIT);
  134. if(h->table) {
  135. struct uint_hash_entry *he, **he_anchor;
  136. he_anchor = CURL_UINT_HASH_SLOT_ADDR(h, id);
  137. while(*he_anchor) {
  138. he = *he_anchor;
  139. if(id == he->id) {
  140. uint_hash_entry_unlink(h, he_anchor, he);
  141. uint_hash_entry_destroy(h, he);
  142. return TRUE;
  143. }
  144. he_anchor = &he->next;
  145. }
  146. }
  147. return FALSE;
  148. }
  149. void *Curl_uint_hash_get(struct uint_hash *h, unsigned int id)
  150. {
  151. DEBUGASSERT(h);
  152. DEBUGASSERT(h->init == CURL_UINTHASHINIT);
  153. if(h->table) {
  154. struct uint_hash_entry *he;
  155. DEBUGASSERT(h->slots);
  156. he = CURL_UINT_HASH_SLOT(h, id);
  157. while(he) {
  158. if(id == he->id) {
  159. return he->value;
  160. }
  161. he = he->next;
  162. }
  163. }
  164. return NULL;
  165. }
  166. static void uint_hash_clear(struct uint_hash *h)
  167. {
  168. if(h && h->table) {
  169. struct uint_hash_entry *he, **he_anchor;
  170. size_t i;
  171. DEBUGASSERT(h->init == CURL_UINTHASHINIT);
  172. for(i = 0; i < h->slots; ++i) {
  173. he_anchor = &h->table[i];
  174. while(*he_anchor) {
  175. he = *he_anchor;
  176. uint_hash_entry_unlink(h, he_anchor, he);
  177. uint_hash_entry_destroy(h, he);
  178. }
  179. }
  180. }
  181. }
  182. #ifdef UNITTESTS
  183. UNITTEST void Curl_uint_hash_clear(struct uint_hash *h)
  184. {
  185. uint_hash_clear(h);
  186. }
  187. #endif
  188. void Curl_uint_hash_destroy(struct uint_hash *h)
  189. {
  190. DEBUGASSERT(h->init == CURL_UINTHASHINIT);
  191. if(h->table) {
  192. uint_hash_clear(h);
  193. Curl_safefree(h->table);
  194. }
  195. DEBUGASSERT(h->size == 0);
  196. h->slots = 0;
  197. }
  198. unsigned int Curl_uint_hash_count(struct uint_hash *h)
  199. {
  200. DEBUGASSERT(h->init == CURL_UINTHASHINIT);
  201. return h->size;
  202. }
  203. void Curl_uint_hash_visit(struct uint_hash *h,
  204. Curl_uint_hash_visit_cb *cb,
  205. void *user_data)
  206. {
  207. if(h && h->table && cb) {
  208. struct uint_hash_entry *he;
  209. size_t i;
  210. DEBUGASSERT(h->init == CURL_UINTHASHINIT);
  211. for(i = 0; i < h->slots; ++i) {
  212. for(he = h->table[i]; he; he = he->next) {
  213. if(!cb(he->id, he->value, user_data))
  214. return;
  215. }
  216. }
  217. }
  218. }