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