2 * Copyright (C) 2014, United States Government, as represented by the
3 * Administrator of the National Aeronautics and Space Administration.
6 * The Java Pathfinder core (jpf-core) platform is licensed under the
7 * Apache License, Version 2.0 (the "License"); you may not use this file except
8 * in compliance with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0.
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 package gov.nasa.jpf.util;
20 import static java.lang.Integer.MIN_VALUE;
22 import java.util.Arrays;
25 * This has approximately the interface of IntVector but uses a hash table
26 * instead of an array. Also, does not require allocation with each add.
27 * Configurable default value.
29 public class SparseIntVector implements Cloneable {
30 private static final boolean DEBUG = false;
32 static final double MAX_LOAD_WIPE = 0.6;
33 static final double MAX_LOAD_REHASH = 0.4;
34 static final int DEFAULT_POW = 10;
35 static final int DEFAULT_VAL = 0;
38 * a simplistic snapshot implementation that stores set indices/values in order to save space
40 public static class Snapshot {
41 private final int length;
42 private final int pow, mask, nextWipe, nextRehash;
44 private final int[] positions;
45 private final int[] indices;
46 private final int[] values;
48 Snapshot (SparseIntVector v){
49 int len = v.idxTable.length;
54 nextWipe = v.nextWipe;
55 nextRehash = v.nextRehash;
58 positions = new int[size];
59 indices = new int[size];
60 values = new int[size];
62 int[] idxTable = v.idxTable;
63 int[] valTable = v.valTable;
65 for (int i=0; i<len; i++) {
66 if (idxTable[i] != MIN_VALUE) {
68 indices[j] = idxTable[i];
69 values[j] = valTable[i];
75 void restore (SparseIntVector v) {
76 int size = indices.length;
81 v.nextWipe = nextWipe;
82 v.nextRehash = nextRehash;
85 int[] idxTable = new int[len];
86 int[] valTable = new int[len];
88 Arrays.fill(idxTable, MIN_VALUE);
90 for (int i=0; i<size; i++) {
92 idxTable[j] = indices[i];
93 valTable[j] = values[i];
96 v.idxTable = idxTable;
97 v.valTable = valTable;
101 int[] idxTable; // MIN_VALUE => unoccupied
102 int[] valTable; // can be bound to null
113 * Creates a SimplePool that holds about 716 elements before first
116 public SparseIntVector() {
117 this(DEFAULT_POW,DEFAULT_VAL);
121 * Creates a SimplePool that holds about 0.7 * 2**pow elements before
124 public SparseIntVector(int pow, int defValue) {
128 mask = valTable.length - 1;
129 nextWipe = (int)(MAX_LOAD_WIPE * mask);
130 nextRehash = (int)(MAX_LOAD_REHASH * mask);
131 defaultValue = defValue;
136 @SuppressWarnings("unchecked")
137 protected void newTable() {
138 valTable = new int[1 << pow];
139 idxTable = new int[1 << pow];
140 if (defaultValue != 0) {
141 Arrays.fill(valTable, defaultValue);
143 Arrays.fill(idxTable, MIN_VALUE);
146 protected int mix(int x) {
149 y += (x >> 8) + (x << 3);
150 x ^= (y >> 5) + (y << 2);
155 // ********************* Public API ******************** //
157 public Snapshot getSnapshot() {
158 return new Snapshot(this);
161 public void restore (Snapshot snap) {
166 public SparseIntVector clone() {
168 SparseIntVector o = (SparseIntVector) super.clone();
169 o.idxTable = idxTable.clone();
170 o.valTable = valTable.clone();
174 } catch (CloneNotSupportedException cnsx) {
184 public void clear() {
185 Arrays.fill(valTable, defaultValue);
186 Arrays.fill(idxTable, MIN_VALUE);
190 public void clear(int idx) {
192 int pos = code & mask;
193 int delta = (code >> (pow - 1)) | 1; // must be odd!
197 int tidx = idxTable[pos];
198 if (tidx == MIN_VALUE) {
199 return; // nothing to clear
203 idxTable[pos] = MIN_VALUE;
204 valTable[pos] = defaultValue;
207 pos = (pos + delta) & mask;
208 assert (pos != oidx); // should never wrap around
212 @SuppressWarnings("unchecked")
213 public int get(int idx) {
215 int pos = code & mask;
216 int delta = (code >> (pow - 1)) | 1; // must be odd!
220 int tidx = idxTable[pos];
221 if (tidx == MIN_VALUE) {
225 return valTable[pos];
227 pos = (pos + delta) & mask;
228 assert (pos != oidx); // should never wrap around
235 for (int i = 0; i < idxTable.length; i++) {
236 if (idxTable[i] != MIN_VALUE /*&& valTable[i] != defaultValue*/) {
243 public void set(int idx, int val) {
245 int pos = code & mask;
246 int delta = (code >> (pow - 1)) | 1; // must be odd!
250 int tidx = idxTable[pos];
251 if (tidx == MIN_VALUE) {
255 valTable[pos] = val; // update
256 return; // and we're done
258 pos = (pos + delta) & mask;
259 assert (pos != oidx); // should never wrap around
261 // idx not in table; add it
263 if ((count+1) >= nextWipe) { // too full
264 if (count >= nextRehash) {
269 // determine if size needs to be increased or just wipe null blocks
270 int oldCount = count;
272 for (int i = 0; i < idxTable.length; i++) {
273 //if (idxTable[i] != MIN_VALUE && valTable[i] != defaultValue) {
274 if (idxTable[i] != MIN_VALUE) {
278 if (count >= nextRehash) {
279 pow++; // needs to be increased in size
281 System.out.println("Rehash to capacity: 2**" + pow);
285 System.out.println("Rehash reclaiming this many nulls: " + (oldCount - count));
290 int[] oldValTable = valTable;
291 int[] oldIdxTable = idxTable;
293 mask = idxTable.length - 1;
294 nextWipe = (int)(MAX_LOAD_WIPE * mask);
295 nextRehash = (int)(MAX_LOAD_REHASH * mask);
297 int oldLen = oldIdxTable.length;
298 for (int i = 0; i < oldLen; i++) {
299 int tidx = oldIdxTable[i];
300 if (tidx == MIN_VALUE) continue;
301 int o = oldValTable[i];
302 //if (o == defaultValue) continue;
306 delta = (code >> (pow - 1)) | 1; // must be odd!
307 while (idxTable[pos] != MIN_VALUE) { // we know enough slots exist
308 pos = (pos + delta) & mask;
310 idxTable[pos] = tidx;
313 // done with rehash; now get idx to empty slot
316 delta = (code >> (pow - 1)) | 1; // must be odd!
317 while (idxTable[pos] != MIN_VALUE) { // we know enough slots exist
318 pos = (pos + delta) & mask;
322 // pos already pointing to empty slot
332 public void setRange (int fromIndex, int toIndex, int val) {
333 for (int i=fromIndex; i<toIndex; i++) {
338 // ************************** Test main ************************ //
340 public static void main(String[] args) {
341 SparseIntVector vect = new SparseIntVector(3, MIN_VALUE);
344 for (int i = -4200; i < 4200; i += 10) {
348 // check for added & non-added
349 for (int i = -4200; i < 4200; i += 10) {
352 throw new IllegalStateException();
355 for (int i = -4205; i < 4200; i += 10) {
357 if (v != MIN_VALUE) {
358 throw new IllegalStateException();
363 for (int i = -4201; i < 4200; i += 10) {
368 for (int i = -4200; i < 4200; i += 10) {
371 throw new IllegalStateException();
374 for (int i = -4201; i < 4200; i += 10) {
377 throw new IllegalStateException();
382 for (int i = -4200; i < 4200; i += 10) {
383 vect.set(i,MIN_VALUE);
386 // check for added & non-added
387 for (int i = -4201; i < 4200; i += 10) {
390 throw new IllegalStateException();
393 for (int i = -4200; i < 4200; i += 10) {
395 if (v != MIN_VALUE) {
396 throw new IllegalStateException();
401 for (int i = -4203; i < 4200; i += 10) {
404 for (int i = -4204; i < 4200; i += 10) {