hash.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. /*****************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 2002, Daniel Stenberg, <[email protected]>, et al
  9. *
  10. * In order to be useful for every potential user, curl and libcurl are
  11. * dual-licensed under the MPL and the MIT/X-derivate licenses.
  12. *
  13. * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  14. * copies of the Software, and permit persons to whom the Software is
  15. * furnished to do so, under the terms of the MPL or the MIT/X-derivate
  16. * licenses. You may pick one of these licenses.
  17. *
  18. * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  19. * KIND, either express or implied.
  20. *
  21. * $Id$
  22. *****************************************************************************/
  23. #include "setup.h"
  24. #include <string.h>
  25. #include <stdlib.h>
  26. #include "hash.h"
  27. #include "llist.h"
  28. #ifdef MALLOCDEBUG
  29. /* this must be the last include file */
  30. #include "memdebug.h"
  31. #endif
  32. static unsigned long
  33. curl_hash_str(const char *key, unsigned int key_length)
  34. {
  35. register unsigned long h = 0;
  36. register unsigned long g;
  37. register char *p = (char *) key;
  38. register char *end = (char *) key + key_length;
  39. while (p < end) {
  40. h = (h << 4) + *p++;
  41. if ((g = (h & 0xF0000000))) {
  42. h = h ^ (g >> 24);
  43. h = h ^ g;
  44. }
  45. }
  46. return h;
  47. }
  48. static unsigned long
  49. curl_hash_num(unsigned long key)
  50. {
  51. key += ~(key << 15);
  52. key ^= (key >> 10);
  53. key += (key << 3);
  54. key ^= (key >> 6);
  55. key += (key << 11);
  56. key ^= (key >> 16);
  57. return key;
  58. }
  59. static void
  60. hash_element_dtor(void *u, void *ele)
  61. {
  62. curl_hash_element *e = (curl_hash_element *) ele;
  63. curl_hash *h = (curl_hash *) u;
  64. if (e->key.type == CURL_HASH_KEY_IS_STRING) {
  65. free(e->key.value.str.val);
  66. }
  67. h->dtor(e->ptr);
  68. free(e);
  69. e = NULL;
  70. }
  71. void
  72. curl_hash_init(curl_hash *h, int slots, curl_hash_dtor dtor)
  73. {
  74. int i;
  75. h->dtor = dtor;
  76. h->size = 0;
  77. h->slots = slots;
  78. h->table = (curl_llist **) malloc(slots * sizeof(curl_llist *));
  79. for (i = 0; i < h->slots; ++i) {
  80. h->table[i] = curl_llist_alloc((curl_llist_dtor) hash_element_dtor);
  81. }
  82. }
  83. curl_hash *
  84. curl_hash_alloc(int slots, curl_hash_dtor dtor)
  85. {
  86. curl_hash *h;
  87. h = (curl_hash *)malloc(sizeof(curl_hash));
  88. if(NULL == h)
  89. return NULL;
  90. curl_hash_init(h, slots, dtor);
  91. return h;
  92. }
  93. #define FIND_SLOT(__h, __s_key, __s_key_len, __n_key) \
  94. ((__s_key ? curl_hash_str(__s_key, __s_key_len) : curl_hash_num(__n_key)) % (__h)->slots)
  95. #define KEY_CREATE(__k, __s_key, __s_key_len, __n_key, __dup) \
  96. if (__s_key) { \
  97. if (__dup) { \
  98. (__k)->value.str.val = (char *) malloc(__s_key_len); \
  99. memcpy((__k)->value.str.val, __s_key, __s_key_len); \
  100. } else { \
  101. (__k)->value.str.val = __s_key; \
  102. } \
  103. (__k)->value.str.len = __s_key_len; \
  104. (__k)->type = CURL_HASH_KEY_IS_STRING; \
  105. } else { \
  106. (__k)->value.num = __n_key; \
  107. (__k)->type = CURL_HASH_KEY_IS_NUM; \
  108. }
  109. #define MIN(a, b) (a > b ? b : a)
  110. static int
  111. curl_hash_key_compare(curl_hash_key *key1, curl_hash_key *key2)
  112. {
  113. if (key1->type == CURL_HASH_KEY_IS_NUM) {
  114. if (key2->type == CURL_HASH_KEY_IS_STRING)
  115. return 0;
  116. if (key1->value.num == key2->value.num)
  117. return 1;
  118. } else {
  119. if (key2->type == CURL_HASH_KEY_IS_NUM)
  120. return 0;
  121. if (memcmp(key1->value.str.val, key2->value.str.val,
  122. MIN(key1->value.str.len, key2->value.str.len)) == 0)
  123. return 1;
  124. }
  125. return 0;
  126. }
  127. int
  128. curl_hash_add_or_update(curl_hash *h, char *str_key, unsigned int str_key_len,
  129. unsigned long num_key, const void *p)
  130. {
  131. curl_hash_element *e;
  132. curl_hash_key tmp;
  133. curl_llist *l;
  134. curl_llist_element *le;
  135. int slot;
  136. slot = FIND_SLOT(h, str_key, str_key_len, num_key);
  137. l = h->table[slot];
  138. KEY_CREATE(&tmp, str_key, str_key_len, num_key, 0);
  139. for (le = CURL_LLIST_HEAD(l); le != NULL; le = CURL_LLIST_NEXT(le)) {
  140. if (curl_hash_key_compare(&tmp, &((curl_hash_element *) CURL_LLIST_VALP(le))->key)) {
  141. curl_hash_element *to_update = CURL_LLIST_VALP(le);
  142. h->dtor(to_update->ptr);
  143. to_update->ptr = (void *) p;
  144. return 1;
  145. }
  146. }
  147. e = (curl_hash_element *) malloc(sizeof(curl_hash_element));
  148. KEY_CREATE(&e->key, str_key, str_key_len, num_key, 1);
  149. e->ptr = (void *) p;
  150. if (curl_llist_insert_next(l, CURL_LLIST_TAIL(l), e)) {
  151. ++h->size;
  152. return 1;
  153. } else {
  154. return 0;
  155. }
  156. }
  157. int
  158. curl_hash_extended_delete(curl_hash *h, char *str_key, unsigned int str_key_len,
  159. unsigned long num_key)
  160. {
  161. curl_llist *l;
  162. curl_llist_element *le;
  163. curl_hash_key tmp;
  164. int slot;
  165. slot = FIND_SLOT(h, str_key, str_key_len, num_key);
  166. l = h->table[slot];
  167. KEY_CREATE(&tmp, str_key, str_key_len, num_key, 0);
  168. for (le = CURL_LLIST_HEAD(l); le != NULL; le = CURL_LLIST_NEXT(le)) {
  169. if (curl_hash_key_compare(&tmp, &((curl_hash_element *) CURL_LLIST_VALP(le))->key)) {
  170. curl_llist_remove(l, le, (void *) h);
  171. --h->size;
  172. return 1;
  173. }
  174. }
  175. return 0;
  176. }
  177. int
  178. curl_hash_extended_find(curl_hash *h, char *str_key, unsigned int str_key_len,
  179. unsigned long num_key, void **p)
  180. {
  181. curl_llist *l;
  182. curl_llist_element *le;
  183. curl_hash_key tmp;
  184. int slot;
  185. slot = FIND_SLOT(h, str_key, str_key_len, num_key);
  186. l = h->table[slot];
  187. KEY_CREATE(&tmp, str_key, str_key_len, num_key, 0);
  188. for (le = CURL_LLIST_HEAD(l); le != NULL; le = CURL_LLIST_NEXT(le)) {
  189. if (curl_hash_key_compare(&tmp, &((curl_hash_element *) CURL_LLIST_VALP(le))->key)) {
  190. *p = ((curl_hash_element *) CURL_LLIST_VALP(le))->ptr;
  191. return 1;
  192. }
  193. }
  194. return 0;
  195. }
  196. void
  197. curl_hash_apply(curl_hash *h, void *user, void (*cb)(void *, curl_hash_element *))
  198. {
  199. curl_llist_element *le;
  200. int i;
  201. for (i = 0; i < h->slots; ++i) {
  202. for (le = CURL_LLIST_HEAD(h->table[i]); le != NULL; le = CURL_LLIST_NEXT(le)) {
  203. cb(user, (curl_hash_element *) CURL_LLIST_VALP(le));
  204. }
  205. }
  206. }
  207. void
  208. curl_hash_clean(curl_hash *h)
  209. {
  210. int i;
  211. for (i = 0; i < h->slots; ++i) {
  212. curl_llist_destroy(h->table[i], (void *) h);
  213. }
  214. free(h->table);
  215. h->table = NULL;
  216. }
  217. size_t
  218. curl_hash_count(curl_hash *h)
  219. {
  220. return h->size;
  221. }
  222. void
  223. curl_hash_destroy(curl_hash *h)
  224. {
  225. if (!h) {
  226. return;
  227. }
  228. curl_hash_clean(h);
  229. free(h);
  230. h = NULL;
  231. }
  232. /*
  233. * local variables:
  234. * eval: (load-file "../curl-mode.el")
  235. * end:
  236. * vim600: fdm=marker
  237. * vim: et sw=2 ts=2 sts=2 tw=78
  238. */