• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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