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