1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.collections4.map;
18
19 import java.util.AbstractCollection;
20 import java.util.AbstractSet;
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.Iterator;
24 import java.util.Map;
25 import java.util.NoSuchElementException;
26 import java.util.Objects;
27 import java.util.Set;
28
29 import org.apache.commons.collections4.KeyValue;
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109 public final class StaticBucketMap<K, V> extends AbstractIterableMap<K, V> {
110
111 class BaseIterator {
112 private final ArrayList<Map.Entry<K, V>> current = new ArrayList<>();
113 private int bucket;
114 private Map.Entry<K, V> last;
115
116 public boolean hasNext() {
117 if (!current.isEmpty()) {
118 return true;
119 }
120 while (bucket < buckets.length) {
121 synchronized (locks[bucket]) {
122 Node<K, V> n = buckets[bucket];
123 while (n != null) {
124 current.add(n);
125 n = n.next;
126 }
127 bucket++;
128 if (!current.isEmpty()) {
129 return true;
130 }
131 }
132 }
133 return false;
134 }
135
136 protected Map.Entry<K, V> nextEntry() {
137 if (!hasNext()) {
138 throw new NoSuchElementException();
139 }
140 last = current.remove(current.size() - 1);
141 return last;
142 }
143
144 public void remove() {
145 if (last == null) {
146 throw new IllegalStateException();
147 }
148 StaticBucketMap.this.remove(last.getKey());
149 last = null;
150 }
151 }
152
153 private final class EntryIterator extends BaseIterator implements Iterator<Map.Entry<K, V>> {
154
155 @Override
156 public Map.Entry<K, V> next() {
157 return nextEntry();
158 }
159
160 }
161
162 private final class EntrySet extends AbstractSet<Map.Entry<K, V>> {
163
164 @Override
165 public void clear() {
166 StaticBucketMap.this.clear();
167 }
168
169 @Override
170 public boolean contains(final Object obj) {
171 final Map.Entry<?, ?> entry = (Map.Entry<?, ?>) obj;
172 final int hash = getHash(entry.getKey());
173 synchronized (locks[hash]) {
174 for (Node<K, V> n = buckets[hash]; n != null; n = n.next) {
175 if (n.equals(entry)) {
176 return true;
177 }
178 }
179 }
180 return false;
181 }
182
183 @Override
184 public Iterator<Map.Entry<K, V>> iterator() {
185 return new EntryIterator();
186 }
187
188 @Override
189 public boolean remove(final Object obj) {
190 if (!(obj instanceof Map.Entry<?, ?>)) {
191 return false;
192 }
193 final Map.Entry<?, ?> entry = (Map.Entry<?, ?>) obj;
194 final int hash = getHash(entry.getKey());
195 synchronized (locks[hash]) {
196 for (Node<K, V> n = buckets[hash]; n != null; n = n.next) {
197 if (n.equals(entry)) {
198 StaticBucketMap.this.remove(n.getKey());
199 return true;
200 }
201 }
202 }
203 return false;
204 }
205
206 @Override
207 public int size() {
208 return StaticBucketMap.this.size();
209 }
210
211 }
212
213 private final class KeyIterator extends BaseIterator implements Iterator<K> {
214
215 @Override
216 public K next() {
217 return nextEntry().getKey();
218 }
219
220 }
221
222 private final class KeySet extends AbstractSet<K> {
223
224 @Override
225 public void clear() {
226 StaticBucketMap.this.clear();
227 }
228
229 @Override
230 public boolean contains(final Object obj) {
231 return StaticBucketMap.this.containsKey(obj);
232 }
233
234 @Override
235 public Iterator<K> iterator() {
236 return new KeyIterator();
237 }
238
239 @Override
240 public boolean remove(final Object obj) {
241 final int hash = getHash(obj);
242 synchronized (locks[hash]) {
243 for (Node<K, V> n = buckets[hash]; n != null; n = n.next) {
244 final Object k = n.getKey();
245 if (Objects.equals(k, obj)) {
246 StaticBucketMap.this.remove(k);
247 return true;
248 }
249 }
250 }
251 return false;
252 }
253
254 @Override
255 public int size() {
256 return StaticBucketMap.this.size();
257 }
258
259 }
260
261
262
263
264 private static final class Lock {
265 public int size;
266 }
267
268
269
270
271 private static final class Node<K, V> implements Map.Entry<K, V>, KeyValue<K, V> {
272 protected K key;
273 protected V value;
274 protected Node<K, V> next;
275
276 @Override
277 public boolean equals(final Object obj) {
278 if (obj == this) {
279 return true;
280 }
281 if (!(obj instanceof Map.Entry<?, ?>)) {
282 return false;
283 }
284
285 final Map.Entry<?, ?> e2 = (Map.Entry<?, ?>) obj;
286 return Objects.equals(key, e2.getKey()) &&
287 Objects.equals(value, e2.getValue());
288 }
289
290 @Override
291 public K getKey() {
292 return key;
293 }
294
295 @Override
296 public V getValue() {
297 return value;
298 }
299
300 @Override
301 public int hashCode() {
302 return (key == null ? 0 : key.hashCode()) ^
303 (value == null ? 0 : value.hashCode());
304 }
305
306 @Override
307 public V setValue(final V value) {
308 final V old = this.value;
309 this.value = value;
310 return old;
311 }
312 }
313
314 private final class ValueIterator extends BaseIterator implements Iterator<V> {
315
316 @Override
317 public V next() {
318 return nextEntry().getValue();
319 }
320
321 }
322
323 private final class Values extends AbstractCollection<V> {
324
325 @Override
326 public void clear() {
327 StaticBucketMap.this.clear();
328 }
329
330 @Override
331 public Iterator<V> iterator() {
332 return new ValueIterator();
333 }
334
335 @Override
336 public int size() {
337 return StaticBucketMap.this.size();
338 }
339
340 }
341
342
343 private static final int DEFAULT_BUCKETS = 255;
344
345
346 private final Node<K, V>[] buckets;
347
348
349 private final Lock[] locks;
350
351
352
353
354 public StaticBucketMap() {
355 this(DEFAULT_BUCKETS);
356 }
357
358
359
360
361
362
363
364
365
366
367
368 @SuppressWarnings("unchecked")
369 public StaticBucketMap(final int numBuckets) {
370 int size = Math.max(17, numBuckets);
371
372
373 if (size % 2 == 0) {
374 size--;
375 }
376
377 buckets = new Node[size];
378 locks = new Lock[size];
379
380 for (int i = 0; i < size; i++) {
381 locks[i] = new Lock();
382 }
383 }
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416 public void atomic(final Runnable runnable) {
417 atomic(Objects.requireNonNull(runnable, "runnable"), 0);
418 }
419
420 private void atomic(final Runnable r, final int bucket) {
421 if (bucket >= buckets.length) {
422 r.run();
423 return;
424 }
425 synchronized (locks[bucket]) {
426 atomic(r, bucket + 1);
427 }
428 }
429
430
431
432
433 @Override
434 public void clear() {
435 for (int i = 0; i < buckets.length; i++) {
436 final Lock lock = locks[i];
437 synchronized (lock) {
438 buckets[i] = null;
439 lock.size = 0;
440 }
441 }
442 }
443
444
445
446
447
448
449
450 @Override
451 public boolean containsKey(final Object key) {
452 final int hash = getHash(key);
453
454 synchronized (locks[hash]) {
455 Node<K, V> n = buckets[hash];
456
457 while (n != null) {
458 if (Objects.equals(n.key, key)) {
459 return true;
460 }
461
462 n = n.next;
463 }
464 }
465 return false;
466 }
467
468
469
470
471
472
473
474 @Override
475 public boolean containsValue(final Object value) {
476 for (int i = 0; i < buckets.length; i++) {
477 synchronized (locks[i]) {
478 Node<K, V> n = buckets[i];
479
480 while (n != null) {
481 if (Objects.equals(n.value, value)) {
482 return true;
483 }
484
485 n = n.next;
486 }
487 }
488 }
489 return false;
490 }
491
492
493
494
495
496
497 @Override
498 public Set<Map.Entry<K, V>> entrySet() {
499 return new EntrySet();
500 }
501
502
503
504
505
506
507
508 @Override
509 public boolean equals(final Object obj) {
510 if (obj == this) {
511 return true;
512 }
513 if (!(obj instanceof Map<?, ?>)) {
514 return false;
515 }
516 final Map<?, ?> other = (Map<?, ?>) obj;
517 return entrySet().equals(other.entrySet());
518 }
519
520
521
522
523
524
525
526 @Override
527 public V get(final Object key) {
528 final int hash = getHash(key);
529
530 synchronized (locks[hash]) {
531 Node<K, V> n = buckets[hash];
532
533 while (n != null) {
534 if (Objects.equals(n.key, key)) {
535 return n.value;
536 }
537
538 n = n.next;
539 }
540 }
541 return null;
542 }
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557 private int getHash(final Object key) {
558 if (key == null) {
559 return 0;
560 }
561 int hash = key.hashCode();
562 hash += ~(hash << 15);
563 hash ^= hash >>> 10;
564 hash += hash << 3;
565 hash ^= hash >>> 6;
566 hash += ~(hash << 11);
567 hash ^= hash >>> 16;
568 hash %= buckets.length;
569 return hash < 0 ? hash * -1 : hash;
570 }
571
572
573
574
575
576
577 @Override
578 public int hashCode() {
579 int hashCode = 0;
580
581 for (int i = 0; i < buckets.length; i++) {
582 synchronized (locks[i]) {
583 Node<K, V> n = buckets[i];
584
585 while (n != null) {
586 hashCode += n.hashCode();
587 n = n.next;
588 }
589 }
590 }
591 return hashCode;
592 }
593
594
595
596
597
598
599 @Override
600 public boolean isEmpty() {
601 return size() == 0;
602 }
603
604
605
606
607
608
609 @Override
610 public Set<K> keySet() {
611 return new KeySet();
612 }
613
614
615
616
617
618
619
620
621 @Override
622 public V put(final K key, final V value) {
623 final int hash = getHash(key);
624
625 synchronized (locks[hash]) {
626 Node<K, V> n = buckets[hash];
627
628 if (n == null) {
629 n = new Node<>();
630 n.key = key;
631 n.value = value;
632 buckets[hash] = n;
633 locks[hash].size++;
634 return null;
635 }
636
637
638
639
640 for (Node<K, V> next = n; next != null; next = next.next) {
641 n = next;
642
643 if (Objects.equals(n.key, key)) {
644 final V returnVal = n.value;
645 n.value = value;
646 return returnVal;
647 }
648 }
649
650
651
652 final Node<K, V> newNode = new Node<>();
653 newNode.key = key;
654 newNode.value = value;
655 n.next = newNode;
656 locks[hash].size++;
657 }
658 return null;
659 }
660
661
662
663
664
665
666
667 @Override
668 public void putAll(final Map<? extends K, ? extends V> map) {
669 for (final Map.Entry<? extends K, ? extends V> entry : map.entrySet()) {
670 put(entry.getKey(), entry.getValue());
671 }
672 }
673
674
675
676
677
678
679
680 @Override
681 public V remove(final Object key) {
682 final int hash = getHash(key);
683
684 synchronized (locks[hash]) {
685 Node<K, V> n = buckets[hash];
686 Node<K, V> prev = null;
687
688 while (n != null) {
689 if (Objects.equals(n.key, key)) {
690
691 if (null == prev) {
692
693 buckets[hash] = n.next;
694 } else {
695
696 prev.next = n.next;
697 }
698 locks[hash].size--;
699 return n.value;
700 }
701
702 prev = n;
703 n = n.next;
704 }
705 }
706 return null;
707 }
708
709
710
711
712
713
714
715 @Override
716 public int size() {
717 int cnt = 0;
718
719 for (int i = 0; i < buckets.length; i++) {
720 synchronized (locks[i]) {
721 cnt += locks[i].size;
722 }
723 }
724 return cnt;
725 }
726
727
728
729
730
731
732 @Override
733 public Collection<V> values() {
734 return new Values();
735 }
736
737 }