Home | History | Annotate | Download | only in protobuf
      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 
     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 {
     62     EMPTY_MAP_FIELD.makeImmutable();
     63   }
     64 
     65   /** Returns an singleton immutable empty MapFieldLite instance. */
     66   @SuppressWarnings({"unchecked", "cast"})
     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. */
     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. */
     77   public Map<K, V> getMap() {
     78     return Collections.unmodifiableMap(mapData);
     79   }
     80 
     81   /** Gets a mutable Map view of this MapField. */
     82   public Map<K, V> getMutableMap() {
     83     return mapData;
     84   }
     85 
     86   public void mergeFrom(MapFieldLite<K, V> other) {
     87     mapData.putAll(copy(other.mapData));
     88   }
     89 
     90   public void clear() {
     91     mapData.clear();
     92   }
     93 
     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    */
    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
    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 
    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    */
    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
    163   public int hashCode() {
    164     return calculateHashCodeForMap(mapData);
    165   }
    166 
    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")
    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. */
    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    */
    198   public void makeImmutable() {
    199     isMutable = false;
    200   }
    201 
    202   /**
    203    * Returns whether this field can be modified.
    204    */
    205   public boolean isMutable() {
    206     return isMutable;
    207   }
    208 
    209   @Override
    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 
    223     MutatabilityAwareMap(MutabilityOracle mutabilityOracle, Map<K, V> delegate) {
    224       this.mutabilityOracle = mutabilityOracle;
    225       this.delegate = delegate;
    226     }
    227 
    228     @Override
    229     public int size() {
    230       return delegate.size();
    231     }
    232 
    233     @Override
    234     public boolean isEmpty() {
    235       return delegate.isEmpty();
    236     }
    237 
    238     @Override
    239     public boolean containsKey(Object key) {
    240       return delegate.containsKey(key);
    241     }
    242 
    243     @Override
    244     public boolean containsValue(Object value) {
    245       return delegate.containsValue(value);
    246     }
    247 
    248     @Override
    249     public V get(Object key) {
    250       return delegate.get(key);
    251     }
    252 
    253     @Override
    254     public V put(K key, V value) {
    255       mutabilityOracle.ensureMutable();
    256       return delegate.put(key, value);
    257     }
    258 
    259     @Override
    260     public V remove(Object key) {
    261       mutabilityOracle.ensureMutable();
    262       return delegate.remove(key);
    263     }
    264 
    265     @Override
    266     public void putAll(Map<? extends K, ? extends V> m) {
    267       mutabilityOracle.ensureMutable();
    268       delegate.putAll(m);
    269     }
    270 
    271     @Override
    272     public void clear() {
    273       mutabilityOracle.ensureMutable();
    274       delegate.clear();
    275     }
    276 
    277     @Override
    278     public Set<K> keySet() {
    279       return new MutatabilityAwareSet<K>(mutabilityOracle, delegate.keySet());
    280     }
    281 
    282     @Override
    283     public Collection<V> values() {
    284       return new MutatabilityAwareCollection<V>(mutabilityOracle, delegate.values());
    285     }
    286 
    287     @Override
    288     public Set<java.util.Map.Entry<K, V>> entrySet() {
    289       return new MutatabilityAwareSet<Entry<K, V>>(mutabilityOracle, delegate.entrySet());
    290     }
    291 
    292     @Override
    293     public boolean equals(Object o) {
    294       return delegate.equals(o);
    295     }
    296 
    297     @Override
    298     public int hashCode() {
    299       return delegate.hashCode();
    300     }
    301 
    302     @Override
    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 
    315     MutatabilityAwareCollection(MutabilityOracle mutabilityOracle, Collection<E> delegate) {
    316       this.mutabilityOracle = mutabilityOracle;
    317       this.delegate = delegate;
    318     }
    319 
    320     @Override
    321     public int size() {
    322       return delegate.size();
    323     }
    324 
    325     @Override
    326     public boolean isEmpty() {
    327       return delegate.isEmpty();
    328     }
    329 
    330     @Override
    331     public boolean contains(Object o) {
    332       return delegate.contains(o);
    333     }
    334 
    335     @Override
    336     public Iterator<E> iterator() {
    337       return new MutatabilityAwareIterator<E>(mutabilityOracle, delegate.iterator());
    338     }
    339 
    340     @Override
    341     public Object[] toArray() {
    342       return delegate.toArray();
    343     }
    344 
    345     @Override
    346     public <T> T[] toArray(T[] a) {
    347       return delegate.toArray(a);
    348     }
    349 
    350     @Override
    351     public boolean add(E e) {
    352       // Unsupported operation in the delegate.
    353       throw new UnsupportedOperationException();
    354     }
    355 
    356     @Override
    357     public boolean remove(Object o) {
    358       mutabilityOracle.ensureMutable();
    359       return delegate.remove(o);
    360     }
    361 
    362     @Override
    363     public boolean containsAll(Collection<?> c) {
    364       return delegate.containsAll(c);
    365     }
    366 
    367     @Override
    368     public boolean addAll(Collection<? extends E> c) {
    369       // Unsupported operation in the delegate.
    370       throw new UnsupportedOperationException();
    371     }
    372 
    373     @Override
    374     public boolean removeAll(Collection<?> c) {
    375       mutabilityOracle.ensureMutable();
    376       return delegate.removeAll(c);
    377     }
    378 
    379     @Override
    380     public boolean retainAll(Collection<?> c) {
    381       mutabilityOracle.ensureMutable();
    382       return delegate.retainAll(c);
    383     }
    384 
    385     @Override
    386     public void clear() {
    387       mutabilityOracle.ensureMutable();
    388       delegate.clear();
    389     }
    390 
    391     @Override
    392     public boolean equals(Object o) {
    393       return delegate.equals(o);
    394     }
    395 
    396     @Override
    397     public int hashCode() {
    398       return delegate.hashCode();
    399     }
    400 
    401     @Override
    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 
    414     MutatabilityAwareSet(MutabilityOracle mutabilityOracle, Set<E> delegate) {
    415       this.mutabilityOracle = mutabilityOracle;
    416       this.delegate = delegate;
    417     }
    418 
    419     @Override
    420     public int size() {
    421       return delegate.size();
    422     }
    423 
    424     @Override
    425     public boolean isEmpty() {
    426       return delegate.isEmpty();
    427     }
    428 
    429     @Override
    430     public boolean contains(Object o) {
    431       return delegate.contains(o);
    432     }
    433 
    434     @Override
    435     public Iterator<E> iterator() {
    436       return new MutatabilityAwareIterator<E>(mutabilityOracle, delegate.iterator());
    437     }
    438 
    439     @Override
    440     public Object[] toArray() {
    441       return delegate.toArray();
    442     }
    443 
    444     @Override
    445     public <T> T[] toArray(T[] a) {
    446       return delegate.toArray(a);
    447     }
    448 
    449     @Override
    450     public boolean add(E e) {
    451       mutabilityOracle.ensureMutable();
    452       return delegate.add(e);
    453     }
    454 
    455     @Override
    456     public boolean remove(Object o) {
    457       mutabilityOracle.ensureMutable();
    458       return delegate.remove(o);
    459     }
    460 
    461     @Override
    462     public boolean containsAll(Collection<?> c) {
    463       return delegate.containsAll(c);
    464     }
    465 
    466     @Override
    467     public boolean addAll(Collection<? extends E> c) {
    468       mutabilityOracle.ensureMutable();
    469       return delegate.addAll(c);
    470     }
    471 
    472     @Override
    473     public boolean retainAll(Collection<?> c) {
    474       mutabilityOracle.ensureMutable();
    475       return delegate.retainAll(c);
    476     }
    477 
    478     @Override
    479     public boolean removeAll(Collection<?> c) {
    480       mutabilityOracle.ensureMutable();
    481       return delegate.removeAll(c);
    482     }
    483 
    484     @Override
    485     public void clear() {
    486       mutabilityOracle.ensureMutable();
    487       delegate.clear();
    488     }
    489 
    490     @Override
    491     public boolean equals(Object o) {
    492       return delegate.equals(o);
    493     }
    494 
    495     @Override
    496     public int hashCode() {
    497       return delegate.hashCode();
    498     }
    499 
    500     @Override
    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 
    513     MutatabilityAwareIterator(MutabilityOracle mutabilityOracle, Iterator<E> delegate) {
    514       this.mutabilityOracle = mutabilityOracle;
    515       this.delegate = delegate;
    516     }
    517 
    518     @Override
    519     public boolean hasNext() {
    520       return delegate.hasNext();
    521     }
    522 
    523     @Override
    524     public E next() {
    525       return delegate.next();
    526     }
    527 
    528     @Override
    529     public void remove() {
    530       mutabilityOracle.ensureMutable();
    531       delegate.remove();
    532     }
    533 
    534     @Override
    535     public boolean equals(Object obj) {
    536       return delegate.equals(obj);
    537     }
    538 
    539     @Override
    540     public int hashCode() {
    541       return delegate.hashCode();
    542     }
    543 
    544     @Override
    545     public String toString() {
    546       return delegate.toString();
    547     }
    548   }
    549 }
    550