1050 |
|
|
1051 |
|
/* ---------------- Iterator Support -------------- */ |
1052 |
|
|
1053 |
< |
abstract class HashIterator { |
1053 |
> |
class HashIterator { |
1054 |
|
int nextSegmentIndex; |
1055 |
|
int nextTableIndex; |
1056 |
|
HashEntry<K,V>[] currentTable; |
1117 |
|
} |
1118 |
|
|
1119 |
|
|
1120 |
– |
|
1120 |
|
/** |
1121 |
< |
* Entry iterator. Exported Entry objects must write-through |
1122 |
< |
* changes in setValue, even if the nodes have been cloned. So we |
1123 |
< |
* cannot return internal HashEntry objects. Instead, the iterator |
1124 |
< |
* itself acts as a forwarding pseudo-entry. |
1125 |
< |
*/ |
1126 |
< |
final class EntryIterator extends HashIterator implements Map.Entry<K,V>, Iterator<Entry<K,V>> { |
1127 |
< |
public Map.Entry<K,V> next() { |
1128 |
< |
nextEntry(); |
1129 |
< |
return this; |
1130 |
< |
} |
1131 |
< |
|
1132 |
< |
public K getKey() { |
1133 |
< |
if (lastReturned == null) |
1134 |
< |
throw new IllegalStateException("Entry was removed"); |
1135 |
< |
return lastReturned.key; |
1136 |
< |
} |
1137 |
< |
|
1138 |
< |
public V getValue() { |
1139 |
< |
if (lastReturned == null) |
1140 |
< |
throw new IllegalStateException("Entry was removed"); |
1141 |
< |
return ConcurrentHashMap.this.get(lastReturned.key); |
1142 |
< |
} |
1143 |
< |
|
1144 |
< |
public V setValue(V value) { |
1146 |
< |
if (lastReturned == null) |
1147 |
< |
throw new IllegalStateException("Entry was removed"); |
1148 |
< |
return ConcurrentHashMap.this.put(lastReturned.key, value); |
1149 |
< |
} |
1150 |
< |
|
1151 |
< |
public boolean equals(Object o) { |
1152 |
< |
// If not acting as entry, just use default. |
1153 |
< |
if (lastReturned == null) |
1154 |
< |
return super.equals(o); |
1155 |
< |
if (!(o instanceof Map.Entry)) |
1156 |
< |
return false; |
1157 |
< |
Map.Entry<?,?> e = (Map.Entry<?,?>)o; |
1158 |
< |
return eq(getKey(), e.getKey()) && eq(getValue(), e.getValue()); |
1159 |
< |
} |
1160 |
< |
|
1161 |
< |
public int hashCode() { |
1162 |
< |
// If not acting as entry, just use default. |
1163 |
< |
if (lastReturned == null) |
1164 |
< |
return super.hashCode(); |
1165 |
< |
|
1166 |
< |
Object k = getKey(); |
1167 |
< |
Object v = getValue(); |
1168 |
< |
return ((k == null) ? 0 : k.hashCode()) ^ |
1169 |
< |
((v == null) ? 0 : v.hashCode()); |
1170 |
< |
} |
1171 |
< |
|
1172 |
< |
public String toString() { |
1173 |
< |
// If not acting as entry, just use default. |
1174 |
< |
if (lastReturned == null) |
1175 |
< |
return super.toString(); |
1176 |
< |
else |
1177 |
< |
return getKey() + "=" + getValue(); |
1121 |
> |
* Custom Entry class used by EntryIterator.next(), that relays |
1122 |
> |
* setValue changes to the underlying map. |
1123 |
> |
*/ |
1124 |
> |
static final class WriteThroughEntry<K,V> extends AbstractMap.SimpleEntry<K,V> { |
1125 |
> |
private final ConcurrentHashMap<K,V> map; |
1126 |
> |
WriteThroughEntry(ConcurrentHashMap map, K k, V v) { |
1127 |
> |
super(k,v); |
1128 |
> |
this.map = map; |
1129 |
> |
} |
1130 |
> |
|
1131 |
> |
/** |
1132 |
> |
* Set our entry's value and write through to the map. The |
1133 |
> |
* value to return is somewhat arbitrary here. Since a |
1134 |
> |
* WriteThroughEntry does not necessarily track asynchronous |
1135 |
> |
* changes, the most recent "previous" value could be |
1136 |
> |
* different than what we return (or could even have been |
1137 |
> |
* removed in which case the put will re-establish). We do not |
1138 |
> |
* and cannot guarantee more. |
1139 |
> |
*/ |
1140 |
> |
public V setValue(V value) { |
1141 |
> |
if (value == null) throw new NullPointerException(); |
1142 |
> |
V v = super.setValue(value); |
1143 |
> |
map.put(getKey(), value); |
1144 |
> |
return v; |
1145 |
|
} |
1146 |
+ |
} |
1147 |
|
|
1148 |
< |
boolean eq(Object o1, Object o2) { |
1149 |
< |
return (o1 == null ? o2 == null : o1.equals(o2)); |
1148 |
> |
final class EntryIterator extends HashIterator implements Iterator<Entry<K,V>> { |
1149 |
> |
public Map.Entry<K,V> next() { |
1150 |
> |
HashEntry<K,V> e = super.nextEntry(); |
1151 |
> |
return new WriteThroughEntry<K,V>(ConcurrentHashMap.this, |
1152 |
> |
e.key, e.value); |
1153 |
|
} |
1183 |
– |
|
1154 |
|
} |
1155 |
|
|
1156 |
|
final class KeySet extends AbstractSet<K> { |
1234 |
|
ConcurrentHashMap.this.clear(); |
1235 |
|
} |
1236 |
|
public Object[] toArray() { |
1267 |
– |
// Since we don't ordinarily have distinct Entry objects, we |
1268 |
– |
// must pack elements using exportable SimpleEntry |
1237 |
|
Collection<Map.Entry<K,V>> c = new ArrayList<Map.Entry<K,V>>(size()); |
1238 |
|
for (Iterator<Map.Entry<K,V>> i = iterator(); i.hasNext(); ) |
1239 |
< |
c.add(new AbstractMap.SimpleEntry<K,V>(i.next())); |
1239 |
> |
c.add(i.next()); |
1240 |
|
return c.toArray(); |
1241 |
|
} |
1242 |
|
public <T> T[] toArray(T[] a) { |
1243 |
|
Collection<Map.Entry<K,V>> c = new ArrayList<Map.Entry<K,V>>(size()); |
1244 |
|
for (Iterator<Map.Entry<K,V>> i = iterator(); i.hasNext(); ) |
1245 |
< |
c.add(new AbstractMap.SimpleEntry<K,V>(i.next())); |
1245 |
> |
c.add(i.next()); |
1246 |
|
return c.toArray(a); |
1247 |
|
} |
1280 |
– |
|
1248 |
|
} |
1249 |
|
|
1250 |
|
/* ---------------- Serialization Support -------------- */ |