hashtable.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. /*
  2. * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
  3. *
  4. * This library is free software; you can redistribute it and/or modify
  5. * it under the terms of the MIT license. See LICENSE for details.
  6. */
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <jansson_config.h> /* for JSON_INLINE */
  10. #include "jansson_private.h" /* for container_of() */
  11. #include "hashtable.h"
  12. typedef struct hashtable_list list_t;
  13. typedef struct hashtable_pair pair_t;
  14. typedef struct hashtable_bucket bucket_t;
  15. #define list_to_pair(list_) container_of(list_, pair_t, list)
  16. /* From http://www.cse.yorku.ca/~oz/hash.html */
  17. static size_t hash_str(const void *ptr)
  18. {
  19. const char *str = (const char *)ptr;
  20. size_t hash = 5381;
  21. size_t c;
  22. while((c = (size_t)*str))
  23. {
  24. hash = ((hash << 5) + hash) + c;
  25. str++;
  26. }
  27. return hash;
  28. }
  29. static JSON_INLINE void list_init(list_t *list)
  30. {
  31. list->next = list;
  32. list->prev = list;
  33. }
  34. static JSON_INLINE void list_insert(list_t *list, list_t *node)
  35. {
  36. node->next = list;
  37. node->prev = list->prev;
  38. list->prev->next = node;
  39. list->prev = node;
  40. }
  41. static JSON_INLINE void list_remove(list_t *list)
  42. {
  43. list->prev->next = list->next;
  44. list->next->prev = list->prev;
  45. }
  46. static JSON_INLINE int bucket_is_empty(hashtable_t *hashtable, bucket_t *bucket)
  47. {
  48. return bucket->first == &hashtable->list && bucket->first == bucket->last;
  49. }
  50. static void insert_to_bucket(hashtable_t *hashtable, bucket_t *bucket,
  51. list_t *list)
  52. {
  53. if(bucket_is_empty(hashtable, bucket))
  54. {
  55. list_insert(&hashtable->list, list);
  56. bucket->first = bucket->last = list;
  57. }
  58. else
  59. {
  60. list_insert(bucket->first, list);
  61. bucket->first = list;
  62. }
  63. }
  64. static size_t primes[] = {
  65. 5, 13, 23, 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593,
  66. 49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469,
  67. 12582917, 25165843, 50331653, 100663319, 201326611, 402653189,
  68. 805306457, 1610612741
  69. };
  70. static JSON_INLINE size_t num_buckets(hashtable_t *hashtable)
  71. {
  72. return primes[hashtable->num_buckets];
  73. }
  74. static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket,
  75. const char *key, size_t hash)
  76. {
  77. list_t *list;
  78. pair_t *pair;
  79. if(bucket_is_empty(hashtable, bucket))
  80. return NULL;
  81. list = bucket->first;
  82. while(1)
  83. {
  84. pair = list_to_pair(list);
  85. if(pair->hash == hash && strcmp(pair->key, key) == 0)
  86. return pair;
  87. if(list == bucket->last)
  88. break;
  89. list = list->next;
  90. }
  91. return NULL;
  92. }
  93. /* returns 0 on success, -1 if key was not found */
  94. static int hashtable_do_del(hashtable_t *hashtable,
  95. const char *key, size_t hash)
  96. {
  97. pair_t *pair;
  98. bucket_t *bucket;
  99. size_t index;
  100. index = hash % num_buckets(hashtable);
  101. bucket = &hashtable->buckets[index];
  102. pair = hashtable_find_pair(hashtable, bucket, key, hash);
  103. if(!pair)
  104. return -1;
  105. if(&pair->list == bucket->first && &pair->list == bucket->last)
  106. bucket->first = bucket->last = &hashtable->list;
  107. else if(&pair->list == bucket->first)
  108. bucket->first = pair->list.next;
  109. else if(&pair->list == bucket->last)
  110. bucket->last = pair->list.prev;
  111. list_remove(&pair->list);
  112. json_decref(pair->value);
  113. jsonp_free(pair);
  114. hashtable->size--;
  115. return 0;
  116. }
  117. static void hashtable_do_clear(hashtable_t *hashtable)
  118. {
  119. list_t *list, *next;
  120. pair_t *pair;
  121. for(list = hashtable->list.next; list != &hashtable->list; list = next)
  122. {
  123. next = list->next;
  124. pair = list_to_pair(list);
  125. json_decref(pair->value);
  126. jsonp_free(pair);
  127. }
  128. }
  129. static int hashtable_do_rehash(hashtable_t *hashtable)
  130. {
  131. list_t *list, *next;
  132. pair_t *pair;
  133. size_t i, index, new_size;
  134. jsonp_free(hashtable->buckets);
  135. hashtable->num_buckets++;
  136. new_size = num_buckets(hashtable);
  137. hashtable->buckets = jsonp_malloc(new_size * sizeof(bucket_t));
  138. if(!hashtable->buckets)
  139. return -1;
  140. for(i = 0; i < num_buckets(hashtable); i++)
  141. {
  142. hashtable->buckets[i].first = hashtable->buckets[i].last =
  143. &hashtable->list;
  144. }
  145. list = hashtable->list.next;
  146. list_init(&hashtable->list);
  147. for(; list != &hashtable->list; list = next) {
  148. next = list->next;
  149. pair = list_to_pair(list);
  150. index = pair->hash % new_size;
  151. insert_to_bucket(hashtable, &hashtable->buckets[index], &pair->list);
  152. }
  153. return 0;
  154. }
  155. int hashtable_init(hashtable_t *hashtable)
  156. {
  157. size_t i;
  158. hashtable->size = 0;
  159. hashtable->num_buckets = 0; /* index to primes[] */
  160. hashtable->buckets = jsonp_malloc(num_buckets(hashtable) * sizeof(bucket_t));
  161. if(!hashtable->buckets)
  162. return -1;
  163. list_init(&hashtable->list);
  164. for(i = 0; i < num_buckets(hashtable); i++)
  165. {
  166. hashtable->buckets[i].first = hashtable->buckets[i].last =
  167. &hashtable->list;
  168. }
  169. return 0;
  170. }
  171. void hashtable_close(hashtable_t *hashtable)
  172. {
  173. hashtable_do_clear(hashtable);
  174. jsonp_free(hashtable->buckets);
  175. }
  176. int hashtable_set(hashtable_t *hashtable,
  177. const char *key, size_t serial,
  178. json_t *value)
  179. {
  180. pair_t *pair;
  181. bucket_t *bucket;
  182. size_t hash, index;
  183. /* rehash if the load ratio exceeds 1 */
  184. if(hashtable->size >= num_buckets(hashtable))
  185. if(hashtable_do_rehash(hashtable))
  186. return -1;
  187. hash = hash_str(key);
  188. index = hash % num_buckets(hashtable);
  189. bucket = &hashtable->buckets[index];
  190. pair = hashtable_find_pair(hashtable, bucket, key, hash);
  191. if(pair)
  192. {
  193. json_decref(pair->value);
  194. pair->value = value;
  195. }
  196. else
  197. {
  198. /* offsetof(...) returns the size of pair_t without the last,
  199. flexible member. This way, the correct amount is
  200. allocated. */
  201. pair = jsonp_malloc(offsetof(pair_t, key) + strlen(key) + 1);
  202. if(!pair)
  203. return -1;
  204. pair->hash = hash;
  205. pair->serial = serial;
  206. strcpy(pair->key, key);
  207. pair->value = value;
  208. list_init(&pair->list);
  209. insert_to_bucket(hashtable, bucket, &pair->list);
  210. hashtable->size++;
  211. }
  212. return 0;
  213. }
  214. void *hashtable_get(hashtable_t *hashtable, const char *key)
  215. {
  216. pair_t *pair;
  217. size_t hash;
  218. bucket_t *bucket;
  219. hash = hash_str(key);
  220. bucket = &hashtable->buckets[hash % num_buckets(hashtable)];
  221. pair = hashtable_find_pair(hashtable, bucket, key, hash);
  222. if(!pair)
  223. return NULL;
  224. return pair->value;
  225. }
  226. int hashtable_del(hashtable_t *hashtable, const char *key)
  227. {
  228. size_t hash = hash_str(key);
  229. return hashtable_do_del(hashtable, key, hash);
  230. }
  231. void hashtable_clear(hashtable_t *hashtable)
  232. {
  233. size_t i;
  234. hashtable_do_clear(hashtable);
  235. for(i = 0; i < num_buckets(hashtable); i++)
  236. {
  237. hashtable->buckets[i].first = hashtable->buckets[i].last =
  238. &hashtable->list;
  239. }
  240. list_init(&hashtable->list);
  241. hashtable->size = 0;
  242. }
  243. void *hashtable_iter(hashtable_t *hashtable)
  244. {
  245. return hashtable_iter_next(hashtable, &hashtable->list);
  246. }
  247. void *hashtable_iter_at(hashtable_t *hashtable, const char *key)
  248. {
  249. pair_t *pair;
  250. size_t hash;
  251. bucket_t *bucket;
  252. hash = hash_str(key);
  253. bucket = &hashtable->buckets[hash % num_buckets(hashtable)];
  254. pair = hashtable_find_pair(hashtable, bucket, key, hash);
  255. if(!pair)
  256. return NULL;
  257. return &pair->list;
  258. }
  259. void *hashtable_iter_next(hashtable_t *hashtable, void *iter)
  260. {
  261. list_t *list = (list_t *)iter;
  262. if(list->next == &hashtable->list)
  263. return NULL;
  264. return list->next;
  265. }
  266. void *hashtable_iter_key(void *iter)
  267. {
  268. pair_t *pair = list_to_pair((list_t *)iter);
  269. return pair->key;
  270. }
  271. size_t hashtable_iter_serial(void *iter)
  272. {
  273. pair_t *pair = list_to_pair((list_t *)iter);
  274. return pair->serial;
  275. }
  276. void *hashtable_iter_value(void *iter)
  277. {
  278. pair_t *pair = list_to_pair((list_t *)iter);
  279. return pair->value;
  280. }
  281. void hashtable_iter_set(void *iter, json_t *value)
  282. {
  283. pair_t *pair = list_to_pair((list_t *)iter);
  284. json_decref(pair->value);
  285. pair->value = value;
  286. }