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 com.google.protobuf.Internal.EnumLite; 34 35 import java.util.Arrays; 36 import java.util.Collection; 37 import java.util.Collections; 38 import java.util.Iterator; 39 import java.util.LinkedHashMap; 40 import java.util.Map; 41 import java.util.Set; 42 43 /** 44 * Internal representation of map fields in generated lite-runtime messages. 45 * 46 * This class is a protobuf implementation detail. Users shouldn't use this 47 * class directly. 48 */ 49 public final class MapFieldLite<K, V> implements MutabilityOracle { 50 private MutatabilityAwareMap<K, V> mapData; 51 private boolean isMutable; 52 MapFieldLite(Map<K, V> mapData)53 private MapFieldLite(Map<K, V> mapData) { 54 this.mapData = new MutatabilityAwareMap<K, V>(this, mapData); 55 this.isMutable = true; 56 } 57 58 @SuppressWarnings({"rawtypes", "unchecked"}) 59 private static final MapFieldLite EMPTY_MAP_FIELD = 60 new MapFieldLite(Collections.emptyMap()); 61 static { EMPTY_MAP_FIELD.makeImmutable()62 EMPTY_MAP_FIELD.makeImmutable(); 63 } 64 65 /** Returns an singleton immutable empty MapFieldLite instance. */ 66 @SuppressWarnings({"unchecked", "cast"}) emptyMapField()67 public static <K, V> MapFieldLite<K, V> emptyMapField() { 68 return (MapFieldLite<K, V>) EMPTY_MAP_FIELD; 69 } 70 71 /** Creates a new MapFieldLite instance. */ newMapField()72 public static <K, V> MapFieldLite<K, V> newMapField() { 73 return new MapFieldLite<K, V>(new LinkedHashMap<K, V>()); 74 } 75 76 /** Gets the content of this MapField as a read-only Map. */ getMap()77 public Map<K, V> getMap() { 78 return Collections.unmodifiableMap(mapData); 79 } 80 81 /** Gets a mutable Map view of this MapField. */ getMutableMap()82 public Map<K, V> getMutableMap() { 83 return mapData; 84 } 85 mergeFrom(MapFieldLite<K, V> other)86 public void mergeFrom(MapFieldLite<K, V> other) { 87 mapData.putAll(copy(other.mapData)); 88 } 89 clear()90 public void clear() { 91 mapData.clear(); 92 } 93 equals(Object a, Object b)94 private static boolean equals(Object a, Object b) { 95 if (a instanceof byte[] && b instanceof byte[]) { 96 return Arrays.equals((byte[]) a, (byte[]) b); 97 } 98 return a.equals(b); 99 } 100 101 /** 102 * Checks whether two {@link Map}s are equal. We don't use the default equals 103 * method of {@link Map} because it compares by identity not by content for 104 * byte arrays. 105 */ equals(Map<K, V> a, Map<K, V> b)106 static <K, V> boolean equals(Map<K, V> a, Map<K, V> b) { 107 if (a == b) { 108 return true; 109 } 110 if (a.size() != b.size()) { 111 return false; 112 } 113 for (Map.Entry<K, V> entry : a.entrySet()) { 114 if (!b.containsKey(entry.getKey())) { 115 return false; 116 } 117 if (!equals(entry.getValue(), b.get(entry.getKey()))) { 118 return false; 119 } 120 } 121 return true; 122 } 123 124 /** 125 * Checks whether two map fields are equal. 126 */ 127 @SuppressWarnings("unchecked") 128 @Override equals(Object object)129 public boolean equals(Object object) { 130 if (!(object instanceof MapFieldLite)) { 131 return false; 132 } 133 MapFieldLite<K, V> other = (MapFieldLite<K, V>) object; 134 return equals(mapData, other.mapData); 135 } 136 calculateHashCodeForObject(Object a)137 private static int calculateHashCodeForObject(Object a) { 138 if (a instanceof byte[]) { 139 return Internal.hashCode((byte[]) a); 140 } 141 // Enums should be stored as integers internally. 142 if (a instanceof EnumLite) { 143 throw new UnsupportedOperationException(); 144 } 145 return a.hashCode(); 146 } 147 148 /** 149 * Calculates the hash code for a {@link Map}. We don't use the default hash 150 * code method of {@link Map} because for byte arrays and protobuf enums it 151 * use {@link Object#hashCode()}. 152 */ calculateHashCodeForMap(Map<K, V> a)153 static <K, V> int calculateHashCodeForMap(Map<K, V> a) { 154 int result = 0; 155 for (Map.Entry<K, V> entry : a.entrySet()) { 156 result += calculateHashCodeForObject(entry.getKey()) 157 ^ calculateHashCodeForObject(entry.getValue()); 158 } 159 return result; 160 } 161 162 @Override hashCode()163 public int hashCode() { 164 return calculateHashCodeForMap(mapData); 165 } 166 copy(Object object)167 private static Object copy(Object object) { 168 if (object instanceof byte[]) { 169 byte[] data = (byte[]) object; 170 return Arrays.copyOf(data, data.length); 171 } 172 return object; 173 } 174 175 /** 176 * Makes a deep copy of a {@link Map}. Immutable objects in the map will be 177 * shared (e.g., integers, strings, immutable messages) and mutable ones will 178 * have a copy (e.g., byte arrays, mutable messages). 179 */ 180 @SuppressWarnings("unchecked") copy(Map<K, V> map)181 static <K, V> Map<K, V> copy(Map<K, V> map) { 182 Map<K, V> result = new LinkedHashMap<K, V>(); 183 for (Map.Entry<K, V> entry : map.entrySet()) { 184 result.put(entry.getKey(), (V) copy(entry.getValue())); 185 } 186 return result; 187 } 188 189 /** Returns a deep copy of this map field. */ copy()190 public MapFieldLite<K, V> copy() { 191 return new MapFieldLite<K, V>(copy(mapData)); 192 } 193 194 /** 195 * Makes this field immutable. All subsequent modifications will throw an 196 * {@link UnsupportedOperationException}. 197 */ makeImmutable()198 public void makeImmutable() { 199 isMutable = false; 200 } 201 202 /** 203 * Returns whether this field can be modified. 204 */ isMutable()205 public boolean isMutable() { 206 return isMutable; 207 } 208 209 @Override ensureMutable()210 public void ensureMutable() { 211 if (!isMutable()) { 212 throw new UnsupportedOperationException(); 213 } 214 } 215 216 /** 217 * An internal map that checks for mutability before delegating. 218 */ 219 static class MutatabilityAwareMap<K, V> implements Map<K, V> { 220 private final MutabilityOracle mutabilityOracle; 221 private final Map<K, V> delegate; 222 MutatabilityAwareMap(MutabilityOracle mutabilityOracle, Map<K, V> delegate)223 MutatabilityAwareMap(MutabilityOracle mutabilityOracle, Map<K, V> delegate) { 224 this.mutabilityOracle = mutabilityOracle; 225 this.delegate = delegate; 226 } 227 228 @Override size()229 public int size() { 230 return delegate.size(); 231 } 232 233 @Override isEmpty()234 public boolean isEmpty() { 235 return delegate.isEmpty(); 236 } 237 238 @Override containsKey(Object key)239 public boolean containsKey(Object key) { 240 return delegate.containsKey(key); 241 } 242 243 @Override containsValue(Object value)244 public boolean containsValue(Object value) { 245 return delegate.containsValue(value); 246 } 247 248 @Override get(Object key)249 public V get(Object key) { 250 return delegate.get(key); 251 } 252 253 @Override put(K key, V value)254 public V put(K key, V value) { 255 mutabilityOracle.ensureMutable(); 256 return delegate.put(key, value); 257 } 258 259 @Override remove(Object key)260 public V remove(Object key) { 261 mutabilityOracle.ensureMutable(); 262 return delegate.remove(key); 263 } 264 265 @Override putAll(Map<? extends K, ? extends V> m)266 public void putAll(Map<? extends K, ? extends V> m) { 267 mutabilityOracle.ensureMutable(); 268 delegate.putAll(m); 269 } 270 271 @Override clear()272 public void clear() { 273 mutabilityOracle.ensureMutable(); 274 delegate.clear(); 275 } 276 277 @Override keySet()278 public Set<K> keySet() { 279 return new MutatabilityAwareSet<K>(mutabilityOracle, delegate.keySet()); 280 } 281 282 @Override values()283 public Collection<V> values() { 284 return new MutatabilityAwareCollection<V>(mutabilityOracle, delegate.values()); 285 } 286 287 @Override entrySet()288 public Set<java.util.Map.Entry<K, V>> entrySet() { 289 return new MutatabilityAwareSet<Entry<K, V>>(mutabilityOracle, delegate.entrySet()); 290 } 291 292 @Override equals(Object o)293 public boolean equals(Object o) { 294 return delegate.equals(o); 295 } 296 297 @Override hashCode()298 public int hashCode() { 299 return delegate.hashCode(); 300 } 301 302 @Override toString()303 public String toString() { 304 return delegate.toString(); 305 } 306 } 307 308 /** 309 * An internal collection that checks for mutability before delegating. 310 */ 311 private static class MutatabilityAwareCollection<E> implements Collection<E> { 312 private final MutabilityOracle mutabilityOracle; 313 private final Collection<E> delegate; 314 MutatabilityAwareCollection(MutabilityOracle mutabilityOracle, Collection<E> delegate)315 MutatabilityAwareCollection(MutabilityOracle mutabilityOracle, Collection<E> delegate) { 316 this.mutabilityOracle = mutabilityOracle; 317 this.delegate = delegate; 318 } 319 320 @Override size()321 public int size() { 322 return delegate.size(); 323 } 324 325 @Override isEmpty()326 public boolean isEmpty() { 327 return delegate.isEmpty(); 328 } 329 330 @Override contains(Object o)331 public boolean contains(Object o) { 332 return delegate.contains(o); 333 } 334 335 @Override iterator()336 public Iterator<E> iterator() { 337 return new MutatabilityAwareIterator<E>(mutabilityOracle, delegate.iterator()); 338 } 339 340 @Override toArray()341 public Object[] toArray() { 342 return delegate.toArray(); 343 } 344 345 @Override toArray(T[] a)346 public <T> T[] toArray(T[] a) { 347 return delegate.toArray(a); 348 } 349 350 @Override add(E e)351 public boolean add(E e) { 352 // Unsupported operation in the delegate. 353 throw new UnsupportedOperationException(); 354 } 355 356 @Override remove(Object o)357 public boolean remove(Object o) { 358 mutabilityOracle.ensureMutable(); 359 return delegate.remove(o); 360 } 361 362 @Override containsAll(Collection<?> c)363 public boolean containsAll(Collection<?> c) { 364 return delegate.containsAll(c); 365 } 366 367 @Override addAll(Collection<? extends E> c)368 public boolean addAll(Collection<? extends E> c) { 369 // Unsupported operation in the delegate. 370 throw new UnsupportedOperationException(); 371 } 372 373 @Override removeAll(Collection<?> c)374 public boolean removeAll(Collection<?> c) { 375 mutabilityOracle.ensureMutable(); 376 return delegate.removeAll(c); 377 } 378 379 @Override retainAll(Collection<?> c)380 public boolean retainAll(Collection<?> c) { 381 mutabilityOracle.ensureMutable(); 382 return delegate.retainAll(c); 383 } 384 385 @Override clear()386 public void clear() { 387 mutabilityOracle.ensureMutable(); 388 delegate.clear(); 389 } 390 391 @Override equals(Object o)392 public boolean equals(Object o) { 393 return delegate.equals(o); 394 } 395 396 @Override hashCode()397 public int hashCode() { 398 return delegate.hashCode(); 399 } 400 401 @Override toString()402 public String toString() { 403 return delegate.toString(); 404 } 405 } 406 407 /** 408 * An internal set that checks for mutability before delegating. 409 */ 410 private static class MutatabilityAwareSet<E> implements Set<E> { 411 private final MutabilityOracle mutabilityOracle; 412 private final Set<E> delegate; 413 MutatabilityAwareSet(MutabilityOracle mutabilityOracle, Set<E> delegate)414 MutatabilityAwareSet(MutabilityOracle mutabilityOracle, Set<E> delegate) { 415 this.mutabilityOracle = mutabilityOracle; 416 this.delegate = delegate; 417 } 418 419 @Override size()420 public int size() { 421 return delegate.size(); 422 } 423 424 @Override isEmpty()425 public boolean isEmpty() { 426 return delegate.isEmpty(); 427 } 428 429 @Override contains(Object o)430 public boolean contains(Object o) { 431 return delegate.contains(o); 432 } 433 434 @Override iterator()435 public Iterator<E> iterator() { 436 return new MutatabilityAwareIterator<E>(mutabilityOracle, delegate.iterator()); 437 } 438 439 @Override toArray()440 public Object[] toArray() { 441 return delegate.toArray(); 442 } 443 444 @Override toArray(T[] a)445 public <T> T[] toArray(T[] a) { 446 return delegate.toArray(a); 447 } 448 449 @Override add(E e)450 public boolean add(E e) { 451 mutabilityOracle.ensureMutable(); 452 return delegate.add(e); 453 } 454 455 @Override remove(Object o)456 public boolean remove(Object o) { 457 mutabilityOracle.ensureMutable(); 458 return delegate.remove(o); 459 } 460 461 @Override containsAll(Collection<?> c)462 public boolean containsAll(Collection<?> c) { 463 return delegate.containsAll(c); 464 } 465 466 @Override addAll(Collection<? extends E> c)467 public boolean addAll(Collection<? extends E> c) { 468 mutabilityOracle.ensureMutable(); 469 return delegate.addAll(c); 470 } 471 472 @Override retainAll(Collection<?> c)473 public boolean retainAll(Collection<?> c) { 474 mutabilityOracle.ensureMutable(); 475 return delegate.retainAll(c); 476 } 477 478 @Override removeAll(Collection<?> c)479 public boolean removeAll(Collection<?> c) { 480 mutabilityOracle.ensureMutable(); 481 return delegate.removeAll(c); 482 } 483 484 @Override clear()485 public void clear() { 486 mutabilityOracle.ensureMutable(); 487 delegate.clear(); 488 } 489 490 @Override equals(Object o)491 public boolean equals(Object o) { 492 return delegate.equals(o); 493 } 494 495 @Override hashCode()496 public int hashCode() { 497 return delegate.hashCode(); 498 } 499 500 @Override toString()501 public String toString() { 502 return delegate.toString(); 503 } 504 } 505 506 /** 507 * An internal iterator that checks for mutability before delegating. 508 */ 509 private static class MutatabilityAwareIterator<E> implements Iterator<E> { 510 private final MutabilityOracle mutabilityOracle; 511 private final Iterator<E> delegate; 512 MutatabilityAwareIterator(MutabilityOracle mutabilityOracle, Iterator<E> delegate)513 MutatabilityAwareIterator(MutabilityOracle mutabilityOracle, Iterator<E> delegate) { 514 this.mutabilityOracle = mutabilityOracle; 515 this.delegate = delegate; 516 } 517 518 @Override hasNext()519 public boolean hasNext() { 520 return delegate.hasNext(); 521 } 522 523 @Override next()524 public E next() { 525 return delegate.next(); 526 } 527 528 @Override remove()529 public void remove() { 530 mutabilityOracle.ensureMutable(); 531 delegate.remove(); 532 } 533 534 @Override equals(Object obj)535 public boolean equals(Object obj) { 536 return delegate.equals(obj); 537 } 538 539 @Override hashCode()540 public int hashCode() { 541 return delegate.hashCode(); 542 } 543 544 @Override toString()545 public String toString() { 546 return delegate.toString(); 547 } 548 } 549 } 550