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.io.IOException;
20 import java.io.ObjectInputStream;
21 import java.io.ObjectOutputStream;
22 import java.lang.ref.Reference;
23 import java.lang.ref.ReferenceQueue;
24 import java.lang.ref.SoftReference;
25 import java.lang.ref.WeakReference;
26 import java.util.ArrayList;
27 import java.util.Collection;
28 import java.util.ConcurrentModificationException;
29 import java.util.Iterator;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.NoSuchElementException;
33 import java.util.Objects;
34 import java.util.Set;
35
36 import org.apache.commons.collections4.MapIterator;
37 import org.apache.commons.collections4.keyvalue.DefaultMapEntry;
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 public abstract class AbstractReferenceMap<K, V> extends AbstractHashedMap<K, V> {
92
93
94
95
96 static class ReferenceBaseIterator<K, V> {
97
98 final AbstractReferenceMap<K, V> parent;
99
100
101 int index;
102 ReferenceEntry<K, V> next;
103 ReferenceEntry<K, V> current;
104
105
106
107
108 K currentKey;
109 K nextKey;
110 V currentValue;
111 V nextValue;
112
113 int expectedModCount;
114
115 ReferenceBaseIterator(final AbstractReferenceMap<K, V> parent) {
116 this.parent = parent;
117 index = !parent.isEmpty() ? parent.data.length : 0;
118
119
120 expectedModCount = parent.modCount;
121 }
122
123 private void checkMod() {
124 if (parent.modCount != expectedModCount) {
125 throw new ConcurrentModificationException();
126 }
127 }
128
129 protected ReferenceEntry<K, V> currentEntry() {
130 checkMod();
131 return current;
132 }
133
134 public boolean hasNext() {
135 checkMod();
136 while (nextNull()) {
137 ReferenceEntry<K, V> e = next;
138 int i = index;
139 while (e == null && i > 0) {
140 i--;
141 e = (ReferenceEntry<K, V>) parent.data[i];
142 }
143 next = e;
144 index = i;
145 if (e == null) {
146 return false;
147 }
148 nextKey = e.getKey();
149 nextValue = e.getValue();
150 if (nextNull()) {
151 next = next.next();
152 }
153 }
154 return true;
155 }
156
157 protected ReferenceEntry<K, V> nextEntry() {
158 checkMod();
159 if (nextNull() && !hasNext()) {
160 throw new NoSuchElementException();
161 }
162 current = next;
163 next = next.next();
164 currentKey = nextKey;
165 currentValue = nextValue;
166 nextKey = null;
167 nextValue = null;
168 return current;
169 }
170
171 private boolean nextNull() {
172 return nextKey == null || nextValue == null;
173 }
174
175 public void remove() {
176 checkMod();
177 if (current == null) {
178 throw new IllegalStateException();
179 }
180 parent.remove(currentKey);
181 current = null;
182 currentKey = null;
183 currentValue = null;
184 expectedModCount = parent.modCount;
185 }
186 }
187
188
189
190
191
192
193
194
195
196
197
198
199 protected static class ReferenceEntry<K, V> extends HashEntry<K, V> {
200
201 private final AbstractReferenceMap<K, V> parent;
202
203
204
205
206
207
208
209
210
211
212 public ReferenceEntry(final AbstractReferenceMap<K, V> parent, final HashEntry<K, V> next,
213 final int hashCode, final K key, final V value) {
214 super(next, hashCode, null, null);
215 this.parent = parent;
216 this.key = toReference(parent.keyType, key, hashCode);
217 this.value = toReference(parent.valueType, value, hashCode);
218 }
219
220
221
222
223
224
225
226
227
228
229
230 @Override
231 public boolean equals(final Object obj) {
232 if (obj == this) {
233 return true;
234 }
235 if (!(obj instanceof Map.Entry)) {
236 return false;
237 }
238
239 final Map.Entry<?, ?> entry = (Map.Entry<?, ?>) obj;
240 final Object entryKey = entry.getKey();
241 final Object entryValue = entry.getValue();
242 if (entryKey == null || entryValue == null) {
243 return false;
244 }
245
246
247 return parent.isEqualKey(entryKey, key) &&
248 parent.isEqualValue(entryValue, getValue());
249 }
250
251
252
253
254
255
256
257 @Override
258 @SuppressWarnings("unchecked")
259 public K getKey() {
260 return (K) (parent.keyType == ReferenceStrength.HARD ? key : ((Reference<K>) key).get());
261 }
262
263
264
265
266
267
268
269 @Override
270 @SuppressWarnings("unchecked")
271 public V getValue() {
272 return (V) (parent.valueType == ReferenceStrength.HARD ? value : ((Reference<V>) value).get());
273 }
274
275
276
277
278
279
280
281
282 @Override
283 public int hashCode() {
284 return parent.hashEntry(getKey(), getValue());
285 }
286
287
288
289
290
291
292 protected ReferenceEntry<K, V> next() {
293 return (ReferenceEntry<K, V>) next;
294 }
295
296
297
298
299 protected void nullValue() {
300 value = null;
301 }
302
303
304
305
306 protected void onPurge() {
307
308 }
309
310
311
312
313
314
315 protected boolean purge(final Reference<?> ref) {
316 boolean r = parent.keyType != ReferenceStrength.HARD && key == ref;
317 r = r || parent.valueType != ReferenceStrength.HARD && value == ref;
318 if (r) {
319 if (parent.keyType != ReferenceStrength.HARD) {
320 ((Reference<?>) key).clear();
321 }
322 if (parent.valueType != ReferenceStrength.HARD) {
323 ((Reference<?>) value).clear();
324 } else if (parent.purgeValues) {
325 nullValue();
326 }
327 }
328 return r;
329 }
330
331
332
333
334
335
336
337 @Override
338 @SuppressWarnings("unchecked")
339 public V setValue(final V value) {
340 final V old = getValue();
341 if (parent.valueType != ReferenceStrength.HARD) {
342 ((Reference<V>) this.value).clear();
343 }
344 this.value = toReference(parent.valueType, value, hashCode);
345 return old;
346 }
347
348
349
350
351
352
353
354
355
356
357
358
359
360 protected <T> Object toReference(final ReferenceStrength type, final T referent, final int hash) {
361 switch (type) {
362 case HARD:
363 return referent;
364 case SOFT:
365 return new SoftRef<>(hash, referent, parent.queue);
366 case WEAK:
367 return new WeakRef<>(hash, referent, parent.queue);
368 default:
369 break;
370 }
371 throw new Error();
372 }
373 }
374
375
376
377
378 static class ReferenceEntrySet<K, V> extends EntrySet<K, V> {
379
380 protected ReferenceEntrySet(final AbstractHashedMap<K, V> parent) {
381 super(parent);
382 }
383
384 @Override
385 public Object[] toArray() {
386 return toArray(new Object[size()]);
387 }
388
389 @Override
390 public <T> T[] toArray(final T[] arr) {
391
392 final ArrayList<Map.Entry<K, V>> list = new ArrayList<>(size());
393 for (final Map.Entry<K, V> entry : this) {
394 list.add(new DefaultMapEntry<>(entry));
395 }
396 return list.toArray(arr);
397 }
398 }
399
400
401
402
403 static class ReferenceEntrySetIterator<K, V>
404 extends ReferenceBaseIterator<K, V> implements Iterator<Map.Entry<K, V>> {
405
406 ReferenceEntrySetIterator(final AbstractReferenceMap<K, V> parent) {
407 super(parent);
408 }
409
410 @Override
411 public Map.Entry<K, V> next() {
412 return nextEntry();
413 }
414
415 }
416
417
418
419
420 static class ReferenceKeySet<K> extends KeySet<K> {
421
422 protected ReferenceKeySet(final AbstractHashedMap<K, ?> parent) {
423 super(parent);
424 }
425
426 @Override
427 public Object[] toArray() {
428 return toArray(new Object[size()]);
429 }
430
431 @Override
432 public <T> T[] toArray(final T[] arr) {
433
434 final List<K> list = new ArrayList<>(size());
435 forEach(list::add);
436 return list.toArray(arr);
437 }
438 }
439
440
441
442
443 static class ReferenceKeySetIterator<K> extends ReferenceBaseIterator<K, Object> implements Iterator<K> {
444
445 @SuppressWarnings("unchecked")
446 ReferenceKeySetIterator(final AbstractReferenceMap<K, ?> parent) {
447 super((AbstractReferenceMap<K, Object>) parent);
448 }
449
450 @Override
451 public K next() {
452 return nextEntry().getKey();
453 }
454 }
455
456
457
458
459 static class ReferenceMapIterator<K, V> extends ReferenceBaseIterator<K, V> implements MapIterator<K, V> {
460
461 protected ReferenceMapIterator(final AbstractReferenceMap<K, V> parent) {
462 super(parent);
463 }
464
465 @Override
466 public K getKey() {
467 final HashEntry<K, V> current = currentEntry();
468 if (current == null) {
469 throw new IllegalStateException(GETKEY_INVALID);
470 }
471 return current.getKey();
472 }
473
474 @Override
475 public V getValue() {
476 final HashEntry<K, V> current = currentEntry();
477 if (current == null) {
478 throw new IllegalStateException(GETVALUE_INVALID);
479 }
480 return current.getValue();
481 }
482
483 @Override
484 public K next() {
485 return nextEntry().getKey();
486 }
487
488 @Override
489 public V setValue(final V value) {
490 final HashEntry<K, V> current = currentEntry();
491 if (current == null) {
492 throw new IllegalStateException(SETVALUE_INVALID);
493 }
494 return current.setValue(value);
495 }
496 }
497
498
499
500
501 public enum ReferenceStrength {
502
503
504
505
506 HARD(0),
507
508
509
510
511 SOFT(1),
512
513
514
515
516 WEAK(2);
517
518
519
520
521
522
523
524 public static ReferenceStrength resolve(final int value) {
525 switch (value) {
526 case 0:
527 return HARD;
528 case 1:
529 return SOFT;
530 case 2:
531 return WEAK;
532 default:
533 throw new IllegalArgumentException();
534 }
535 }
536
537
538 public final int value;
539
540 ReferenceStrength(final int value) {
541 this.value = value;
542 }
543
544 }
545
546
547
548
549 static class ReferenceValues<V> extends Values<V> {
550
551 protected ReferenceValues(final AbstractHashedMap<?, V> parent) {
552 super(parent);
553 }
554
555 @Override
556 public Object[] toArray() {
557 return toArray(new Object[size()]);
558 }
559
560 @Override
561 public <T> T[] toArray(final T[] arr) {
562
563 final List<V> list = new ArrayList<>(size());
564 forEach(list::add);
565 return list.toArray(arr);
566 }
567 }
568
569
570
571
572 static class ReferenceValuesIterator<V> extends ReferenceBaseIterator<Object, V> implements Iterator<V> {
573
574 @SuppressWarnings("unchecked")
575 ReferenceValuesIterator(final AbstractReferenceMap<?, V> parent) {
576 super((AbstractReferenceMap<Object, V>) parent);
577 }
578
579 @Override
580 public V next() {
581 return nextEntry().getValue();
582 }
583 }
584
585
586
587
588 static class SoftRef<T> extends SoftReference<T> {
589
590 private final int hash;
591
592 SoftRef(final int hash, final T r, final ReferenceQueue<? super T> q) {
593 super(r, q);
594 this.hash = hash;
595 }
596
597 @Override
598 public boolean equals(final Object obj) {
599 if (this == obj) {
600 return true;
601 }
602 if (obj == null) {
603 return false;
604 }
605 if (getClass() != obj.getClass()) {
606 return false;
607 }
608 final SoftRef<?> other = (SoftRef<?>) obj;
609 return hash == other.hash;
610 }
611
612 @Override
613 public int hashCode() {
614 return hash;
615 }
616 }
617
618
619
620
621 static class WeakRef<T> extends WeakReference<T> {
622
623 private final int hash;
624
625 WeakRef(final int hash, final T r, final ReferenceQueue<? super T> q) {
626 super(r, q);
627 this.hash = hash;
628 }
629
630 @Override
631 public boolean equals(final Object obj) {
632 if (this == obj) {
633 return true;
634 }
635 if (obj == null) {
636 return false;
637 }
638 if (getClass() != obj.getClass()) {
639 return false;
640 }
641 final WeakRef<?> other = (WeakRef<?>) obj;
642 return hash == other.hash;
643 }
644
645 @Override
646 public int hashCode() {
647 return hash;
648 }
649 }
650
651
652
653
654 private ReferenceStrength keyType;
655
656
657
658
659 private ReferenceStrength valueType;
660
661
662
663
664 private boolean purgeValues;
665
666
667
668
669
670 private transient ReferenceQueue<Object> queue;
671
672
673
674
675 protected AbstractReferenceMap() {
676 }
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695 protected AbstractReferenceMap(
696 final ReferenceStrength keyType, final ReferenceStrength valueType, final int capacity,
697 final float loadFactor, final boolean purgeValues) {
698 super(capacity, loadFactor);
699 this.keyType = keyType;
700 this.valueType = valueType;
701 this.purgeValues = purgeValues;
702 }
703
704
705
706
707 @Override
708 public void clear() {
709 super.clear();
710
711 while (queue.poll() != null) {
712 }
713 }
714
715
716
717
718
719
720
721 @Override
722 public boolean containsKey(final Object key) {
723 purgeBeforeRead();
724 final Entry<K, V> entry = getEntry(key);
725 if (entry == null) {
726 return false;
727 }
728 return entry.getValue() != null;
729 }
730
731
732
733
734
735
736
737 @Override
738 public boolean containsValue(final Object value) {
739 purgeBeforeRead();
740 if (value == null) {
741 return false;
742 }
743 return super.containsValue(value);
744 }
745
746
747
748
749
750
751
752
753
754
755 @Override
756 protected ReferenceEntry<K, V> createEntry(final HashEntry<K, V> next, final int hashCode,
757 final K key, final V value) {
758 return new ReferenceEntry<>(this, next, hashCode, key, value);
759 }
760
761
762
763
764
765
766 @Override
767 protected Iterator<Map.Entry<K, V>> createEntrySetIterator() {
768 return new ReferenceEntrySetIterator<>(this);
769 }
770
771
772
773
774
775
776 @Override
777 protected Iterator<K> createKeySetIterator() {
778 return new ReferenceKeySetIterator<>(this);
779 }
780
781
782
783
784
785
786 @Override
787 protected Iterator<V> createValuesIterator() {
788 return new ReferenceValuesIterator<>(this);
789 }
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813 @Override
814 @SuppressWarnings("unchecked")
815 protected void doReadObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
816 keyType = ReferenceStrength.resolve(in.readInt());
817 valueType = ReferenceStrength.resolve(in.readInt());
818 purgeValues = in.readBoolean();
819 loadFactor = in.readFloat();
820 final int capacity = in.readInt();
821 init();
822 data = new HashEntry[capacity];
823
824
825
826
827
828
829
830 threshold = calculateThreshold(data.length, loadFactor);
831
832 while (true) {
833 final K key = (K) in.readObject();
834 if (key == null) {
835 break;
836 }
837 final V value = (V) in.readObject();
838 put(key, value);
839 }
840
841 }
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865 @Override
866 protected void doWriteObject(final ObjectOutputStream out) throws IOException {
867 out.writeInt(keyType.value);
868 out.writeInt(valueType.value);
869 out.writeBoolean(purgeValues);
870 out.writeFloat(loadFactor);
871 out.writeInt(data.length);
872 for (final MapIterator<K, V> it = mapIterator(); it.hasNext();) {
873 out.writeObject(it.next());
874 out.writeObject(it.getValue());
875 }
876 out.writeObject(null);
877
878 }
879
880
881
882
883
884
885
886
887 @Override
888 public Set<Map.Entry<K, V>> entrySet() {
889 if (entrySet == null) {
890 entrySet = new ReferenceEntrySet<>(this);
891 }
892 return entrySet;
893 }
894
895
896
897
898
899
900
901 @Override
902 public V get(final Object key) {
903 purgeBeforeRead();
904 final Entry<K, V> entry = getEntry(key);
905 if (entry == null) {
906 return null;
907 }
908 return entry.getValue();
909 }
910
911
912
913
914
915
916
917 @Override
918 protected HashEntry<K, V> getEntry(final Object key) {
919 if (key == null) {
920 return null;
921 }
922 return super.getEntry(key);
923 }
924
925
926
927
928
929
930
931
932
933 protected int hashEntry(final Object key, final Object value) {
934 return (key == null ? 0 : key.hashCode()) ^
935 (value == null ? 0 : value.hashCode());
936 }
937
938
939
940
941 @Override
942 protected void init() {
943 queue = new ReferenceQueue<>();
944 }
945
946
947
948
949
950
951 @Override
952 public boolean isEmpty() {
953 purgeBeforeRead();
954 return super.isEmpty();
955 }
956
957
958
959
960
961
962
963
964
965
966
967
968 @Override
969 @SuppressWarnings("unchecked")
970 protected boolean isEqualKey(final Object key1, Object key2) {
971 key2 = keyType == ReferenceStrength.HARD ? key2 : ((Reference<K>) key2).get();
972 return Objects.equals(key1, key2);
973 }
974
975
976
977
978
979
980
981 protected boolean isKeyType(final ReferenceStrength type) {
982 return keyType == type;
983 }
984
985
986
987
988
989
990
991 protected boolean isValueType(final ReferenceStrength type) {
992 return valueType == type;
993 }
994
995
996
997
998
999
1000 @Override
1001 public Set<K> keySet() {
1002 if (keySet == null) {
1003 keySet = new ReferenceKeySet<>(this);
1004 }
1005 return keySet;
1006 }
1007
1008
1009
1010
1011
1012
1013
1014 @Override
1015 public MapIterator<K, V> mapIterator() {
1016 return new ReferenceMapIterator<>(this);
1017 }
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028 protected void purge() {
1029 Reference<?> ref = queue.poll();
1030 while (ref != null) {
1031 purge(ref);
1032 ref = queue.poll();
1033 }
1034 }
1035
1036
1037
1038
1039
1040
1041 protected void purge(final Reference<?> ref) {
1042
1043
1044
1045 final int hash = ref.hashCode();
1046 final int index = hashIndex(hash, data.length);
1047 HashEntry<K, V> previous = null;
1048 HashEntry<K, V> entry = data[index];
1049 while (entry != null) {
1050 final ReferenceEntry<K, V> refEntry = (ReferenceEntry<K, V>) entry;
1051 if (refEntry.purge(ref)) {
1052 if (previous == null) {
1053 data[index] = entry.next;
1054 } else {
1055 previous.next = entry.next;
1056 }
1057 size--;
1058 refEntry.onPurge();
1059 return;
1060 }
1061 previous = entry;
1062 entry = entry.next;
1063 }
1064
1065 }
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076 protected void purgeBeforeRead() {
1077 purge();
1078 }
1079
1080
1081
1082
1083
1084
1085
1086 protected void purgeBeforeWrite() {
1087 purge();
1088 }
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099 @Override
1100 public V put(final K key, final V value) {
1101 Objects.requireNonNull(key, "key");
1102 Objects.requireNonNull(value, "value");
1103 purgeBeforeWrite();
1104 return super.put(key, value);
1105 }
1106
1107
1108
1109
1110
1111
1112
1113 @Override
1114 public V remove(final Object key) {
1115 if (key == null) {
1116 return null;
1117 }
1118 purgeBeforeWrite();
1119 return super.remove(key);
1120 }
1121
1122
1123
1124
1125
1126
1127 @Override
1128 public int size() {
1129 purgeBeforeRead();
1130 return super.size();
1131 }
1132
1133
1134
1135
1136
1137
1138 @Override
1139 public Collection<V> values() {
1140 if (values == null) {
1141 values = new ReferenceValues<>(this);
1142 }
1143 return values;
1144 }
1145 }