OLD | NEW |
1 // Protocol Buffers - Google's data interchange format | 1 // Protocol Buffers - Google's data interchange format |
2 // Copyright 2008 Google Inc. All rights reserved. | 2 // Copyright 2008 Google Inc. All rights reserved. |
3 // https://developers.google.com/protocol-buffers/ | 3 // https://developers.google.com/protocol-buffers/ |
4 // | 4 // |
5 // Redistribution and use in source and binary forms, with or without | 5 // Redistribution and use in source and binary forms, with or without |
6 // modification, are permitted provided that the following conditions are | 6 // modification, are permitted provided that the following conditions are |
7 // met: | 7 // met: |
8 // | 8 // |
9 // * Redistributions of source code must retain the above copyright | 9 // * Redistributions of source code must retain the above copyright |
10 // notice, this list of conditions and the following disclaimer. | 10 // notice, this list of conditions and the following disclaimer. |
(...skipping 12 matching lines...) Expand all Loading... |
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
30 | 30 |
31 package com.google.protobuf; | 31 package com.google.protobuf; |
32 | 32 |
| 33 import com.google.protobuf.MapFieldLite.MutatabilityAwareMap; |
| 34 |
33 import java.util.ArrayList; | 35 import java.util.ArrayList; |
34 import java.util.Collection; | |
35 import java.util.Collections; | 36 import java.util.Collections; |
36 import java.util.Iterator; | |
37 import java.util.LinkedHashMap; | 37 import java.util.LinkedHashMap; |
38 import java.util.List; | 38 import java.util.List; |
39 import java.util.Map; | 39 import java.util.Map; |
40 import java.util.Set; | |
41 | 40 |
42 /** | 41 /** |
43 * Internal representation of map fields in generated messages. | 42 * Internal representation of map fields in generated messages. |
44 * | 43 * |
45 * This class supports accessing the map field as a {@link Map} to be used in | 44 * This class supports accessing the map field as a {@link Map} to be used in |
46 * generated API and also supports accessing the field as a {@link List} to be | 45 * generated API and also supports accessing the field as a {@link List} to be |
47 * used in reflection API. It keeps track of where the data is currently stored | 46 * used in reflection API. It keeps track of where the data is currently stored |
48 * and do necessary conversions between map and list. | 47 * and do necessary conversions between map and list. |
49 * | 48 * |
50 * This class is a protobuf implementation detail. Users shouldn't use this | 49 * This class is a protobuf implementation detail. Users shouldn't use this |
51 * class directly. | 50 * class directly. |
52 * | 51 * |
53 * THREAD-SAFETY NOTE: Read-only access is thread-safe. Users can call getMap() | 52 * THREAD-SAFETY NOTE: Read-only access is thread-safe. Users can call getMap() |
54 * and getList() concurrently in multiple threads. If write-access is needed, | 53 * and getList() concurrently in multiple threads. If write-access is needed, |
55 * all access must be synchronized. | 54 * all access must be synchronized. |
56 */ | 55 */ |
57 public class MapField<K, V> implements MutabilityOracle { | 56 public class MapField<K, V> implements MutabilityOracle { |
58 /** | 57 /** |
59 * Indicates where the data of this map field is currently stored. | 58 * Indicates where the data of this map field is currently stored. |
60 * | 59 * |
61 * MAP: Data is stored in mapData. | 60 * MAP: Data is stored in mapData. |
62 * LIST: Data is stored in listData. | 61 * LIST: Data is stored in listData. |
63 * BOTH: mapData and listData have the same data. | 62 * BOTH: mapData and listData have the same data. |
64 * | 63 * |
65 * When the map field is accessed (through generated API or reflection API), | 64 * When the map field is accessed (through generated API or reflection API), |
66 * it will shift between these 3 modes: | 65 * it will shift between these 3 modes: |
67 * | 66 * |
68 * getMap() getList() getMutableMap() getMutableList() | 67 * getMap() getList() getMutableMap() getMutableList() |
69 * MAP MAP BOTH MAP LIST | 68 * MAP MAP BOTH MAP LIST |
70 * LIST BOTH LIST MAP LIST | 69 * LIST BOTH LIST MAP LIST |
71 * BOTH BOTH BOTH MAP LIST | 70 * BOTH BOTH BOTH MAP LIST |
72 * | 71 * |
73 * As the map field changes its mode, the list/map reference returned in a | 72 * As the map field changes its mode, the list/map reference returned in a |
74 * previous method call may be invalidated. | 73 * previous method call may be invalidated. |
75 */ | 74 */ |
76 private enum StorageMode {MAP, LIST, BOTH} | 75 private enum StorageMode {MAP, LIST, BOTH} |
77 | 76 |
78 private volatile boolean isMutable; | 77 private volatile boolean isMutable; |
79 private volatile StorageMode mode; | 78 private volatile StorageMode mode; |
80 private MutatabilityAwareMap<K, V> mapData; | 79 private MutatabilityAwareMap<K, V> mapData; |
81 private List<Message> listData; | 80 private List<Message> listData; |
82 | 81 |
83 // Convert between a map entry Message and a key-value pair. | 82 // Convert between a map entry Message and a key-value pair. |
84 private static interface Converter<K, V> { | 83 private static interface Converter<K, V> { |
85 Message convertKeyAndValueToMessage(K key, V value); | 84 Message convertKeyAndValueToMessage(K key, V value); |
86 void convertMessageToKeyAndValue(Message message, Map<K, V> map); | 85 void convertMessageToKeyAndValue(Message message, Map<K, V> map); |
87 | 86 |
88 Message getMessageDefaultInstance(); | 87 Message getMessageDefaultInstance(); |
89 } | 88 } |
90 | 89 |
91 private static class ImmutableMessageConverter<K, V> implements Converter<K, V
> { | 90 private static class ImmutableMessageConverter<K, V> implements Converter<K, V
> { |
92 private final MapEntry<K, V> defaultEntry; | 91 private final MapEntry<K, V> defaultEntry; |
93 public ImmutableMessageConverter(MapEntry<K, V> defaultEntry) { | 92 public ImmutableMessageConverter(MapEntry<K, V> defaultEntry) { |
94 this.defaultEntry = defaultEntry; | 93 this.defaultEntry = defaultEntry; |
95 } | 94 } |
96 | 95 |
97 @Override | 96 @Override |
98 public Message convertKeyAndValueToMessage(K key, V value) { | 97 public Message convertKeyAndValueToMessage(K key, V value) { |
99 return defaultEntry.newBuilderForType().setKey(key).setValue(value).buildP
artial(); | 98 return defaultEntry.newBuilderForType().setKey(key).setValue(value).buildP
artial(); |
100 } | 99 } |
101 | 100 |
102 @Override | 101 @Override |
103 public void convertMessageToKeyAndValue(Message message, Map<K, V> map) { | 102 public void convertMessageToKeyAndValue(Message message, Map<K, V> map) { |
104 MapEntry<K, V> entry = (MapEntry<K, V>) message; | 103 MapEntry<K, V> entry = (MapEntry<K, V>) message; |
105 map.put(entry.getKey(), entry.getValue()); | 104 map.put(entry.getKey(), entry.getValue()); |
106 } | 105 } |
107 | 106 |
108 @Override | 107 @Override |
109 public Message getMessageDefaultInstance() { | 108 public Message getMessageDefaultInstance() { |
110 return defaultEntry; | 109 return defaultEntry; |
111 } | 110 } |
112 } | 111 } |
113 | 112 |
114 | 113 |
115 private final Converter<K, V> converter; | 114 private final Converter<K, V> converter; |
116 | 115 |
117 private MapField( | 116 private MapField( |
118 Converter<K, V> converter, | 117 Converter<K, V> converter, |
119 StorageMode mode, | 118 StorageMode mode, |
120 Map<K, V> mapData) { | 119 Map<K, V> mapData) { |
121 this.converter = converter; | 120 this.converter = converter; |
122 this.isMutable = true; | 121 this.isMutable = true; |
123 this.mode = mode; | 122 this.mode = mode; |
124 this.mapData = new MutatabilityAwareMap<K, V>(this, mapData); | 123 this.mapData = new MutatabilityAwareMap<K, V>(this, mapData); |
125 this.listData = null; | 124 this.listData = null; |
126 } | 125 } |
127 | 126 |
128 private MapField( | 127 private MapField( |
129 MapEntry<K, V> defaultEntry, | 128 MapEntry<K, V> defaultEntry, |
130 StorageMode mode, | 129 StorageMode mode, |
131 Map<K, V> mapData) { | 130 Map<K, V> mapData) { |
132 this(new ImmutableMessageConverter<K, V>(defaultEntry), mode, mapData); | 131 this(new ImmutableMessageConverter<K, V>(defaultEntry), mode, mapData); |
133 } | 132 } |
134 | 133 |
135 | 134 |
136 /** Returns an immutable empty MapField. */ | 135 /** Returns an immutable empty MapField. */ |
137 public static <K, V> MapField<K, V> emptyMapField( | 136 public static <K, V> MapField<K, V> emptyMapField( |
138 MapEntry<K, V> defaultEntry) { | 137 MapEntry<K, V> defaultEntry) { |
139 return new MapField<K, V>( | 138 return new MapField<K, V>( |
140 defaultEntry, StorageMode.MAP, Collections.<K, V>emptyMap()); | 139 defaultEntry, StorageMode.MAP, Collections.<K, V>emptyMap()); |
141 } | 140 } |
142 | 141 |
143 | 142 |
144 /** Creates a new mutable empty MapField. */ | 143 /** Creates a new mutable empty MapField. */ |
145 public static <K, V> MapField<K, V> newMapField(MapEntry<K, V> defaultEntry) { | 144 public static <K, V> MapField<K, V> newMapField(MapEntry<K, V> defaultEntry) { |
146 return new MapField<K, V>( | 145 return new MapField<K, V>( |
147 defaultEntry, StorageMode.MAP, new LinkedHashMap<K, V>()); | 146 defaultEntry, StorageMode.MAP, new LinkedHashMap<K, V>()); |
148 } | 147 } |
149 | 148 |
150 | 149 |
151 private Message convertKeyAndValueToMessage(K key, V value) { | 150 private Message convertKeyAndValueToMessage(K key, V value) { |
152 return converter.convertKeyAndValueToMessage(key, value); | 151 return converter.convertKeyAndValueToMessage(key, value); |
153 } | 152 } |
154 | 153 |
155 @SuppressWarnings("unchecked") | 154 @SuppressWarnings("unchecked") |
156 private void convertMessageToKeyAndValue(Message message, Map<K, V> map) { | 155 private void convertMessageToKeyAndValue(Message message, Map<K, V> map) { |
157 converter.convertMessageToKeyAndValue(message, map); | 156 converter.convertMessageToKeyAndValue(message, map); |
158 } | 157 } |
159 | 158 |
160 private List<Message> convertMapToList(MutatabilityAwareMap<K, V> mapData) { | 159 private List<Message> convertMapToList(MutatabilityAwareMap<K, V> mapData) { |
161 List<Message> listData = new ArrayList<Message>(); | 160 List<Message> listData = new ArrayList<Message>(); |
162 for (Map.Entry<K, V> entry : mapData.entrySet()) { | 161 for (Map.Entry<K, V> entry : mapData.entrySet()) { |
163 listData.add( | 162 listData.add( |
164 convertKeyAndValueToMessage( | 163 convertKeyAndValueToMessage( |
165 entry.getKey(), entry.getValue())); | 164 entry.getKey(), entry.getValue())); |
166 } | 165 } |
167 return listData; | 166 return listData; |
168 } | 167 } |
169 | 168 |
170 private MutatabilityAwareMap<K, V> convertListToMap(List<Message> listData) { | 169 private MutatabilityAwareMap<K, V> convertListToMap(List<Message> listData) { |
171 Map<K, V> mapData = new LinkedHashMap<K, V>(); | 170 Map<K, V> mapData = new LinkedHashMap<K, V>(); |
172 for (Message item : listData) { | 171 for (Message item : listData) { |
173 convertMessageToKeyAndValue(item, mapData); | 172 convertMessageToKeyAndValue(item, mapData); |
174 } | 173 } |
175 return new MutatabilityAwareMap<K, V>(this, mapData); | 174 return new MutatabilityAwareMap<K, V>(this, mapData); |
176 } | 175 } |
177 | 176 |
178 /** Returns the content of this MapField as a read-only Map. */ | 177 /** Returns the content of this MapField as a read-only Map. */ |
179 public Map<K, V> getMap() { | 178 public Map<K, V> getMap() { |
180 if (mode == StorageMode.LIST) { | 179 if (mode == StorageMode.LIST) { |
181 synchronized (this) { | 180 synchronized (this) { |
182 if (mode == StorageMode.LIST) { | 181 if (mode == StorageMode.LIST) { |
183 mapData = convertListToMap(listData); | 182 mapData = convertListToMap(listData); |
184 mode = StorageMode.BOTH; | 183 mode = StorageMode.BOTH; |
185 } | 184 } |
186 } | 185 } |
187 } | 186 } |
188 return Collections.unmodifiableMap(mapData); | 187 return Collections.unmodifiableMap(mapData); |
189 } | 188 } |
190 | 189 |
191 /** Gets a mutable Map view of this MapField. */ | 190 /** Gets a mutable Map view of this MapField. */ |
192 public Map<K, V> getMutableMap() { | 191 public Map<K, V> getMutableMap() { |
193 if (mode != StorageMode.MAP) { | 192 if (mode != StorageMode.MAP) { |
194 if (mode == StorageMode.LIST) { | 193 if (mode == StorageMode.LIST) { |
195 mapData = convertListToMap(listData); | 194 mapData = convertListToMap(listData); |
196 } | 195 } |
197 listData = null; | 196 listData = null; |
198 mode = StorageMode.MAP; | 197 mode = StorageMode.MAP; |
199 } | 198 } |
200 return mapData; | 199 return mapData; |
201 } | 200 } |
202 | 201 |
203 public void mergeFrom(MapField<K, V> other) { | 202 public void mergeFrom(MapField<K, V> other) { |
204 getMutableMap().putAll(MapFieldLite.copy(other.getMap())); | 203 getMutableMap().putAll(MapFieldLite.copy(other.getMap())); |
205 } | 204 } |
206 | 205 |
207 public void clear() { | 206 public void clear() { |
208 mapData = new MutatabilityAwareMap<K, V>(this, new LinkedHashMap<K, V>()); | 207 mapData = new MutatabilityAwareMap<K, V>(this, new LinkedHashMap<K, V>()); |
209 mode = StorageMode.MAP; | 208 mode = StorageMode.MAP; |
210 } | 209 } |
211 | 210 |
212 @SuppressWarnings("unchecked") | 211 @SuppressWarnings("unchecked") |
213 @Override | 212 @Override |
214 public boolean equals(Object object) { | 213 public boolean equals(Object object) { |
215 if (!(object instanceof MapField)) { | 214 if (!(object instanceof MapField)) { |
216 return false; | 215 return false; |
217 } | 216 } |
218 MapField<K, V> other = (MapField<K, V>) object; | 217 MapField<K, V> other = (MapField<K, V>) object; |
219 return MapFieldLite.<K, V>equals(getMap(), other.getMap()); | 218 return MapFieldLite.<K, V>equals(getMap(), other.getMap()); |
220 } | 219 } |
221 | 220 |
222 @Override | 221 @Override |
223 public int hashCode() { | 222 public int hashCode() { |
224 return MapFieldLite.<K, V>calculateHashCodeForMap(getMap()); | 223 return MapFieldLite.<K, V>calculateHashCodeForMap(getMap()); |
225 } | 224 } |
226 | 225 |
227 /** Returns a deep copy of this MapField. */ | 226 /** Returns a deep copy of this MapField. */ |
228 public MapField<K, V> copy() { | 227 public MapField<K, V> copy() { |
229 return new MapField<K, V>( | 228 return new MapField<K, V>( |
230 converter, StorageMode.MAP, MapFieldLite.copy(getMap())); | 229 converter, StorageMode.MAP, MapFieldLite.copy(getMap())); |
231 } | 230 } |
232 | 231 |
233 /** Gets the content of this MapField as a read-only List. */ | 232 /** Gets the content of this MapField as a read-only List. */ |
234 List<Message> getList() { | 233 List<Message> getList() { |
235 if (mode == StorageMode.MAP) { | 234 if (mode == StorageMode.MAP) { |
236 synchronized (this) { | 235 synchronized (this) { |
237 if (mode == StorageMode.MAP) { | 236 if (mode == StorageMode.MAP) { |
238 listData = convertMapToList(mapData); | 237 listData = convertMapToList(mapData); |
239 mode = StorageMode.BOTH; | 238 mode = StorageMode.BOTH; |
240 } | 239 } |
241 } | 240 } |
242 } | 241 } |
243 return Collections.unmodifiableList(listData); | 242 return Collections.unmodifiableList(listData); |
244 } | 243 } |
245 | 244 |
246 /** Gets a mutable List view of this MapField. */ | 245 /** Gets a mutable List view of this MapField. */ |
247 List<Message> getMutableList() { | 246 List<Message> getMutableList() { |
248 if (mode != StorageMode.LIST) { | 247 if (mode != StorageMode.LIST) { |
249 if (mode == StorageMode.MAP) { | 248 if (mode == StorageMode.MAP) { |
250 listData = convertMapToList(mapData); | 249 listData = convertMapToList(mapData); |
251 } | 250 } |
252 mapData = null; | 251 mapData = null; |
253 mode = StorageMode.LIST; | 252 mode = StorageMode.LIST; |
254 } | 253 } |
255 return listData; | 254 return listData; |
256 } | 255 } |
257 | 256 |
258 /** | 257 /** |
259 * Gets the default instance of the message stored in the list view of this | 258 * Gets the default instance of the message stored in the list view of this |
260 * map field. | 259 * map field. |
261 */ | 260 */ |
262 Message getMapEntryMessageDefaultInstance() { | 261 Message getMapEntryMessageDefaultInstance() { |
263 return converter.getMessageDefaultInstance(); | 262 return converter.getMessageDefaultInstance(); |
264 } | 263 } |
265 | 264 |
266 /** | 265 /** |
267 * Makes this list immutable. All subsequent modifications will throw an | 266 * Makes this list immutable. All subsequent modifications will throw an |
268 * {@link UnsupportedOperationException}. | 267 * {@link UnsupportedOperationException}. |
269 */ | 268 */ |
270 public void makeImmutable() { | 269 public void makeImmutable() { |
271 isMutable = false; | 270 isMutable = false; |
272 } | 271 } |
273 | 272 |
274 /** | 273 /** |
275 * Returns whether this field can be modified. | 274 * Returns whether this field can be modified. |
276 */ | 275 */ |
277 public boolean isMutable() { | 276 public boolean isMutable() { |
278 return isMutable; | 277 return isMutable; |
279 } | 278 } |
280 | 279 |
281 /* (non-Javadoc) | 280 /* (non-Javadoc) |
282 * @see com.google.protobuf.MutabilityOracle#ensureMutable() | 281 * @see com.google.protobuf.MutabilityOracle#ensureMutable() |
283 */ | 282 */ |
284 @Override | 283 @Override |
285 public void ensureMutable() { | 284 public void ensureMutable() { |
286 if (!isMutable()) { | 285 if (!isMutable()) { |
287 throw new UnsupportedOperationException(); | 286 throw new UnsupportedOperationException(); |
288 } | 287 } |
289 } | 288 } |
290 | |
291 /** | |
292 * An internal map that checks for mutability before delegating. | |
293 */ | |
294 private static class MutatabilityAwareMap<K, V> implements Map<K, V> { | |
295 private final MutabilityOracle mutabilityOracle; | |
296 private final Map<K, V> delegate; | |
297 | |
298 MutatabilityAwareMap(MutabilityOracle mutabilityOracle, Map<K, V> delegate)
{ | |
299 this.mutabilityOracle = mutabilityOracle; | |
300 this.delegate = delegate; | |
301 } | |
302 | |
303 @Override | |
304 public int size() { | |
305 return delegate.size(); | |
306 } | |
307 | |
308 @Override | |
309 public boolean isEmpty() { | |
310 return delegate.isEmpty(); | |
311 } | |
312 | |
313 @Override | |
314 public boolean containsKey(Object key) { | |
315 return delegate.containsKey(key); | |
316 } | |
317 | |
318 @Override | |
319 public boolean containsValue(Object value) { | |
320 return delegate.containsValue(value); | |
321 } | |
322 | |
323 @Override | |
324 public V get(Object key) { | |
325 return delegate.get(key); | |
326 } | |
327 | |
328 @Override | |
329 public V put(K key, V value) { | |
330 mutabilityOracle.ensureMutable(); | |
331 return delegate.put(key, value); | |
332 } | |
333 | |
334 @Override | |
335 public V remove(Object key) { | |
336 mutabilityOracle.ensureMutable(); | |
337 return delegate.remove(key); | |
338 } | |
339 | |
340 @Override | |
341 public void putAll(Map<? extends K, ? extends V> m) { | |
342 mutabilityOracle.ensureMutable(); | |
343 delegate.putAll(m); | |
344 } | |
345 | |
346 @Override | |
347 public void clear() { | |
348 mutabilityOracle.ensureMutable(); | |
349 delegate.clear(); | |
350 } | |
351 | |
352 @Override | |
353 public Set<K> keySet() { | |
354 return new MutatabilityAwareSet<K>(mutabilityOracle, delegate.keySet()); | |
355 } | |
356 | |
357 @Override | |
358 public Collection<V> values() { | |
359 return new MutatabilityAwareCollection<V>(mutabilityOracle, delegate.value
s()); | |
360 } | |
361 | |
362 @Override | |
363 public Set<java.util.Map.Entry<K, V>> entrySet() { | |
364 return new MutatabilityAwareSet<Entry<K, V>>(mutabilityOracle, delegate.en
trySet()); | |
365 } | |
366 | |
367 @Override | |
368 public boolean equals(Object o) { | |
369 return delegate.equals(o); | |
370 } | |
371 | |
372 @Override | |
373 public int hashCode() { | |
374 return delegate.hashCode(); | |
375 } | |
376 | |
377 @Override | |
378 public String toString() { | |
379 return delegate.toString(); | |
380 } | |
381 | |
382 /** | |
383 * An internal collection that checks for mutability before delegating. | |
384 */ | |
385 private static class MutatabilityAwareCollection<E> implements Collection<E>
{ | |
386 private final MutabilityOracle mutabilityOracle; | |
387 private final Collection<E> delegate; | |
388 | |
389 MutatabilityAwareCollection(MutabilityOracle mutabilityOracle, Collection<
E> delegate) { | |
390 this.mutabilityOracle = mutabilityOracle; | |
391 this.delegate = delegate; | |
392 } | |
393 | |
394 @Override | |
395 public int size() { | |
396 return delegate.size(); | |
397 } | |
398 | |
399 @Override | |
400 public boolean isEmpty() { | |
401 return delegate.isEmpty(); | |
402 } | |
403 | |
404 @Override | |
405 public boolean contains(Object o) { | |
406 return delegate.contains(o); | |
407 } | |
408 | |
409 @Override | |
410 public Iterator<E> iterator() { | |
411 return new MutatabilityAwareIterator<E>(mutabilityOracle, delegate.itera
tor()); | |
412 } | |
413 | |
414 @Override | |
415 public Object[] toArray() { | |
416 return delegate.toArray(); | |
417 } | |
418 | |
419 @Override | |
420 public <T> T[] toArray(T[] a) { | |
421 return delegate.toArray(a); | |
422 } | |
423 | |
424 @Override | |
425 public boolean add(E e) { | |
426 // Unsupported operation in the delegate. | |
427 throw new UnsupportedOperationException(); | |
428 } | |
429 | |
430 @Override | |
431 public boolean remove(Object o) { | |
432 mutabilityOracle.ensureMutable(); | |
433 return delegate.remove(o); | |
434 } | |
435 | |
436 @Override | |
437 public boolean containsAll(Collection<?> c) { | |
438 return delegate.containsAll(c); | |
439 } | |
440 | |
441 @Override | |
442 public boolean addAll(Collection<? extends E> c) { | |
443 // Unsupported operation in the delegate. | |
444 throw new UnsupportedOperationException(); | |
445 } | |
446 | |
447 @Override | |
448 public boolean removeAll(Collection<?> c) { | |
449 mutabilityOracle.ensureMutable(); | |
450 return delegate.removeAll(c); | |
451 } | |
452 | |
453 @Override | |
454 public boolean retainAll(Collection<?> c) { | |
455 mutabilityOracle.ensureMutable(); | |
456 return delegate.retainAll(c); | |
457 } | |
458 | |
459 @Override | |
460 public void clear() { | |
461 mutabilityOracle.ensureMutable(); | |
462 delegate.clear(); | |
463 } | |
464 | |
465 @Override | |
466 public boolean equals(Object o) { | |
467 return delegate.equals(o); | |
468 } | |
469 | |
470 @Override | |
471 public int hashCode() { | |
472 return delegate.hashCode(); | |
473 } | |
474 | |
475 @Override | |
476 public String toString() { | |
477 return delegate.toString(); | |
478 } | |
479 } | |
480 | |
481 /** | |
482 * An internal set that checks for mutability before delegating. | |
483 */ | |
484 private static class MutatabilityAwareSet<E> implements Set<E> { | |
485 private final MutabilityOracle mutabilityOracle; | |
486 private final Set<E> delegate; | |
487 | |
488 MutatabilityAwareSet(MutabilityOracle mutabilityOracle, Set<E> delegate) { | |
489 this.mutabilityOracle = mutabilityOracle; | |
490 this.delegate = delegate; | |
491 } | |
492 | |
493 @Override | |
494 public int size() { | |
495 return delegate.size(); | |
496 } | |
497 | |
498 @Override | |
499 public boolean isEmpty() { | |
500 return delegate.isEmpty(); | |
501 } | |
502 | |
503 @Override | |
504 public boolean contains(Object o) { | |
505 return delegate.contains(o); | |
506 } | |
507 | |
508 @Override | |
509 public Iterator<E> iterator() { | |
510 return new MutatabilityAwareIterator<E>(mutabilityOracle, delegate.itera
tor()); | |
511 } | |
512 | |
513 @Override | |
514 public Object[] toArray() { | |
515 return delegate.toArray(); | |
516 } | |
517 | |
518 @Override | |
519 public <T> T[] toArray(T[] a) { | |
520 return delegate.toArray(a); | |
521 } | |
522 | |
523 @Override | |
524 public boolean add(E e) { | |
525 mutabilityOracle.ensureMutable(); | |
526 return delegate.add(e); | |
527 } | |
528 | |
529 @Override | |
530 public boolean remove(Object o) { | |
531 mutabilityOracle.ensureMutable(); | |
532 return delegate.remove(o); | |
533 } | |
534 | |
535 @Override | |
536 public boolean containsAll(Collection<?> c) { | |
537 return delegate.containsAll(c); | |
538 } | |
539 | |
540 @Override | |
541 public boolean addAll(Collection<? extends E> c) { | |
542 mutabilityOracle.ensureMutable(); | |
543 return delegate.addAll(c); | |
544 } | |
545 | |
546 @Override | |
547 public boolean retainAll(Collection<?> c) { | |
548 mutabilityOracle.ensureMutable(); | |
549 return delegate.retainAll(c); | |
550 } | |
551 | |
552 @Override | |
553 public boolean removeAll(Collection<?> c) { | |
554 mutabilityOracle.ensureMutable(); | |
555 return delegate.removeAll(c); | |
556 } | |
557 | |
558 @Override | |
559 public void clear() { | |
560 mutabilityOracle.ensureMutable(); | |
561 delegate.clear(); | |
562 } | |
563 | |
564 @Override | |
565 public boolean equals(Object o) { | |
566 return delegate.equals(o); | |
567 } | |
568 | |
569 @Override | |
570 public int hashCode() { | |
571 return delegate.hashCode(); | |
572 } | |
573 | |
574 @Override | |
575 public String toString() { | |
576 return delegate.toString(); | |
577 } | |
578 } | |
579 | |
580 /** | |
581 * An internal iterator that checks for mutability before delegating. | |
582 */ | |
583 private static class MutatabilityAwareIterator<E> implements Iterator<E> { | |
584 private final MutabilityOracle mutabilityOracle; | |
585 private final Iterator<E> delegate; | |
586 | |
587 MutatabilityAwareIterator(MutabilityOracle mutabilityOracle, Iterator<E> d
elegate) { | |
588 this.mutabilityOracle = mutabilityOracle; | |
589 this.delegate = delegate; | |
590 } | |
591 | |
592 @Override | |
593 public boolean hasNext() { | |
594 return delegate.hasNext(); | |
595 } | |
596 | |
597 @Override | |
598 public E next() { | |
599 return delegate.next(); | |
600 } | |
601 | |
602 @Override | |
603 public void remove() { | |
604 mutabilityOracle.ensureMutable(); | |
605 delegate.remove(); | |
606 } | |
607 | |
608 @Override | |
609 public boolean equals(Object obj) { | |
610 return delegate.equals(obj); | |
611 } | |
612 | |
613 @Override | |
614 public int hashCode() { | |
615 return delegate.hashCode(); | |
616 } | |
617 | |
618 @Override | |
619 public String toString() { | |
620 return delegate.toString(); | |
621 } | |
622 } | |
623 } | |
624 } | 289 } |
OLD | NEW |