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 * HASH TABLES OF NON-NEGATIVE INTEGERS FOR HASH CONSING.
21 */
22
23 #include <stdint.h>
24 #include <assert.h>
25
26 #include "utils/int_hash_tables.h"
27 #include "utils/memalloc.h"
28
29
30 /*
31 * For debugging: check whether n is a power of two
32 */
33 #ifndef NDEBUG
is_power_of_two(uint32_t n)34 static bool is_power_of_two(uint32_t n) {
35 return (n & (n - 1)) == 0;
36 }
37 #endif
38
39
40
41 /*
42 * Initialize table: n = initial size (must be a power of 2)
43 * If n = 0 set size = default value
44 */
init_int_htbl(int_htbl_t * table,uint32_t n)45 void init_int_htbl(int_htbl_t *table, uint32_t n) {
46 uint32_t i;
47 int_hrec_t *tmp;
48
49 if (n == 0) {
50 n = INT_HTBL_DEFAULT_SIZE;
51 }
52
53 if (n >= MAX_HTBL_SIZE) {
54 out_of_memory(); // abort
55 }
56
57 assert(is_power_of_two(n));
58
59 tmp = (int_hrec_t *) safe_malloc(n * sizeof(int_hrec_t));
60 for (i=0; i<n; i++) {
61 tmp[i].value = NULL_VALUE;
62 }
63
64 table->records = tmp;
65 table->size = n;
66 table->nelems = 0;
67 table->ndeleted = 0;
68
69 table->resize_threshold = (uint32_t)(n * RESIZE_RATIO);
70 table->cleanup_threshold = (uint32_t)(n * CLEANUP_RATIO);
71 }
72
73
74 /*
75 * Delete table
76 */
delete_int_htbl(int_htbl_t * table)77 void delete_int_htbl(int_htbl_t *table) {
78 safe_free(table->records);
79 table->records = NULL;
80 }
81
82
83 /*
84 * Reset table: remove all elements
85 */
reset_int_htbl(int_htbl_t * table)86 void reset_int_htbl(int_htbl_t *table) {
87 uint32_t i, n;
88
89 n = table->size;
90 for (i=0; i<n; i++) {
91 table->records[i].value = NULL_VALUE;
92 }
93
94 table->nelems = 0;
95 table->ndeleted = 0;
96 }
97
98
99
100
101 /*
102 * Copy record <k, v> into a clean record array t.
103 * t contains no DELETED_VALUE and must have at least one empty slot
104 * <k, v> must not be present in t.
105 * mask must be 2^n - 1 and (size of t) = 2^n
106 */
int_htbl_copy_record(int_hrec_t * t,uint32_t k,int32_t v,uint32_t mask)107 static void int_htbl_copy_record(int_hrec_t *t, uint32_t k, int32_t v, uint32_t mask) {
108 uint32_t j;
109 int_hrec_t *r;
110
111 j = k & mask;
112 for (;;) {
113 r = t + j;
114 if (r->value == NULL_VALUE) {
115 r->value = v;
116 r->key = k;
117 return;
118 }
119 j ++;
120 j &= mask;
121 }
122 }
123
124
125 /*
126 * Remove deleted elements
127 */
int_htbl_cleanup(int_htbl_t * table)128 static void int_htbl_cleanup(int_htbl_t *table) {
129 int_hrec_t *tmp;
130 uint32_t j, n;
131 uint32_t mask;
132 int32_t v;
133
134 n = table->size;
135 tmp = (int_hrec_t *) safe_malloc(n * sizeof(int_hrec_t));
136 for (j=0; j<n; j++) {
137 tmp[j].value = NULL_VALUE;
138 }
139
140 mask = n - 1;
141 for (j=0; j<n; j++) {
142 v = table->records[j].value;
143 if (v >= 0) {
144 int_htbl_copy_record(tmp, table->records[j].key, v, mask);
145 }
146 }
147
148 safe_free(table->records);
149 table->records = tmp;
150 table->ndeleted = 0;
151 }
152
153
154
155 /*
156 * Remove deleted elements and make table twice as large
157 */
int_htbl_extend(int_htbl_t * table)158 static void int_htbl_extend(int_htbl_t *table) {
159 int_hrec_t *tmp;
160 uint32_t j, n, n2;
161 uint32_t mask;
162 int32_t v;
163
164 n = table->size;
165 n2 = n<<1;
166 if (n2 == 0 || n2 >= MAX_HTBL_SIZE) {
167 // overflow or too large
168 out_of_memory();
169 }
170
171 tmp = (int_hrec_t *) safe_malloc(n2 * sizeof(int_hrec_t));
172 for (j=0; j<n2; j++) {
173 tmp[j].value = NULL_VALUE;
174 }
175 mask = n2 - 1;
176
177 for (j=0; j<n; j++) {
178 v = table->records[j].value;
179 if (v >= 0) {
180 int_htbl_copy_record(tmp, table->records[j].key, v, mask);
181 }
182 }
183
184 safe_free(table->records);
185 table->records = tmp;
186 table->ndeleted = 0;
187 table->size = n2;
188
189 // keep same fill/cleanup ratios
190 table->resize_threshold = (uint32_t) (n2 * RESIZE_RATIO);
191 table->cleanup_threshold = (uint32_t) (n2 * CLEANUP_RATIO);
192 }
193
194
195 /*
196 * Erase <k, v>
197 */
int_htbl_erase_record(int_htbl_t * table,uint32_t k,int32_t v)198 void int_htbl_erase_record(int_htbl_t *table, uint32_t k, int32_t v) {
199 uint32_t mask, j;
200 int_hrec_t *r;
201
202 // table must not be full, otherwise the function loops
203 assert(table->size > table->nelems + table->ndeleted);
204
205 mask = table->size - 1;
206 j = k & mask;
207 for (;;) {
208 r = table->records + j;
209 if (r->value == v) break;
210 if (r->value == NULL_VALUE) return;
211 j ++;
212 j &= mask;
213 }
214
215 assert(r->key == k && r->value == v);
216 table->nelems --;
217 table->ndeleted ++;
218 r->value = DELETED_VALUE;
219 if (table->ndeleted > table->cleanup_threshold) {
220 int_htbl_cleanup(table);
221 }
222 }
223
224
225 /*
226 * Add record <k, v> to the table
227 * - the record must not be present in the table
228 */
int_htbl_add_record(int_htbl_t * table,uint32_t k,int32_t v)229 void int_htbl_add_record(int_htbl_t *table, uint32_t k, int32_t v) {
230 uint32_t mask, j;
231 int_hrec_t *r;
232
233 assert(table->size > table->nelems + table->ndeleted);
234
235 mask = table->size - 1;
236 j = k & mask;
237 for (;;) {
238 r = table->records + j;
239 if (r->value == NULL_VALUE) goto add;
240 if (r->value == DELETED_VALUE) break;
241 assert(r->value != v);
242 j ++;
243 j &= mask;
244 }
245
246 assert(table->ndeleted > 0);
247 table->ndeleted --;
248
249 add:
250 // add <k, v> into record r
251 table->nelems ++;
252 r->key = k;
253 r->value = v;
254
255 if (table->nelems + table->ndeleted > table->resize_threshold) {
256 int_htbl_extend(table);
257 }
258 }
259
260
261 /*
262 * Find index of object equal to o or return -1 if no such index is in the hash table.
263 */
int_htbl_find_obj(int_htbl_t * table,int_hobj_t * o)264 int32_t int_htbl_find_obj(int_htbl_t *table, int_hobj_t *o) {
265 uint32_t mask, j, k;
266 int32_t v;
267 int_hrec_t *r;
268
269 // the table must not be full, otherwise, the function loops
270 assert(table->size > table->nelems + table->ndeleted);
271
272 mask = table->size - 1;
273 k = o->hash(o);
274 j = k & mask;
275 for (;;) {
276 r = table->records + j;
277 v = r->value;
278 if ((v >= 0 && r->key == k && o->eq(o, v)) || v == NULL_VALUE) {
279 return v;
280 }
281 j ++;
282 j &= mask;
283 }
284 }
285
286
287 /*
288 * Allocate an index for o (by calling build) then store this index and k in
289 * record r. k must be the hash code of o.
290 */
int_htbl_store_new_obj(int_htbl_t * table,int_hrec_t * r,uint32_t k,int_hobj_t * o)291 static int32_t int_htbl_store_new_obj(int_htbl_t *table, int_hrec_t *r, uint32_t k, int_hobj_t *o) {
292 int32_t v;
293
294 v = o->build(o);
295
296 // error in build is signaled by returning v < 0
297 if (v >= 0) {
298 table->nelems ++;
299 r->key = k;
300 r->value = v;
301
302 if (table->nelems + table->ndeleted > table->resize_threshold) {
303 int_htbl_extend(table);
304 }
305 }
306
307 return v;
308 }
309
310
311 /*
312 * Get index of an object equal to o if such an index is in the table.
313 * Otherwise, allocate an index by calling o->build(o) then store that index
314 * in the table.
315 */
int_htbl_get_obj(int_htbl_t * table,int_hobj_t * o)316 int32_t int_htbl_get_obj(int_htbl_t *table, int_hobj_t *o) {
317 uint32_t mask, j, k;
318 int32_t v;
319 int_hrec_t *r;
320 int_hrec_t *aux;
321
322 assert(table->size > table->nelems + table->ndeleted);
323
324 mask = table->size - 1;
325 k = o->hash(o);
326 j = k & mask;
327
328 for (;;) {
329 r = table->records + j;
330 v = r->value;
331 if (v == NULL_VALUE) return int_htbl_store_new_obj(table, r, k, o);
332 if (v == DELETED_VALUE) break;
333 if (r->key == k && o->eq(o, v)) return v;
334 j ++;
335 j &= mask;
336 }
337
338 // aux will be used to store the new index if needed
339 aux = r;
340 for (;;) {
341 j ++;
342 j &= mask;
343 r = table->records + j;
344 v = r->value;
345 if (v == NULL_VALUE) {
346 table->ndeleted --;
347 return int_htbl_store_new_obj(table, aux, k, o);
348 }
349 if (v >= 0 && r->key == k && o->eq(o, v)) return v;
350 }
351 }
352
353
354