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