1 /*
2 * This file is part of the Yices SMT Solver.
3 * Copyright (C) 2017 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 /*
20 * SUPPORT FOR HASH CONSING OF INTEGER ARRAYS
21 */
22
23 #include <assert.h>
24 #include <stdbool.h>
25
26 #include "utils/hash_functions.h"
27 #include "utils/int_array_hsets.h"
28 #include "utils/memalloc.h"
29
30
31
32 /*
33 * ARRAY DESCRIPTORS
34 */
35
36 /*
37 * Hash code of array a[0 ...n-1]
38 */
hash_array(int32_t * a,uint32_t n)39 static inline uint32_t hash_array(int32_t *a, uint32_t n) {
40 return jenkins_hash_intarray(a, n);
41 }
42
43
44 /*
45 * Create descriptor for a[0 ... n-1]
46 * - don't set the hash code
47 */
make_harray(int32_t * a,uint32_t n)48 static harray_t *make_harray(int32_t *a, uint32_t n) {
49 harray_t *tmp;
50 uint32_t i;
51
52 if (n >= MAX_HARRAY_SIZE) {
53 out_of_memory();
54 }
55
56 tmp = (harray_t *) safe_malloc(sizeof(harray_t) + n * sizeof(int32_t));
57 tmp->nelems = n;
58 for (i=0; i<n; i++) {
59 tmp->data[i] = a[i];
60 }
61
62 return tmp;
63 }
64
65
66 /*
67 * Check whether v == a[0...n-1]
68 */
eq_harray(harray_t * p,int32_t * a,uint32_t n)69 static bool eq_harray(harray_t *p, int32_t *a, uint32_t n) {
70 uint32_t i;
71
72 if (p->nelems != n) {
73 return false;
74 }
75
76 for (i=0; i<n; i++) {
77 if (p->data[i] != a[i]) {
78 return false;
79 }
80 }
81
82 return true;
83 }
84
85
86
87 /*
88 * HASH TABLE
89 */
90
91 /*
92 * For debugging: check whether n is a power of two
93 */
94 #ifndef NDEBUG
is_power_of_two(uint32_t n)95 static bool is_power_of_two(uint32_t n) {
96 return (n & (n - 1)) == 0;
97 }
98 #endif
99
100
101 /*
102 * Initialize set
103 * - n = initial size
104 * - n must be a power of 2. If n = 0, the default size is used.
105 */
init_int_array_hset(int_array_hset_t * set,uint32_t n)106 void init_int_array_hset(int_array_hset_t *set, uint32_t n) {
107 uint32_t i;
108 harray_t **tmp;
109
110 if (n == 0) {
111 n = DEF_INT_ARRAY_HSET_SIZE;
112 }
113
114 if (n >= MAX_INT_ARRAY_HSET_SIZE) {
115 out_of_memory();
116 }
117
118 assert(is_power_of_two(n));
119
120 tmp = (harray_t **) safe_malloc(n * sizeof(harray_t *));
121 for (i=0; i<n; i++) {
122 tmp[i] = NULL;
123 }
124
125 set->data = tmp;
126 set->size = n;
127 set->nelems = 0;
128 set->ndeleted = 0;
129
130 set->resize_threshold = (uint32_t) (n * INT_ARRAY_HSET_RESIZE_RATIO);
131 set->cleanup_threshold = (uint32_t) (n * INT_ARRAY_HSET_CLEANUP_RATIO);
132 }
133
134
135 /*
136 * Check whether p is a non-deleted/non-null pointer
137 */
live_harray(harray_t * p)138 static inline bool live_harray(harray_t *p) {
139 return p != NULL && p != DELETED_HARRAY;
140 }
141
142
143 /*
144 * Delete the set
145 */
delete_int_array_hset(int_array_hset_t * set)146 void delete_int_array_hset(int_array_hset_t *set) {
147 harray_t *p;
148 uint32_t i, n;
149
150 n = set->size;
151 for (i=0; i<n; i++) {
152 p = set->data[i];
153 if (live_harray(p)) safe_free(p);
154 }
155 safe_free(set->data);
156 set->data = NULL;
157 }
158
159
160 /*
161 * Empty the set
162 */
reset_int_array_hset(int_array_hset_t * set)163 void reset_int_array_hset(int_array_hset_t *set) {
164 harray_t *p;
165 uint32_t i, n;
166
167 n = set->size;
168 for (i=0; i<n; i++) {
169 p = set->data[i];
170 if (live_harray(p)) safe_free(p);
171 set->data[i] = NULL;
172 }
173 set->nelems = 0;
174 set->ndeleted = 0;
175 }
176
177
178 /*
179 * Store p in a clean data array
180 * - mask = size of data - 1 (the size must be a power of 2)
181 * - p->hash must be the correct hash code for p
182 * - data must not contain DELETED_HARRAY marks and must have room for p
183 */
int_array_hset_clean_copy(harray_t ** data,harray_t * p,uint32_t mask)184 static void int_array_hset_clean_copy(harray_t **data, harray_t *p, uint32_t mask) {
185 uint32_t i;
186
187 i = p->hash & mask;
188 while (data[i] != NULL) {
189 i ++;
190 i &= mask;
191 }
192 data[i] = p;
193 }
194
195
196 /*
197 * Remove all deletion markers from set
198 */
int_array_hset_cleanup(int_array_hset_t * set)199 static void int_array_hset_cleanup(int_array_hset_t *set) {
200 harray_t **tmp, *p;
201 uint32_t i, n, mask;
202
203 n = set->size;
204 tmp = (harray_t **) safe_malloc(n * sizeof(harray_t *));
205 for (i=0; i<n; i++) {
206 tmp[i] = NULL;
207 }
208
209 mask = n - 1;
210 for (i=0; i<n; i++) {
211 p = set->data[i];
212 if (live_harray(p)) {
213 int_array_hset_clean_copy(tmp, p, mask);
214 }
215 }
216
217 safe_free(set->data);
218 set->data = tmp;
219 set->ndeleted = 0;
220 }
221
222
223 /*
224 * Remove all deletion markers and make the set twice larger
225 */
int_array_hset_extend(int_array_hset_t * set)226 static void int_array_hset_extend(int_array_hset_t *set) {
227 harray_t **tmp, *p;
228 uint32_t i, n, mask, new_size;
229
230 n = set->size;
231 new_size = n << 1;
232 if (new_size >= MAX_INT_ARRAY_HSET_SIZE) {
233 out_of_memory();
234 }
235
236 tmp = (harray_t **) safe_malloc(new_size * sizeof(harray_t *));
237 for (i=0; i<new_size; i++) {
238 tmp[i] = NULL;
239 }
240
241 mask = new_size - 1;
242 for (i=0; i<n; i++) {
243 p = set->data[i];
244 if (live_harray(p)) {
245 int_array_hset_clean_copy(tmp, p, mask);
246 }
247 }
248
249 safe_free(set->data);
250 set->data = tmp;
251 set->size = new_size;
252 set->ndeleted = 0;
253
254 set->resize_threshold = (uint32_t) (new_size * INT_ARRAY_HSET_RESIZE_RATIO);
255 set->cleanup_threshold = (uint32_t) (new_size * INT_ARRAY_HSET_CLEANUP_RATIO);
256 }
257
258
259 /*
260 * Search for array a[0 ... n-1]
261 */
int_array_hset_find(int_array_hset_t * set,uint32_t n,int32_t * a)262 harray_t *int_array_hset_find(int_array_hset_t *set, uint32_t n, int32_t *a) {
263 harray_t *p;
264 uint32_t i, h, mask;
265
266 assert(set->nelems + set->ndeleted < set->size);
267
268 mask = set->size - 1;
269 h = hash_array(a, n);
270 i = h & mask;
271 for (;;) {
272 p = set->data[i];
273 if (p == NULL || (p != DELETED_HARRAY && p->hash == h && eq_harray(p, a, n))) {
274 return p;
275 }
276 i ++;
277 i &= mask;
278 }
279 }
280
281
282 /*
283 * Find or create descriptor for a[0...n-1]
284 */
int_array_hset_get(int_array_hset_t * set,uint32_t n,int32_t * a)285 harray_t *int_array_hset_get(int_array_hset_t *set, uint32_t n, int32_t *a) {
286 harray_t *p;
287 uint32_t i, j, h, mask;
288
289 assert(set->nelems + set->ndeleted < set->size);
290
291 mask = set->size - 1;
292 h = hash_array(a, n);
293 i = h & mask;
294 for (;;) {
295 p = set->data[i];
296 if (p == NULL) goto add;
297 if (p == DELETED_HARRAY) break;
298 if (p->hash == h && eq_harray(p, a, n)) goto found;
299 i ++;
300 i &= mask;
301 }
302
303 // set->data[i] = where new set can be added
304 j = i;
305 for (;;) {
306 j ++;
307 j &= mask;
308 p = set->data[j];
309 if (p == NULL) {
310 set->ndeleted --;
311 goto add;
312 }
313 if (p != DELETED_HARRAY && p->hash == h && eq_harray(p, a, n)) goto found;
314 }
315
316 add:
317 p = make_harray(a, n);
318 p->hash = h;
319 set->data[i] = p;
320 set->nelems ++;
321 if (set->nelems + set->ndeleted > set->resize_threshold) {
322 int_array_hset_extend(set);
323 }
324
325 found:
326 return p;
327 }
328
329
330 /*
331 * Remove a from the set
332 * - no change if a is not in the set
333 */
int_array_hset_remove(int_array_hset_t * set,uint32_t n,int32_t * a)334 void int_array_hset_remove(int_array_hset_t *set, uint32_t n, int32_t *a) {
335 harray_t *p;
336 uint32_t i, h, mask;
337
338 assert(set->nelems + set->ndeleted < set->size);
339
340 mask = set->size - 1;
341 h = hash_array(a, n);
342 i = h & mask;
343 for (;;) {
344 p = set->data[i];
345 if (p == NULL) return;
346 if (p != DELETED_HARRAY && p->hash == h && eq_harray(p, a, n)) break;
347 i ++;
348 i &= mask;
349 }
350
351 // remove p
352 safe_free(p);
353 set->data[i] = DELETED_HARRAY;
354 set->nelems --;
355 set->ndeleted ++;
356
357 if (set->ndeleted > set->cleanup_threshold) {
358 int_array_hset_cleanup(set);
359 }
360 }
361
362
363 /*
364 * Remove all arrays that satisfy f
365 * - for every array a in the table, call f(aux, a)
366 * - if that returns true, then a is deleted
367 * - f must not have side effects
368 */
int_array_hset_remove_arrays(int_array_hset_t * set,void * aux,int_array_hset_filter_t f)369 void int_array_hset_remove_arrays(int_array_hset_t *set, void *aux, int_array_hset_filter_t f) {
370 harray_t *p;
371 uint32_t i, n, k;
372
373 n = set->size;
374 k = 0;
375 for (i=0; i<n; i++) {
376 p = set->data[i];
377 if (live_harray(p) && f(aux, p)) {
378 // remove p
379 safe_free(p);
380 set->data[i] = DELETED_HARRAY;
381 k ++;
382 }
383 }
384
385 // k = number of deletions
386 assert(k <= set->nelems);
387 set->nelems -= k;
388 set->ndeleted += k;
389 if (set->ndeleted > set->cleanup_threshold) {
390 int_array_hset_cleanup(set);
391 }
392 }
393
394