|
20 | 20 | import java.lang.ref.SoftReference; |
21 | 21 | import java.lang.ref.WeakReference; |
22 | 22 | import java.lang.reflect.Array; |
| 23 | +import java.util.AbstractCollection; |
23 | 24 | import java.util.AbstractMap; |
24 | 25 | import java.util.AbstractSet; |
| 26 | +import java.util.Collection; |
25 | 27 | import java.util.Collections; |
26 | 28 | import java.util.EnumSet; |
27 | 29 | import java.util.HashSet; |
28 | 30 | import java.util.Iterator; |
29 | 31 | import java.util.Map; |
30 | 32 | import java.util.NoSuchElementException; |
31 | 33 | import java.util.Set; |
| 34 | +import java.util.Spliterator; |
| 35 | +import java.util.Spliterators; |
32 | 36 | import java.util.concurrent.ConcurrentHashMap; |
33 | 37 | import java.util.concurrent.ConcurrentMap; |
34 | 38 | import java.util.concurrent.atomic.AtomicInteger; |
@@ -104,6 +108,18 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen |
104 | 108 | @Nullable |
105 | 109 | private volatile Set<Map.Entry<K, V>> entrySet; |
106 | 110 |
|
| 111 | + /** |
| 112 | + * Late binding key set. |
| 113 | + */ |
| 114 | + @Nullable |
| 115 | + private Set<K> keySet; |
| 116 | + |
| 117 | + /** |
| 118 | + * Late binding values collection. |
| 119 | + */ |
| 120 | + @Nullable |
| 121 | + private Collection<V> values; |
| 122 | + |
107 | 123 |
|
108 | 124 | /** |
109 | 125 | * Create a new {@code ConcurrentReferenceHashMap} instance. |
@@ -528,6 +544,26 @@ public Set<Map.Entry<K, V>> entrySet() { |
528 | 544 | return entrySet; |
529 | 545 | } |
530 | 546 |
|
| 547 | + @Override |
| 548 | + public Set<K> keySet() { |
| 549 | + Set<K> keySet = this.keySet; |
| 550 | + if (keySet == null) { |
| 551 | + keySet = new KeySet(); |
| 552 | + this.keySet = keySet; |
| 553 | + } |
| 554 | + return keySet; |
| 555 | + } |
| 556 | + |
| 557 | + @Override |
| 558 | + public Collection<V> values() { |
| 559 | + Collection<V> values = this.values; |
| 560 | + if (values == null) { |
| 561 | + values = new Values(); |
| 562 | + this.values = values; |
| 563 | + } |
| 564 | + return values; |
| 565 | + } |
| 566 | + |
531 | 567 | @Nullable |
532 | 568 | private <T> T doTask(@Nullable Object key, Task<T> task) { |
533 | 569 | int hash = getHash(key); |
@@ -969,7 +1005,7 @@ private interface Entries<V> { |
969 | 1005 | /** |
970 | 1006 | * Internal entry-set implementation. |
971 | 1007 | */ |
972 | | - private class EntrySet extends AbstractSet<Map.Entry<K, V>> { |
| 1008 | + private final class EntrySet extends AbstractSet<Map.Entry<K, V>> { |
973 | 1009 |
|
974 | 1010 | @Override |
975 | 1011 | public Iterator<Map.Entry<K, V>> iterator() { |
@@ -1005,13 +1041,133 @@ public int size() { |
1005 | 1041 | public void clear() { |
1006 | 1042 | ConcurrentReferenceHashMap.this.clear(); |
1007 | 1043 | } |
| 1044 | + |
| 1045 | + @Override |
| 1046 | + public Spliterator<Map.Entry<K, V>> spliterator() { |
| 1047 | + return Spliterators.spliterator(this, Spliterator.DISTINCT | Spliterator.CONCURRENT); |
| 1048 | + } |
| 1049 | + } |
| 1050 | + |
| 1051 | + /** |
| 1052 | + * Internal key-set implementation. |
| 1053 | + */ |
| 1054 | + private final class KeySet extends AbstractSet<K> { |
| 1055 | + @Override |
| 1056 | + public Iterator<K> iterator() { |
| 1057 | + return new KeyIterator(); |
| 1058 | + } |
| 1059 | + |
| 1060 | + @Override |
| 1061 | + public int size() { |
| 1062 | + return ConcurrentReferenceHashMap.this.size(); |
| 1063 | + } |
| 1064 | + |
| 1065 | + @Override |
| 1066 | + public boolean isEmpty() { |
| 1067 | + return ConcurrentReferenceHashMap.this.isEmpty(); |
| 1068 | + } |
| 1069 | + |
| 1070 | + @Override |
| 1071 | + public void clear() { |
| 1072 | + ConcurrentReferenceHashMap.this.clear(); |
| 1073 | + } |
| 1074 | + |
| 1075 | + @Override |
| 1076 | + public boolean contains(Object k) { |
| 1077 | + return ConcurrentReferenceHashMap.this.containsKey(k); |
| 1078 | + } |
| 1079 | + |
| 1080 | + @Override |
| 1081 | + public Spliterator<K> spliterator() { |
| 1082 | + return Spliterators.spliterator(this, Spliterator.DISTINCT | Spliterator.CONCURRENT); |
| 1083 | + } |
| 1084 | + } |
| 1085 | + |
| 1086 | + /** |
| 1087 | + * Internal key iterator implementation. |
| 1088 | + */ |
| 1089 | + private final class KeyIterator implements Iterator<K> { |
| 1090 | + |
| 1091 | + private final Iterator<Map.Entry<K, V>> iterator = entrySet().iterator(); |
| 1092 | + |
| 1093 | + @Override |
| 1094 | + public boolean hasNext() { |
| 1095 | + return this.iterator.hasNext(); |
| 1096 | + } |
| 1097 | + |
| 1098 | + @Override |
| 1099 | + public void remove() { |
| 1100 | + this.iterator.remove(); |
| 1101 | + } |
| 1102 | + |
| 1103 | + @Override |
| 1104 | + public K next() { |
| 1105 | + return this.iterator.next().getKey(); |
| 1106 | + } |
| 1107 | + } |
| 1108 | + |
| 1109 | + /** |
| 1110 | + * Internal values collection implementation. |
| 1111 | + */ |
| 1112 | + private final class Values extends AbstractCollection<V> { |
| 1113 | + @Override |
| 1114 | + public Iterator<V> iterator() { |
| 1115 | + return new ValueIterator(); |
| 1116 | + } |
| 1117 | + |
| 1118 | + @Override |
| 1119 | + public int size() { |
| 1120 | + return ConcurrentReferenceHashMap.this.size(); |
| 1121 | + } |
| 1122 | + |
| 1123 | + @Override |
| 1124 | + public boolean isEmpty() { |
| 1125 | + return ConcurrentReferenceHashMap.this.isEmpty(); |
| 1126 | + } |
| 1127 | + |
| 1128 | + @Override |
| 1129 | + public void clear() { |
| 1130 | + ConcurrentReferenceHashMap.this.clear(); |
| 1131 | + } |
| 1132 | + |
| 1133 | + @Override |
| 1134 | + public boolean contains(Object v) { |
| 1135 | + return ConcurrentReferenceHashMap.this.containsValue(v); |
| 1136 | + } |
| 1137 | + |
| 1138 | + @Override |
| 1139 | + public Spliterator<V> spliterator() { |
| 1140 | + return Spliterators.spliterator(this, Spliterator.CONCURRENT); |
| 1141 | + } |
1008 | 1142 | } |
1009 | 1143 |
|
| 1144 | + /** |
| 1145 | + * Internal value iterator implementation. |
| 1146 | + */ |
| 1147 | + private final class ValueIterator implements Iterator<V> { |
| 1148 | + |
| 1149 | + private final Iterator<Map.Entry<K, V>> iterator = entrySet().iterator(); |
| 1150 | + |
| 1151 | + @Override |
| 1152 | + public boolean hasNext() { |
| 1153 | + return this.iterator.hasNext(); |
| 1154 | + } |
| 1155 | + |
| 1156 | + @Override |
| 1157 | + public void remove() { |
| 1158 | + this.iterator.remove(); |
| 1159 | + } |
| 1160 | + |
| 1161 | + @Override |
| 1162 | + public V next() { |
| 1163 | + return this.iterator.next().getValue(); |
| 1164 | + } |
| 1165 | + } |
1010 | 1166 |
|
1011 | 1167 | /** |
1012 | 1168 | * Internal entry iterator implementation. |
1013 | 1169 | */ |
1014 | | - private class EntryIterator implements Iterator<Map.Entry<K, V>> { |
| 1170 | + private final class EntryIterator implements Iterator<Map.Entry<K, V>> { |
1015 | 1171 |
|
1016 | 1172 | private int segmentIndex; |
1017 | 1173 |
|
|
0 commit comments