1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.math4.legacy.linear;
19
20 import org.apache.commons.math4.core.jdkmath.JdkMath;
21
22 import java.io.IOException;
23 import java.io.ObjectInputStream;
24 import java.io.Serializable;
25 import java.util.ConcurrentModificationException;
26 import java.util.NoSuchElementException;
27
28
29
30
31
32
33
34
35
36
37
38 class OpenIntToDoubleHashMap implements Serializable {
39
40
41 protected static final byte FREE = 0;
42
43
44 protected static final byte FULL = 1;
45
46
47 protected static final byte REMOVED = 2;
48
49
50 private static final long serialVersionUID = -3646337053166149105L;
51
52
53 private static final float LOAD_FACTOR = 0.5f;
54
55
56
57
58 private static final int DEFAULT_EXPECTED_SIZE = 16;
59
60
61
62
63 private static final int RESIZE_MULTIPLIER = 2;
64
65
66 private static final int PERTURB_SHIFT = 5;
67
68
69 private int[] keys;
70
71
72 private double[] values;
73
74
75 private byte[] states;
76
77
78 private final double missingEntries;
79
80
81 private int size;
82
83
84 private int mask;
85
86
87 private transient int count;
88
89
90
91
92 OpenIntToDoubleHashMap() {
93 this(DEFAULT_EXPECTED_SIZE, Double.NaN);
94 }
95
96
97
98
99
100 OpenIntToDoubleHashMap(final double missingEntries) {
101 this(DEFAULT_EXPECTED_SIZE, missingEntries);
102 }
103
104
105
106
107
108 OpenIntToDoubleHashMap(final int expectedSize) {
109 this(expectedSize, Double.NaN);
110 }
111
112
113
114
115
116
117 OpenIntToDoubleHashMap(final int expectedSize,
118 final double missingEntries) {
119 final int capacity = computeCapacity(expectedSize);
120 keys = new int[capacity];
121 values = new double[capacity];
122 states = new byte[capacity];
123 this.missingEntries = missingEntries;
124 mask = capacity - 1;
125 }
126
127
128
129
130
131 OpenIntToDoubleHashMap(final OpenIntToDoubleHashMap source) {
132 final int length = source.keys.length;
133 keys = new int[length];
134 System.arraycopy(source.keys, 0, keys, 0, length);
135 values = new double[length];
136 System.arraycopy(source.values, 0, values, 0, length);
137 states = new byte[length];
138 System.arraycopy(source.states, 0, states, 0, length);
139 missingEntries = source.missingEntries;
140 size = source.size;
141 mask = source.mask;
142 count = source.count;
143 }
144
145
146
147
148
149
150 private static int computeCapacity(final int expectedSize) {
151 if (expectedSize == 0) {
152 return 1;
153 }
154 final int capacity = (int) JdkMath.ceil(expectedSize / LOAD_FACTOR);
155 final int powerOfTwo = Integer.highestOneBit(capacity);
156 if (powerOfTwo == capacity) {
157 return capacity;
158 }
159 return nextPowerOfTwo(capacity);
160 }
161
162
163
164
165
166
167 private static int nextPowerOfTwo(final int i) {
168 return Integer.highestOneBit(i) << 1;
169 }
170
171
172
173
174
175
176 public double get(final int key) {
177
178 final int hash = hashOf(key);
179 int index = hash & mask;
180 if (containsKey(key, index)) {
181 return values[index];
182 }
183
184 if (states[index] == FREE) {
185 return missingEntries;
186 }
187
188 int j = index;
189 for (int perturb = perturb(hash); states[index] != FREE; perturb >>= PERTURB_SHIFT) {
190 j = probe(perturb, j);
191 index = j & mask;
192 if (containsKey(key, index)) {
193 return values[index];
194 }
195 }
196
197 return missingEntries;
198 }
199
200
201
202
203
204
205 public boolean containsKey(final int key) {
206
207 final int hash = hashOf(key);
208 int index = hash & mask;
209 if (containsKey(key, index)) {
210 return true;
211 }
212
213 if (states[index] == FREE) {
214 return false;
215 }
216
217 int j = index;
218 for (int perturb = perturb(hash); states[index] != FREE; perturb >>= PERTURB_SHIFT) {
219 j = probe(perturb, j);
220 index = j & mask;
221 if (containsKey(key, index)) {
222 return true;
223 }
224 }
225
226 return false;
227 }
228
229
230
231
232
233
234
235
236 public Iterator iterator() {
237 return new Iterator();
238 }
239
240
241
242
243
244
245 private static int perturb(final int hash) {
246 return hash & 0x7fffffff;
247 }
248
249
250
251
252
253
254 private int findInsertionIndex(final int key) {
255 return findInsertionIndex(keys, states, key, mask);
256 }
257
258
259
260
261
262
263
264
265
266 private static int findInsertionIndex(final int[] keys, final byte[] states,
267 final int key, final int mask) {
268 final int hash = hashOf(key);
269 int index = hash & mask;
270 if (states[index] == FREE) {
271 return index;
272 } else if (states[index] == FULL && keys[index] == key) {
273 return changeIndexSign(index);
274 }
275
276 int perturb = perturb(hash);
277 int j = index;
278 if (states[index] == FULL) {
279 while (true) {
280 j = probe(perturb, j);
281 index = j & mask;
282 perturb >>= PERTURB_SHIFT;
283
284 if (states[index] != FULL || keys[index] == key) {
285 break;
286 }
287 }
288 }
289
290 if (states[index] == FREE) {
291 return index;
292 } else if (states[index] == FULL) {
293
294
295 return changeIndexSign(index);
296 }
297
298 final int firstRemoved = index;
299 while (true) {
300 j = probe(perturb, j);
301 index = j & mask;
302
303 if (states[index] == FREE) {
304 return firstRemoved;
305 } else if (states[index] == FULL && keys[index] == key) {
306 return changeIndexSign(index);
307 }
308
309 perturb >>= PERTURB_SHIFT;
310 }
311 }
312
313
314
315
316
317
318
319 private static int probe(final int perturb, final int j) {
320 return (j << 2) + j + perturb + 1;
321 }
322
323
324
325
326
327
328 private static int changeIndexSign(final int index) {
329 return -index - 1;
330 }
331
332
333
334
335
336 public int size() {
337 return size;
338 }
339
340
341
342
343
344
345
346 public double remove(final int key) {
347
348 final int hash = hashOf(key);
349 int index = hash & mask;
350 if (containsKey(key, index)) {
351 return doRemove(index);
352 }
353
354 if (states[index] == FREE) {
355 return missingEntries;
356 }
357
358 int j = index;
359 for (int perturb = perturb(hash); states[index] != FREE; perturb >>= PERTURB_SHIFT) {
360 j = probe(perturb, j);
361 index = j & mask;
362 if (containsKey(key, index)) {
363 return doRemove(index);
364 }
365 }
366
367 return missingEntries;
368 }
369
370
371
372
373
374
375
376
377 private boolean containsKey(final int key, final int index) {
378 return (key != 0 || states[index] == FULL) && keys[index] == key;
379 }
380
381
382
383
384
385
386 private double doRemove(int index) {
387 keys[index] = 0;
388 states[index] = REMOVED;
389 final double previous = values[index];
390 values[index] = missingEntries;
391 --size;
392 ++count;
393 return previous;
394 }
395
396
397
398
399
400
401
402 public double put(final int key, final double value) {
403 int index = findInsertionIndex(key);
404 double previous = missingEntries;
405 boolean newMapping = true;
406 if (index < 0) {
407 index = changeIndexSign(index);
408 previous = values[index];
409 newMapping = false;
410 }
411 keys[index] = key;
412 states[index] = FULL;
413 values[index] = value;
414 if (newMapping) {
415 ++size;
416 if (shouldGrowTable()) {
417 growTable();
418 }
419 ++count;
420 }
421 return previous;
422 }
423
424
425
426
427 private void growTable() {
428
429 final int oldLength = states.length;
430 final int[] oldKeys = keys;
431 final double[] oldValues = values;
432 final byte[] oldStates = states;
433
434 final int newLength = RESIZE_MULTIPLIER * oldLength;
435 final int[] newKeys = new int[newLength];
436 final double[] newValues = new double[newLength];
437 final byte[] newStates = new byte[newLength];
438 final int newMask = newLength - 1;
439 for (int i = 0; i < oldLength; ++i) {
440 if (oldStates[i] == FULL) {
441 final int key = oldKeys[i];
442 final int index = findInsertionIndex(newKeys, newStates, key, newMask);
443 newKeys[index] = key;
444 newValues[index] = oldValues[i];
445 newStates[index] = FULL;
446 }
447 }
448
449 mask = newMask;
450 keys = newKeys;
451 values = newValues;
452 states = newStates;
453 }
454
455
456
457
458
459 private boolean shouldGrowTable() {
460 return size > (mask + 1) * LOAD_FACTOR;
461 }
462
463
464
465
466
467
468 private static int hashOf(final int key) {
469 final int h = key ^ ((key >>> 20) ^ (key >>> 12));
470 return h ^ (h >>> 7) ^ (h >>> 4);
471 }
472
473
474
475 public final class Iterator {
476
477
478 private final int referenceCount;
479
480
481 private int current;
482
483
484 private int next;
485
486
487
488
489 private Iterator() {
490
491
492 referenceCount = count;
493
494
495 next = -1;
496 try {
497 advance();
498 } catch (NoSuchElementException nsee) {
499
500 }
501 }
502
503
504
505
506
507 public boolean hasNext() {
508 return next >= 0;
509 }
510
511
512
513
514
515
516
517 public int key()
518 throws ConcurrentModificationException, NoSuchElementException {
519 if (referenceCount != count) {
520 throw new ConcurrentModificationException();
521 }
522 if (current < 0) {
523 throw new NoSuchElementException();
524 }
525 return keys[current];
526 }
527
528
529
530
531
532
533
534 public double value()
535 throws ConcurrentModificationException, NoSuchElementException {
536 if (referenceCount != count) {
537 throw new ConcurrentModificationException();
538 }
539 if (current < 0) {
540 throw new NoSuchElementException();
541 }
542 return values[current];
543 }
544
545
546
547
548
549
550 public void advance()
551 throws ConcurrentModificationException, NoSuchElementException {
552
553 if (referenceCount != count) {
554 throw new ConcurrentModificationException();
555 }
556
557
558 current = next;
559
560
561 try {
562 do {
563 ++next;
564 } while (states[next] != FULL);
565 } catch (ArrayIndexOutOfBoundsException e) {
566 next = -2;
567 if (current < 0) {
568 throw new NoSuchElementException();
569 }
570 }
571 }
572 }
573
574
575
576
577
578
579
580
581 private void readObject(final ObjectInputStream stream)
582 throws IOException, ClassNotFoundException {
583 stream.defaultReadObject();
584 count = 0;
585 }
586
587 }