/src/utils/vector_hash_map.c

https://github.com/SRI-CSL/yices2 · C · 303 lines · 175 code · 54 blank · 74 comment · 35 complexity · 5bc7317a0cac2cd12c8c5a201dddd3c3 MD5 · raw file

  1. /*
  2. * This file is part of the Yices SMT Solver.
  3. * Copyright (C) 2018 SRI International.
  4. *
  5. * Yices is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * Yices is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with Yices. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /*
  19. * Table to map integer keys to an array of integers (vector)
  20. */
  21. #include <assert.h>
  22. #include <stdbool.h>
  23. #include "utils/memalloc.h"
  24. #include "utils/vector_hash_map.h"
  25. /*
  26. * Allocate a new vector of default size for key k
  27. */
  28. static vhmap_vector_t *new_vhmap_vector(int32_t k) {
  29. vhmap_vector_t *tmp;
  30. uint32_t n;
  31. n = DEF_VECTOR_HMAP_SIZE;
  32. tmp = (vhmap_vector_t *) safe_malloc(sizeof(vhmap_vector_t) + n * sizeof(int32_t));
  33. tmp->key = k;
  34. tmp->size = n;
  35. tmp->nelems = 0;
  36. return tmp;
  37. }
  38. /*
  39. * Add x to vector v: v must not be full
  40. */
  41. static void vhmap_vector_add(vhmap_vector_t *v, int32_t x) {
  42. uint32_t i;
  43. i = v->nelems;
  44. assert(i < v->size);
  45. v->data[i] = x;
  46. v->nelems = i+1;
  47. }
  48. /*
  49. * Check whether v is full
  50. */
  51. static inline bool vhmap_vector_is_full(vhmap_vector_t *v) {
  52. return v->nelems == v->size;
  53. }
  54. /*
  55. * Increase v's size by 50%
  56. */
  57. static vhmap_vector_t *extend_vhmap_vector(vhmap_vector_t *v) {
  58. vhmap_vector_t *tmp;
  59. uint32_t n;
  60. n = v->size;
  61. n += (n >> 1);
  62. if (n > MAX_VECTOR_HMAP_SIZE) {
  63. out_of_memory();
  64. }
  65. tmp = (vhmap_vector_t *) safe_realloc(v, sizeof(vhmap_vector_t) + n * sizeof(int32_t));
  66. tmp->size = n;
  67. return tmp;
  68. }
  69. /*
  70. * For debugging: check whether n is 0 or a power of 2
  71. */
  72. #ifndef NDEBUG
  73. static bool is_power_of_two(uint32_t n) {
  74. return (n & (n - 1)) == 0;
  75. }
  76. #endif
  77. /*
  78. * Initialization:
  79. * - n = initial size. It must be a power of 2 or 0.
  80. * - if n = 0, the default size is used.
  81. */
  82. void init_vector_hmap(vector_hmap_t *hmap, uint32_t n) {
  83. vhmap_vector_t **tmp;
  84. uint32_t i;
  85. if (n == 0) {
  86. n = DEF_VECTOR_HMAP_SIZE;
  87. }
  88. if (n > MAX_VECTOR_HMAP_SIZE) {
  89. out_of_memory();
  90. }
  91. assert(is_power_of_two(n));
  92. tmp = (vhmap_vector_t **) safe_malloc(n * sizeof(vhmap_vector_t *));
  93. for (i=0; i<n; i++) {
  94. tmp[i] = NULL;
  95. }
  96. hmap->data = tmp;
  97. hmap->size = n;
  98. hmap->nelems = 0;
  99. hmap->resize_threshold = (uint32_t) (n * VECTOR_HMAP_RESIZE_RATIO);
  100. }
  101. /*
  102. * Empty the table
  103. */
  104. void reset_vector_hmap(vector_hmap_t *hmap) {
  105. uint32_t i, n;
  106. n = hmap->size;
  107. for (i=0; i<n; i++) {
  108. if (hmap->data[i] != NULL) {
  109. safe_free(hmap->data[i]);
  110. hmap->data[i] = NULL;
  111. }
  112. }
  113. hmap->nelems = 0;
  114. }
  115. /*
  116. * Delete: free memory
  117. */
  118. void delete_vector_hmap(vector_hmap_t *hmap) {
  119. reset_vector_hmap(hmap);
  120. safe_free(hmap->data);
  121. hmap->data = NULL;
  122. }
  123. /*
  124. * Hash of a key (Jenkins hash)
  125. */
  126. static uint32_t hash_key(int32_t k) {
  127. uint32_t x;
  128. x = (uint32_t) k;
  129. x = (x + 0x7ed55d16) + (x<<12);
  130. x = (x ^ 0xc761c23c) ^ (x>>19);
  131. x = (x + 0x165667b1) + (x<<5);
  132. x = (x + 0xd3a2646c) ^ (x<<9);
  133. x = (x + 0xfd7046c5) + (x<<3);
  134. x = (x ^ 0xb55a4f09) ^ (x>>16);
  135. return x;
  136. }
  137. /*
  138. * Store v into a clean array a:
  139. * - mask = size of a - 1 where the size is a power of two
  140. * - the array must not be full
  141. */
  142. static void vector_hmap_clean_copy(vhmap_vector_t **a, vhmap_vector_t *v, uint32_t mask) {
  143. uint32_t i;
  144. i = hash_key(v->key) & mask;
  145. while (a[i] != NULL) {
  146. i ++;
  147. i &= mask;
  148. }
  149. a[i] = v;
  150. }
  151. /*
  152. * Make the table twice as large. Keep the content
  153. */
  154. static void extend_vector_hmap(vector_hmap_t *hmap) {
  155. vhmap_vector_t **tmp;
  156. vhmap_vector_t *v;
  157. uint32_t i, n, new_size, mask;
  158. n = hmap->size;
  159. new_size = n << 1;
  160. if (new_size > MAX_VECTOR_HMAP_SIZE) {
  161. out_of_memory();
  162. }
  163. tmp = (vhmap_vector_t **) safe_malloc(new_size * sizeof(vhmap_vector_t *));
  164. for (i=0; i<new_size; i++) {
  165. tmp[i] = NULL;
  166. }
  167. assert(is_power_of_two(new_size));
  168. mask = new_size - 1;
  169. for (i=0; i<n; i++) {
  170. v = hmap->data[i];
  171. if (v != NULL) {
  172. vector_hmap_clean_copy(tmp, v, mask);
  173. }
  174. }
  175. safe_free(hmap->data);
  176. hmap->data = tmp;
  177. hmap->size = new_size;
  178. hmap->resize_threshold = (uint32_t) (new_size * VECTOR_HMAP_RESIZE_RATIO);
  179. }
  180. /*
  181. * Get the vector of key k
  182. * - return NULL if there's no vector of key k
  183. */
  184. vhmap_vector_t *vector_hmap_find(const vector_hmap_t *hmap, int32_t k) {
  185. vhmap_vector_t *v;
  186. uint32_t i, mask;
  187. assert(is_power_of_two(hmap->size) && hmap->nelems < hmap->size);
  188. mask = hmap->size - 1;
  189. i = hash_key(k) & mask;
  190. for (;;) {
  191. v = hmap->data[i];
  192. if (v == NULL || v->key == k) break;
  193. i ++;
  194. i &= mask;
  195. }
  196. return v;
  197. }
  198. /*
  199. * Add a fresh vector v to the table:
  200. * - k = key
  201. * - x = element to store in v
  202. * - i = index in hmap->data to store v
  203. */
  204. static void vector_hmap_add_new(vector_hmap_t *hmap, int32_t k, int32_t x, uint32_t i) {
  205. vhmap_vector_t *v;
  206. assert(i < hmap->size && hmap->data[i] == NULL);
  207. v = new_vhmap_vector(k);
  208. vhmap_vector_add(v, x);
  209. hmap->data[i] = v;
  210. hmap->nelems ++;
  211. if (hmap->nelems >= hmap->resize_threshold) {
  212. extend_vector_hmap(hmap);
  213. }
  214. }
  215. /*
  216. * Add element x to an existing vector v at index i
  217. */
  218. static void vector_hmap_add_to_vector(vector_hmap_t *hmap, vhmap_vector_t *v, int32_t x, uint32_t i) {
  219. assert(i < hmap->size && hmap->data[i] == v);
  220. if (vhmap_vector_is_full(v)) {
  221. v = extend_vhmap_vector(v);
  222. hmap->data[i] = v;
  223. }
  224. vhmap_vector_add(v, x);
  225. }
  226. /*
  227. * Add element x to the vector of key k
  228. * - this creates a new vector if k is not already in the table.
  229. */
  230. void vector_hmap_add(vector_hmap_t *hmap, int32_t k, int32_t x) {
  231. vhmap_vector_t *v;
  232. uint32_t i, mask;
  233. assert(is_power_of_two(hmap->size) && hmap->nelems < hmap->size);
  234. mask = hmap->size - 1;
  235. i = hash_key(k) & mask;
  236. for (;;) {
  237. v = hmap->data[i];
  238. if (v == NULL) {
  239. vector_hmap_add_new(hmap, k, x, i);
  240. break;
  241. }
  242. if (v->key == k) {
  243. vector_hmap_add_to_vector(hmap, v, x, i);
  244. break;
  245. }
  246. i ++;
  247. i &= mask;
  248. }
  249. }