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 | |
35 import java.util.ArrayList; | 33 import java.util.ArrayList; |
| 34 import java.util.Collection; |
36 import java.util.Collections; | 35 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; |
40 | 41 |
41 /** | 42 /** |
42 * Internal representation of map fields in generated messages. | 43 * Internal representation of map fields in generated messages. |
43 * | 44 * |
44 * This class supports accessing the map field as a {@link Map} to be used in | 45 * This class supports accessing the map field as a {@link Map} to be used in |
45 * generated API and also supports accessing the field as a {@link List} to be | 46 * generated API and also supports accessing the field as a {@link List} to be |
46 * used in reflection API. It keeps track of where the data is currently stored | 47 * used in reflection API. It keeps track of where the data is currently stored |
47 * and do necessary conversions between map and list. | 48 * and do necessary conversions between map and list. |
48 * | 49 * |
49 * This class is a protobuf implementation detail. Users shouldn't use this | 50 * This class is a protobuf implementation detail. Users shouldn't use this |
50 * class directly. | 51 * class directly. |
51 * | 52 * |
52 * THREAD-SAFETY NOTE: Read-only access is thread-safe. Users can call getMap() | 53 * THREAD-SAFETY NOTE: Read-only access is thread-safe. Users can call getMap() |
53 * and getList() concurrently in multiple threads. If write-access is needed, | 54 * and getList() concurrently in multiple threads. If write-access is needed, |
54 * all access must be synchronized. | 55 * all access must be synchronized. |
55 */ | 56 */ |
56 public class MapField<K, V> implements MutabilityOracle { | 57 public class MapField<K, V> implements MutabilityOracle { |
57 /** | 58 /** |
58 * Indicates where the data of this map field is currently stored. | 59 * Indicates where the data of this map field is currently stored. |
59 * | 60 * |
60 * MAP: Data is stored in mapData. | 61 * MAP: Data is stored in mapData. |
61 * LIST: Data is stored in listData. | 62 * LIST: Data is stored in listData. |
62 * BOTH: mapData and listData have the same data. | 63 * BOTH: mapData and listData have the same data. |
63 * | 64 * |
64 * When the map field is accessed (through generated API or reflection API), | 65 * When the map field is accessed (through generated API or reflection API), |
65 * it will shift between these 3 modes: | 66 * it will shift between these 3 modes: |
66 * | 67 * |
67 * getMap() getList() getMutableMap() getMutableList() | 68 * getMap() getList() getMutableMap() getMutableList() |
68 * MAP MAP BOTH MAP LIST | 69 * MAP MAP BOTH MAP LIST |
69 * LIST BOTH LIST MAP LIST | 70 * LIST BOTH LIST MAP LIST |
70 * BOTH BOTH BOTH MAP LIST | 71 * BOTH BOTH BOTH MAP LIST |
71 * | 72 * |
72 * As the map field changes its mode, the list/map reference returned in a | 73 * As the map field changes its mode, the list/map reference returned in a |
73 * previous method call may be invalidated. | 74 * previous method call may be invalidated. |
74 */ | 75 */ |
75 private enum StorageMode {MAP, LIST, BOTH} | 76 private enum StorageMode {MAP, LIST, BOTH} |
76 | 77 |
77 private volatile boolean isMutable; | 78 private volatile boolean isMutable; |
78 private volatile StorageMode mode; | 79 private volatile StorageMode mode; |
79 private MutatabilityAwareMap<K, V> mapData; | 80 private MutatabilityAwareMap<K, V> mapData; |
80 private List<Message> listData; | 81 private List<Message> listData; |
81 | 82 |
82 // Convert between a map entry Message and a key-value pair. | 83 // Convert between a map entry Message and a key-value pair. |
83 private static interface Converter<K, V> { | 84 private static interface Converter<K, V> { |
84 Message convertKeyAndValueToMessage(K key, V value); | 85 Message convertKeyAndValueToMessage(K key, V value); |
85 void convertMessageToKeyAndValue(Message message, Map<K, V> map); | 86 void convertMessageToKeyAndValue(Message message, Map<K, V> map); |
86 | 87 |
87 Message getMessageDefaultInstance(); | 88 Message getMessageDefaultInstance(); |
88 } | 89 } |
89 | 90 |
90 private static class ImmutableMessageConverter<K, V> implements Converter<K, V
> { | 91 private static class ImmutableMessageConverter<K, V> implements Converter<K, V
> { |
91 private final MapEntry<K, V> defaultEntry; | 92 private final MapEntry<K, V> defaultEntry; |
92 public ImmutableMessageConverter(MapEntry<K, V> defaultEntry) { | 93 public ImmutableMessageConverter(MapEntry<K, V> defaultEntry) { |
93 this.defaultEntry = defaultEntry; | 94 this.defaultEntry = defaultEntry; |
94 } | 95 } |
95 | 96 |
96 @Override | 97 @Override |
97 public Message convertKeyAndValueToMessage(K key, V value) { | 98 public Message convertKeyAndValueToMessage(K key, V value) { |
98 return defaultEntry.newBuilderForType().setKey(key).setValue(value).buildP
artial(); | 99 return defaultEntry.newBuilderForType().setKey(key).setValue(value).buildP
artial(); |
99 } | 100 } |
100 | 101 |
101 @Override | 102 @Override |
102 public void convertMessageToKeyAndValue(Message message, Map<K, V> map) { | 103 public void convertMessageToKeyAndValue(Message message, Map<K, V> map) { |
103 MapEntry<K, V> entry = (MapEntry<K, V>) message; | 104 MapEntry<K, V> entry = (MapEntry<K, V>) message; |
104 map.put(entry.getKey(), entry.getValue()); | 105 map.put(entry.getKey(), entry.getValue()); |
105 } | 106 } |
106 | 107 |
107 @Override | 108 @Override |
108 public Message getMessageDefaultInstance() { | 109 public Message getMessageDefaultInstance() { |
109 return defaultEntry; | 110 return defaultEntry; |
110 } | 111 } |
111 } | 112 } |
112 | 113 |
113 | 114 |
114 private final Converter<K, V> converter; | 115 private final Converter<K, V> converter; |
115 | 116 |
116 private MapField( | 117 private MapField( |
117 Converter<K, V> converter, | 118 Converter<K, V> converter, |
118 StorageMode mode, | 119 StorageMode mode, |
119 Map<K, V> mapData) { | 120 Map<K, V> mapData) { |
120 this.converter = converter; | 121 this.converter = converter; |
121 this.isMutable = true; | 122 this.isMutable = true; |
122 this.mode = mode; | 123 this.mode = mode; |
123 this.mapData = new MutatabilityAwareMap<K, V>(this, mapData); | 124 this.mapData = new MutatabilityAwareMap<K, V>(this, mapData); |
124 this.listData = null; | 125 this.listData = null; |
125 } | 126 } |
126 | 127 |
127 private MapField( | 128 private MapField( |
128 MapEntry<K, V> defaultEntry, | 129 MapEntry<K, V> defaultEntry, |
129 StorageMode mode, | 130 StorageMode mode, |
130 Map<K, V> mapData) { | 131 Map<K, V> mapData) { |
131 this(new ImmutableMessageConverter<K, V>(defaultEntry), mode, mapData); | 132 this(new ImmutableMessageConverter<K, V>(defaultEntry), mode, mapData); |
132 } | 133 } |
133 | 134 |
134 | 135 |
135 /** Returns an immutable empty MapField. */ | 136 /** Returns an immutable empty MapField. */ |
136 public static <K, V> MapField<K, V> emptyMapField( | 137 public static <K, V> MapField<K, V> emptyMapField( |
137 MapEntry<K, V> defaultEntry) { | 138 MapEntry<K, V> defaultEntry) { |
138 return new MapField<K, V>( | 139 return new MapField<K, V>( |
139 defaultEntry, StorageMode.MAP, Collections.<K, V>emptyMap()); | 140 defaultEntry, StorageMode.MAP, Collections.<K, V>emptyMap()); |
140 } | 141 } |
141 | 142 |
142 | 143 |
143 /** Creates a new mutable empty MapField. */ | 144 /** Creates a new mutable empty MapField. */ |
144 public static <K, V> MapField<K, V> newMapField(MapEntry<K, V> defaultEntry) { | 145 public static <K, V> MapField<K, V> newMapField(MapEntry<K, V> defaultEntry) { |
145 return new MapField<K, V>( | 146 return new MapField<K, V>( |
146 defaultEntry, StorageMode.MAP, new LinkedHashMap<K, V>()); | 147 defaultEntry, StorageMode.MAP, new LinkedHashMap<K, V>()); |
147 } | 148 } |
148 | 149 |
149 | 150 |
150 private Message convertKeyAndValueToMessage(K key, V value) { | 151 private Message convertKeyAndValueToMessage(K key, V value) { |
151 return converter.convertKeyAndValueToMessage(key, value); | 152 return converter.convertKeyAndValueToMessage(key, value); |
152 } | 153 } |
153 | 154 |
154 @SuppressWarnings("unchecked") | 155 @SuppressWarnings("unchecked") |
155 private void convertMessageToKeyAndValue(Message message, Map<K, V> map) { | 156 private void convertMessageToKeyAndValue(Message message, Map<K, V> map) { |
156 converter.convertMessageToKeyAndValue(message, map); | 157 converter.convertMessageToKeyAndValue(message, map); |
157 } | 158 } |
158 | 159 |
159 private List<Message> convertMapToList(MutatabilityAwareMap<K, V> mapData) { | 160 private List<Message> convertMapToList(MutatabilityAwareMap<K, V> mapData) { |
160 List<Message> listData = new ArrayList<Message>(); | 161 List<Message> listData = new ArrayList<Message>(); |
161 for (Map.Entry<K, V> entry : mapData.entrySet()) { | 162 for (Map.Entry<K, V> entry : mapData.entrySet()) { |
162 listData.add( | 163 listData.add( |
163 convertKeyAndValueToMessage( | 164 convertKeyAndValueToMessage( |
164 entry.getKey(), entry.getValue())); | 165 entry.getKey(), entry.getValue())); |
165 } | 166 } |
166 return listData; | 167 return listData; |
167 } | 168 } |
168 | 169 |
169 private MutatabilityAwareMap<K, V> convertListToMap(List<Message> listData) { | 170 private MutatabilityAwareMap<K, V> convertListToMap(List<Message> listData) { |
170 Map<K, V> mapData = new LinkedHashMap<K, V>(); | 171 Map<K, V> mapData = new LinkedHashMap<K, V>(); |
171 for (Message item : listData) { | 172 for (Message item : listData) { |
172 convertMessageToKeyAndValue(item, mapData); | 173 convertMessageToKeyAndValue(item, mapData); |
173 } | 174 } |
174 return new MutatabilityAwareMap<K, V>(this, mapData); | 175 return new MutatabilityAwareMap<K, V>(this, mapData); |
175 } | 176 } |
176 | 177 |
177 /** Returns the content of this MapField as a read-only Map. */ | 178 /** Returns the content of this MapField as a read-only Map. */ |
178 public Map<K, V> getMap() { | 179 public Map<K, V> getMap() { |
179 if (mode == StorageMode.LIST) { | 180 if (mode == StorageMode.LIST) { |
180 synchronized (this) { | 181 synchronized (this) { |
181 if (mode == StorageMode.LIST) { | 182 if (mode == StorageMode.LIST) { |
182 mapData = convertListToMap(listData); | 183 mapData = convertListToMap(listData); |
183 mode = StorageMode.BOTH; | 184 mode = StorageMode.BOTH; |
184 } | 185 } |
185 } | 186 } |
186 } | 187 } |
187 return Collections.unmodifiableMap(mapData); | 188 return Collections.unmodifiableMap(mapData); |
188 } | 189 } |
189 | 190 |
190 /** Gets a mutable Map view of this MapField. */ | 191 /** Gets a mutable Map view of this MapField. */ |
191 public Map<K, V> getMutableMap() { | 192 public Map<K, V> getMutableMap() { |
192 if (mode != StorageMode.MAP) { | 193 if (mode != StorageMode.MAP) { |
193 if (mode == StorageMode.LIST) { | 194 if (mode == StorageMode.LIST) { |
194 mapData = convertListToMap(listData); | 195 mapData = convertListToMap(listData); |
195 } | 196 } |
196 listData = null; | 197 listData = null; |
197 mode = StorageMode.MAP; | 198 mode = StorageMode.MAP; |
198 } | 199 } |
199 return mapData; | 200 return mapData; |
200 } | 201 } |
201 | 202 |
202 public void mergeFrom(MapField<K, V> other) { | 203 public void mergeFrom(MapField<K, V> other) { |
203 getMutableMap().putAll(MapFieldLite.copy(other.getMap())); | 204 getMutableMap().putAll(MapFieldLite.copy(other.getMap())); |
204 } | 205 } |
205 | 206 |
206 public void clear() { | 207 public void clear() { |
207 mapData = new MutatabilityAwareMap<K, V>(this, new LinkedHashMap<K, V>()); | 208 mapData = new MutatabilityAwareMap<K, V>(this, new LinkedHashMap<K, V>()); |
208 mode = StorageMode.MAP; | 209 mode = StorageMode.MAP; |
209 } | 210 } |
210 | 211 |
211 @SuppressWarnings("unchecked") | 212 @SuppressWarnings("unchecked") |
212 @Override | 213 @Override |
213 public boolean equals(Object object) { | 214 public boolean equals(Object object) { |
214 if (!(object instanceof MapField)) { | 215 if (!(object instanceof MapField)) { |
215 return false; | 216 return false; |
216 } | 217 } |
217 MapField<K, V> other = (MapField<K, V>) object; | 218 MapField<K, V> other = (MapField<K, V>) object; |
218 return MapFieldLite.<K, V>equals(getMap(), other.getMap()); | 219 return MapFieldLite.<K, V>equals(getMap(), other.getMap()); |
219 } | 220 } |
220 | 221 |
221 @Override | 222 @Override |
222 public int hashCode() { | 223 public int hashCode() { |
223 return MapFieldLite.<K, V>calculateHashCodeForMap(getMap()); | 224 return MapFieldLite.<K, V>calculateHashCodeForMap(getMap()); |
224 } | 225 } |
225 | 226 |
226 /** Returns a deep copy of this MapField. */ | 227 /** Returns a deep copy of this MapField. */ |
227 public MapField<K, V> copy() { | 228 public MapField<K, V> copy() { |
228 return new MapField<K, V>( | 229 return new MapField<K, V>( |
229 converter, StorageMode.MAP, MapFieldLite.copy(getMap())); | 230 converter, StorageMode.MAP, MapFieldLite.copy(getMap())); |
230 } | 231 } |
231 | 232 |
232 /** Gets the content of this MapField as a read-only List. */ | 233 /** Gets the content of this MapField as a read-only List. */ |
233 List<Message> getList() { | 234 List<Message> getList() { |
234 if (mode == StorageMode.MAP) { | 235 if (mode == StorageMode.MAP) { |
235 synchronized (this) { | 236 synchronized (this) { |
236 if (mode == StorageMode.MAP) { | 237 if (mode == StorageMode.MAP) { |
237 listData = convertMapToList(mapData); | 238 listData = convertMapToList(mapData); |
238 mode = StorageMode.BOTH; | 239 mode = StorageMode.BOTH; |
239 } | 240 } |
240 } | 241 } |
241 } | 242 } |
242 return Collections.unmodifiableList(listData); | 243 return Collections.unmodifiableList(listData); |
243 } | 244 } |
244 | 245 |
245 /** Gets a mutable List view of this MapField. */ | 246 /** Gets a mutable List view of this MapField. */ |
246 List<Message> getMutableList() { | 247 List<Message> getMutableList() { |
247 if (mode != StorageMode.LIST) { | 248 if (mode != StorageMode.LIST) { |
248 if (mode == StorageMode.MAP) { | 249 if (mode == StorageMode.MAP) { |
249 listData = convertMapToList(mapData); | 250 listData = convertMapToList(mapData); |
250 } | 251 } |
251 mapData = null; | 252 mapData = null; |
252 mode = StorageMode.LIST; | 253 mode = StorageMode.LIST; |
253 } | 254 } |
254 return listData; | 255 return listData; |
255 } | 256 } |
256 | 257 |
257 /** | 258 /** |
258 * Gets the default instance of the message stored in the list view of this | 259 * Gets the default instance of the message stored in the list view of this |
259 * map field. | 260 * map field. |
260 */ | 261 */ |
261 Message getMapEntryMessageDefaultInstance() { | 262 Message getMapEntryMessageDefaultInstance() { |
262 return converter.getMessageDefaultInstance(); | 263 return converter.getMessageDefaultInstance(); |
263 } | 264 } |
264 | 265 |
265 /** | 266 /** |
266 * Makes this list immutable. All subsequent modifications will throw an | 267 * Makes this list immutable. All subsequent modifications will throw an |
267 * {@link UnsupportedOperationException}. | 268 * {@link UnsupportedOperationException}. |
268 */ | 269 */ |
269 public void makeImmutable() { | 270 public void makeImmutable() { |
270 isMutable = false; | 271 isMutable = false; |
271 } | 272 } |
272 | 273 |
273 /** | 274 /** |
274 * Returns whether this field can be modified. | 275 * Returns whether this field can be modified. |
275 */ | 276 */ |
276 public boolean isMutable() { | 277 public boolean isMutable() { |
277 return isMutable; | 278 return isMutable; |
278 } | 279 } |
279 | 280 |
280 /* (non-Javadoc) | 281 /* (non-Javadoc) |
281 * @see com.google.protobuf.MutabilityOracle#ensureMutable() | 282 * @see com.google.protobuf.MutabilityOracle#ensureMutable() |
282 */ | 283 */ |
283 @Override | 284 @Override |
284 public void ensureMutable() { | 285 public void ensureMutable() { |
285 if (!isMutable()) { | 286 if (!isMutable()) { |
286 throw new UnsupportedOperationException(); | 287 throw new UnsupportedOperationException(); |
287 } | 288 } |
288 } | 289 } |
| 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 } |
289 } | 624 } |
OLD | NEW |