• 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 static com.google.protobuf.Internal.checkNotNull;
34 
35 import java.util.ArrayList;
36 import java.util.Collection;
37 import java.util.Collections;
38 import java.util.Iterator;
39 import java.util.LinkedHashMap;
40 import java.util.List;
41 import java.util.Map;
42 import java.util.Set;
43 
44 /**
45  * Internal representation of map fields in generated messages.
46  *
47  * <p>This class supports accessing the map field as a {@link Map} to be used in generated API and
48  * also supports accessing the field as a {@link List} to be used in reflection API. It keeps track
49  * of where the data is currently stored and do necessary conversions between map and list.
50  *
51  * <p>This class is a protobuf implementation detail. Users shouldn't use this class directly.
52  *
53  * <p>THREAD-SAFETY NOTE: Read-only access is thread-safe. Users can call getMap() and getList()
54  * concurrently in multiple threads. If write-access is needed, all access must be synchronized.
55  */
56 public class MapField<K, V> implements MutabilityOracle {
57 
58   /**
59    * Indicates where the data of this map field is currently stored.
60    *
61    * <ul>
62    *   <li>MAP: Data is stored in mapData.
63    *   <li>LIST: Data is stored in listData.
64    *   <li>BOTH: mapData and listData have the same data.
65    * </ul>
66    *
67    * <p>When the map field is accessed (through generated API or reflection API), it will shift
68    * between these 3 modes:
69    *
70    * <pre>
71    *          <b>getMap()   getList()    getMutableMap()   getMutableList()</b>
72    * <b>MAP</b>      MAP        BOTH         MAP               LIST
73    * <b>LIST</b>     BOTH       LIST         MAP               LIST
74    * <b>BOTH</b>     BOTH       BOTH         MAP               LIST
75    * </pre>
76    *
77    * <p>As the map field changes its mode, the list/map reference returned in a previous method call
78    * may be invalidated.
79    */
80   private enum StorageMode {
81     MAP,
82     LIST,
83     BOTH
84   }
85 
86   private volatile boolean isMutable;
87   private volatile StorageMode mode;
88   private MutatabilityAwareMap<K, V> mapData;
89   private List<Message> listData;
90 
91   // Convert between a map entry Message and a key-value pair.
92   private static interface Converter<K, V> {
convertKeyAndValueToMessage(K key, V value)93     Message convertKeyAndValueToMessage(K key, V value);
94 
convertMessageToKeyAndValue(Message message, Map<K, V> map)95     void convertMessageToKeyAndValue(Message message, Map<K, V> map);
96 
getMessageDefaultInstance()97     Message getMessageDefaultInstance();
98   }
99 
100   private static class ImmutableMessageConverter<K, V> implements Converter<K, V> {
101     private final MapEntry<K, V> defaultEntry;
102 
ImmutableMessageConverter(MapEntry<K, V> defaultEntry)103     public ImmutableMessageConverter(MapEntry<K, V> defaultEntry) {
104       this.defaultEntry = defaultEntry;
105     }
106 
107     @Override
convertKeyAndValueToMessage(K key, V value)108     public Message convertKeyAndValueToMessage(K key, V value) {
109       return defaultEntry.newBuilderForType().setKey(key).setValue(value).buildPartial();
110     }
111 
112     @Override
113     @SuppressWarnings("unchecked")
convertMessageToKeyAndValue(Message message, Map<K, V> map)114     public void convertMessageToKeyAndValue(Message message, Map<K, V> map) {
115       MapEntry<K, V> entry = (MapEntry<K, V>) message;
116       map.put(entry.getKey(), entry.getValue());
117     }
118 
119     @Override
getMessageDefaultInstance()120     public Message getMessageDefaultInstance() {
121       return defaultEntry;
122     }
123   }
124 
125 
126   private final Converter<K, V> converter;
127 
MapField(Converter<K, V> converter, StorageMode mode, Map<K, V> mapData)128   private MapField(Converter<K, V> converter, StorageMode mode, Map<K, V> mapData) {
129     this.converter = converter;
130     this.isMutable = true;
131     this.mode = mode;
132     this.mapData = new MutatabilityAwareMap<K, V>(this, mapData);
133     this.listData = null;
134   }
135 
MapField(MapEntry<K, V> defaultEntry, StorageMode mode, Map<K, V> mapData)136   private MapField(MapEntry<K, V> defaultEntry, StorageMode mode, Map<K, V> mapData) {
137     this(new ImmutableMessageConverter<K, V>(defaultEntry), mode, mapData);
138   }
139 
140 
141   /** Returns an immutable empty MapField. */
emptyMapField(MapEntry<K, V> defaultEntry)142   public static <K, V> MapField<K, V> emptyMapField(MapEntry<K, V> defaultEntry) {
143     return new MapField<K, V>(defaultEntry, StorageMode.MAP, Collections.<K, V>emptyMap());
144   }
145 
146 
147   /** Creates a new mutable empty MapField. */
newMapField(MapEntry<K, V> defaultEntry)148   public static <K, V> MapField<K, V> newMapField(MapEntry<K, V> defaultEntry) {
149     return new MapField<K, V>(defaultEntry, StorageMode.MAP, new LinkedHashMap<K, V>());
150   }
151 
152 
convertKeyAndValueToMessage(K key, V value)153   private Message convertKeyAndValueToMessage(K key, V value) {
154     return converter.convertKeyAndValueToMessage(key, value);
155   }
156 
157   @SuppressWarnings("unchecked")
convertMessageToKeyAndValue(Message message, Map<K, V> map)158   private void convertMessageToKeyAndValue(Message message, Map<K, V> map) {
159     converter.convertMessageToKeyAndValue(message, map);
160   }
161 
convertMapToList(MutatabilityAwareMap<K, V> mapData)162   private List<Message> convertMapToList(MutatabilityAwareMap<K, V> mapData) {
163     List<Message> listData = new ArrayList<Message>();
164     for (Map.Entry<K, V> entry : mapData.entrySet()) {
165       listData.add(convertKeyAndValueToMessage(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>(converter, StorageMode.MAP, MapFieldLite.copy(getMap()));
230   }
231 
232   /** Gets the content of this MapField as a read-only List. */
getList()233   List<Message> getList() {
234     if (mode == StorageMode.MAP) {
235       synchronized (this) {
236         if (mode == StorageMode.MAP) {
237           listData = convertMapToList(mapData);
238           mode = StorageMode.BOTH;
239         }
240       }
241     }
242     return Collections.unmodifiableList(listData);
243   }
244 
245   /** Gets a mutable List view of this MapField. */
getMutableList()246   List<Message> getMutableList() {
247     if (mode != StorageMode.LIST) {
248       if (mode == StorageMode.MAP) {
249         listData = convertMapToList(mapData);
250       }
251       mapData = null;
252       mode = StorageMode.LIST;
253     }
254     return listData;
255   }
256 
257   /** Gets the default instance of the message stored in the list view of this map field. */
getMapEntryMessageDefaultInstance()258   Message getMapEntryMessageDefaultInstance() {
259     return converter.getMessageDefaultInstance();
260   }
261 
262   /**
263    * Makes this list immutable. All subsequent modifications will throw an {@link
264    * UnsupportedOperationException}.
265    */
makeImmutable()266   public void makeImmutable() {
267     isMutable = false;
268   }
269 
270   /** Returns whether this field can be modified. */
isMutable()271   public boolean isMutable() {
272     return isMutable;
273   }
274 
275   /* (non-Javadoc)
276    * @see com.google.protobuf.MutabilityOracle#ensureMutable()
277    */
278   @Override
ensureMutable()279   public void ensureMutable() {
280     if (!isMutable()) {
281       throw new UnsupportedOperationException();
282     }
283   }
284 
285   /** An internal map that checks for mutability before delegating. */
286   private static class MutatabilityAwareMap<K, V> implements Map<K, V> {
287     private final MutabilityOracle mutabilityOracle;
288     private final Map<K, V> delegate;
289 
MutatabilityAwareMap(MutabilityOracle mutabilityOracle, Map<K, V> delegate)290     MutatabilityAwareMap(MutabilityOracle mutabilityOracle, Map<K, V> delegate) {
291       this.mutabilityOracle = mutabilityOracle;
292       this.delegate = delegate;
293     }
294 
295     @Override
size()296     public int size() {
297       return delegate.size();
298     }
299 
300     @Override
isEmpty()301     public boolean isEmpty() {
302       return delegate.isEmpty();
303     }
304 
305     @Override
containsKey(Object key)306     public boolean containsKey(Object key) {
307       return delegate.containsKey(key);
308     }
309 
310     @Override
containsValue(Object value)311     public boolean containsValue(Object value) {
312       return delegate.containsValue(value);
313     }
314 
315     @Override
get(Object key)316     public V get(Object key) {
317       return delegate.get(key);
318     }
319 
320     @Override
put(K key, V value)321     public V put(K key, V value) {
322       mutabilityOracle.ensureMutable();
323       checkNotNull(key);
324       checkNotNull(value);
325       return delegate.put(key, value);
326     }
327 
328     @Override
remove(Object key)329     public V remove(Object key) {
330       mutabilityOracle.ensureMutable();
331       return delegate.remove(key);
332     }
333 
334     @Override
putAll(Map<? extends K, ? extends V> m)335     public void putAll(Map<? extends K, ? extends V> m) {
336       mutabilityOracle.ensureMutable();
337       for (K key : m.keySet()) {
338         checkNotNull(key);
339         checkNotNull(m.get(key));
340       }
341       delegate.putAll(m);
342     }
343 
344     @Override
clear()345     public void clear() {
346       mutabilityOracle.ensureMutable();
347       delegate.clear();
348     }
349 
350     @Override
keySet()351     public Set<K> keySet() {
352       return new MutatabilityAwareSet<K>(mutabilityOracle, delegate.keySet());
353     }
354 
355     @Override
values()356     public Collection<V> values() {
357       return new MutatabilityAwareCollection<V>(mutabilityOracle, delegate.values());
358     }
359 
360     @Override
entrySet()361     public Set<java.util.Map.Entry<K, V>> entrySet() {
362       return new MutatabilityAwareSet<Entry<K, V>>(mutabilityOracle, delegate.entrySet());
363     }
364 
365     @Override
equals(Object o)366     public boolean equals(Object o) {
367       return delegate.equals(o);
368     }
369 
370     @Override
hashCode()371     public int hashCode() {
372       return delegate.hashCode();
373     }
374 
375     @Override
toString()376     public String toString() {
377       return delegate.toString();
378     }
379 
380     /** An internal collection that checks for mutability before delegating. */
381     private static class MutatabilityAwareCollection<E> implements Collection<E> {
382       private final MutabilityOracle mutabilityOracle;
383       private final Collection<E> delegate;
384 
MutatabilityAwareCollection(MutabilityOracle mutabilityOracle, Collection<E> delegate)385       MutatabilityAwareCollection(MutabilityOracle mutabilityOracle, Collection<E> delegate) {
386         this.mutabilityOracle = mutabilityOracle;
387         this.delegate = delegate;
388       }
389 
390       @Override
size()391       public int size() {
392         return delegate.size();
393       }
394 
395       @Override
isEmpty()396       public boolean isEmpty() {
397         return delegate.isEmpty();
398       }
399 
400       @Override
contains(Object o)401       public boolean contains(Object o) {
402         return delegate.contains(o);
403       }
404 
405       @Override
iterator()406       public Iterator<E> iterator() {
407         return new MutatabilityAwareIterator<E>(mutabilityOracle, delegate.iterator());
408       }
409 
410       @Override
toArray()411       public Object[] toArray() {
412         return delegate.toArray();
413       }
414 
415       @Override
toArray(T[] a)416       public <T> T[] toArray(T[] a) {
417         return delegate.toArray(a);
418       }
419 
420       @Override
add(E e)421       public boolean add(E e) {
422         // Unsupported operation in the delegate.
423         throw new UnsupportedOperationException();
424       }
425 
426       @Override
remove(Object o)427       public boolean remove(Object o) {
428         mutabilityOracle.ensureMutable();
429         return delegate.remove(o);
430       }
431 
432       @Override
containsAll(Collection<?> c)433       public boolean containsAll(Collection<?> c) {
434         return delegate.containsAll(c);
435       }
436 
437       @Override
addAll(Collection<? extends E> c)438       public boolean addAll(Collection<? extends E> c) {
439         // Unsupported operation in the delegate.
440         throw new UnsupportedOperationException();
441       }
442 
443       @Override
removeAll(Collection<?> c)444       public boolean removeAll(Collection<?> c) {
445         mutabilityOracle.ensureMutable();
446         return delegate.removeAll(c);
447       }
448 
449       @Override
retainAll(Collection<?> c)450       public boolean retainAll(Collection<?> c) {
451         mutabilityOracle.ensureMutable();
452         return delegate.retainAll(c);
453       }
454 
455       @Override
clear()456       public void clear() {
457         mutabilityOracle.ensureMutable();
458         delegate.clear();
459       }
460 
461       @Override
equals(Object o)462       public boolean equals(Object o) {
463         return delegate.equals(o);
464       }
465 
466       @Override
hashCode()467       public int hashCode() {
468         return delegate.hashCode();
469       }
470 
471       @Override
toString()472       public String toString() {
473         return delegate.toString();
474       }
475     }
476 
477     /** An internal set that checks for mutability before delegating. */
478     private static class MutatabilityAwareSet<E> implements Set<E> {
479       private final MutabilityOracle mutabilityOracle;
480       private final Set<E> delegate;
481 
MutatabilityAwareSet(MutabilityOracle mutabilityOracle, Set<E> delegate)482       MutatabilityAwareSet(MutabilityOracle mutabilityOracle, Set<E> delegate) {
483         this.mutabilityOracle = mutabilityOracle;
484         this.delegate = delegate;
485       }
486 
487       @Override
size()488       public int size() {
489         return delegate.size();
490       }
491 
492       @Override
isEmpty()493       public boolean isEmpty() {
494         return delegate.isEmpty();
495       }
496 
497       @Override
contains(Object o)498       public boolean contains(Object o) {
499         return delegate.contains(o);
500       }
501 
502       @Override
iterator()503       public Iterator<E> iterator() {
504         return new MutatabilityAwareIterator<E>(mutabilityOracle, delegate.iterator());
505       }
506 
507       @Override
toArray()508       public Object[] toArray() {
509         return delegate.toArray();
510       }
511 
512       @Override
toArray(T[] a)513       public <T> T[] toArray(T[] a) {
514         return delegate.toArray(a);
515       }
516 
517       @Override
add(E e)518       public boolean add(E e) {
519         mutabilityOracle.ensureMutable();
520         return delegate.add(e);
521       }
522 
523       @Override
remove(Object o)524       public boolean remove(Object o) {
525         mutabilityOracle.ensureMutable();
526         return delegate.remove(o);
527       }
528 
529       @Override
containsAll(Collection<?> c)530       public boolean containsAll(Collection<?> c) {
531         return delegate.containsAll(c);
532       }
533 
534       @Override
addAll(Collection<? extends E> c)535       public boolean addAll(Collection<? extends E> c) {
536         mutabilityOracle.ensureMutable();
537         return delegate.addAll(c);
538       }
539 
540       @Override
retainAll(Collection<?> c)541       public boolean retainAll(Collection<?> c) {
542         mutabilityOracle.ensureMutable();
543         return delegate.retainAll(c);
544       }
545 
546       @Override
removeAll(Collection<?> c)547       public boolean removeAll(Collection<?> c) {
548         mutabilityOracle.ensureMutable();
549         return delegate.removeAll(c);
550       }
551 
552       @Override
clear()553       public void clear() {
554         mutabilityOracle.ensureMutable();
555         delegate.clear();
556       }
557 
558       @Override
equals(Object o)559       public boolean equals(Object o) {
560         return delegate.equals(o);
561       }
562 
563       @Override
hashCode()564       public int hashCode() {
565         return delegate.hashCode();
566       }
567 
568       @Override
toString()569       public String toString() {
570         return delegate.toString();
571       }
572     }
573 
574     /** An internal iterator that checks for mutability before delegating. */
575     private static class MutatabilityAwareIterator<E> implements Iterator<E> {
576       private final MutabilityOracle mutabilityOracle;
577       private final Iterator<E> delegate;
578 
MutatabilityAwareIterator(MutabilityOracle mutabilityOracle, Iterator<E> delegate)579       MutatabilityAwareIterator(MutabilityOracle mutabilityOracle, Iterator<E> delegate) {
580         this.mutabilityOracle = mutabilityOracle;
581         this.delegate = delegate;
582       }
583 
584       @Override
hasNext()585       public boolean hasNext() {
586         return delegate.hasNext();
587       }
588 
589       @Override
next()590       public E next() {
591         return delegate.next();
592       }
593 
594       @Override
remove()595       public void remove() {
596         mutabilityOracle.ensureMutable();
597         delegate.remove();
598       }
599 
600       @Override
equals(Object obj)601       public boolean equals(Object obj) {
602         return delegate.equals(obj);
603       }
604 
605       @Override
hashCode()606       public int hashCode() {
607         return delegate.hashCode();
608       }
609 
610       @Override
toString()611       public String toString() {
612         return delegate.toString();
613       }
614     }
615   }
616 }
617