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 * SPARSE ARRAYS
21 */
22
23 #include "utils/memalloc.h"
24 #include "utils/sparse_arrays.h"
25
26
27 /*
28 * Initialize a:
29 * - n = minimal size requested
30 * - if n is 0, the default size is used
31 * - all blocks are marked as clean
32 */
init_sparse_array(sparse_array_t * a,uint32_t n)33 void init_sparse_array(sparse_array_t *a, uint32_t n) {
34 uint32_t nblocks;
35
36 if (n == 0) {
37 nblocks = DEF_SPARSE_ARRAY_NBLOCKS;
38 } else {
39 nblocks = (n + (BSIZE - 1)) >> BSIZE_NBITS;
40 assert(n <= nblocks * BSIZE);
41 if (nblocks > MAX_NBLOCKS) {
42 out_of_memory();
43 }
44 }
45
46 // adjust n to a multiple of the block size
47 n = nblocks * BSIZE;
48 a->data = (uint32_t *) safe_malloc(n * sizeof(uint32_t));
49 a->clean = allocate_bitvector0(nblocks); // all dirty
50 a->nblocks = nblocks;
51 a->nelems = 0;
52 }
53
54
55 /*
56 * Delete: free all memory
57 */
delete_sparse_array(sparse_array_t * a)58 void delete_sparse_array(sparse_array_t *a) {
59 safe_free(a->data);
60 delete_bitvector(a->clean);
61 a->data = NULL;
62 a->clean = NULL;
63 }
64
65
66 /*
67 * Reset: mark all blocks as dirty
68 */
reset_sparse_array(sparse_array_t * a)69 void reset_sparse_array(sparse_array_t *a) {
70 clear_bitvector(a->clean, a->nblocks);
71 a->nelems = 0;
72 }
73
74
75 /*
76 * Initialize block i in array a
77 */
clean_block(uint32_t * a,uint32_t i)78 static void clean_block(uint32_t *a, uint32_t i) {
79 uint32_t n;
80
81 n = BSIZE;
82 a += block_start(i);
83 do {
84 *a ++ = 0;
85 n --;
86 } while (n > 0);
87 }
88
89
90 /*
91 * Copy block i of a into b
92 */
copy_block(uint32_t * b,uint32_t * a,uint32_t i)93 static void copy_block(uint32_t *b, uint32_t *a, uint32_t i) {
94 uint32_t n;
95
96 n = BSIZE;
97 a += block_start(i);
98 b += block_start(i);
99 do {
100 * b++ = *a ++;
101 n --;
102 } while (n > 0);
103 }
104
105
106
107 /*
108 * Resize the array to at least nb blocks
109 * - nb must be more than a->nblocks
110 */
resize_sparse_array(sparse_array_t * a,uint32_t nb)111 static void resize_sparse_array(sparse_array_t *a, uint32_t nb) {
112 uint32_t i, nblocks, n;
113 uint32_t *tmp;
114
115 if (nb > MAX_NBLOCKS) {
116 out_of_memory();
117 }
118
119 n = a->nblocks;
120 nblocks = n;
121 nblocks += nblocks>>1; // try 50% larger
122 if (nb > nblocks) {
123 nblocks = nb;
124 } else if (nblocks > MAX_NBLOCKS) {
125 nblocks = MAX_NBLOCKS;
126 }
127
128 // n = current size, nblocks = new size
129 // we avoid realloc here (to save the cost of copying the full array)
130 tmp = (uint32_t *) safe_malloc(nblocks * (BSIZE * sizeof(uint32_t)));
131 a->clean = extend_bitvector0(a->clean, n, nblocks);
132
133 // copy all clean blocks from a->data to tmp
134 n = a->nblocks;
135 for (i=0; i<n; i++) {
136 if (tst_bit(a->clean, i)) {
137 copy_block(tmp, a->data, i);
138 }
139 }
140
141 safe_free(a->data);
142 a->data = tmp;
143 a->nblocks = nblocks;
144 }
145
146
147 /*
148 * Read the value mapped to i:
149 * - return 0 if i is in a dirty block or outside the array
150 */
sparse_array_read(sparse_array_t * a,uint32_t i)151 uint32_t sparse_array_read(sparse_array_t *a, uint32_t i) {
152 uint32_t k, y;
153
154 k = block_of_index(i);
155 y = 0;
156 if (k < a->nblocks && tst_bit(a->clean, k)) {
157 y = a->data[i];
158 }
159 return y;
160 }
161
162
163 /*
164 * Increment a[i]
165 */
sparse_array_incr(sparse_array_t * a,uint32_t i)166 void sparse_array_incr(sparse_array_t *a, uint32_t i) {
167 uint32_t k;
168
169 k = block_of_index(i);
170 if (k >= a->nblocks) {
171 resize_sparse_array(a, k+1);
172 }
173 if (tst_bit(a->clean, k) && a->data[i] < UINT32_MAX) {
174 if (a->data[i] == 0) {
175 a->nelems ++;
176 }
177 a->data[i] ++;
178 } else {
179 set_bit(a->clean, k);
180 clean_block(a->data, k);
181 a->data[i] = 1;
182 a->nelems ++;
183 }
184 }
185
186
187 /*
188 * Decrement a[i]: the current count must be positive
189 */
sparse_array_decr(sparse_array_t * a,uint32_t i)190 void sparse_array_decr(sparse_array_t *a, uint32_t i) {
191 #ifndef NDEBUG
192 uint32_t k;
193
194 k = block_of_index(i);
195 assert(k < a->nblocks && tst_bit(a->clean, k) && a->data[i] > 0);
196 #endif
197
198 a->data[i] --;
199 if (a->data[i] == 0) {
200 assert(a->nelems > 0);
201 a->nelems --;
202 }
203 }
204
205
206 /*
207 * Apply f(aux, i) to all i that have positive count in block k
208 */
iterate_in_block(uint32_t * a,uint32_t k,void * aux,sparse_array_iterator_t f)209 static void iterate_in_block(uint32_t *a, uint32_t k, void *aux, sparse_array_iterator_t f) {
210 uint32_t n, i;
211
212 n = block_start(k) + BSIZE;
213 for (i = block_start(k); i<n; i++) {
214 if (a[i] > 0) {
215 f(aux, i);
216 }
217 }
218 }
219
220
221 /*
222 * Go through all elements i with a positive ref counter and call f(aux, i)
223 */
sparse_array_iterate(sparse_array_t * a,void * aux,sparse_array_iterator_t f)224 void sparse_array_iterate(sparse_array_t *a, void *aux, sparse_array_iterator_t f) {
225 uint32_t i, n;
226
227 n = a->nblocks;
228 for (i=0; i<n; i++) {
229 if (tst_bit(a->clean, i)) {
230 iterate_in_block(a->data, i, aux, f);
231 }
232 }
233 }
234
235