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