Index: third_party/protobuf/java/core/src/main/java/com/google/protobuf/MapFieldLite.java |
diff --git a/third_party/protobuf/java/core/src/main/java/com/google/protobuf/MapFieldLite.java b/third_party/protobuf/java/core/src/main/java/com/google/protobuf/MapFieldLite.java |
index 16b3fefe138b7d238d9ec89b0e66ba3de54d2c28..960b633909a064b526deeb9c16948c92eed10212 100644 |
--- a/third_party/protobuf/java/core/src/main/java/com/google/protobuf/MapFieldLite.java |
+++ b/third_party/protobuf/java/core/src/main/java/com/google/protobuf/MapFieldLite.java |
@@ -33,85 +33,71 @@ package com.google.protobuf; |
import com.google.protobuf.Internal.EnumLite; |
import java.util.Arrays; |
+import java.util.Collection; |
import java.util.Collections; |
+import java.util.Iterator; |
import java.util.LinkedHashMap; |
import java.util.Map; |
import java.util.Set; |
/** |
* Internal representation of map fields in generated lite-runtime messages. |
- * |
+ * |
* This class is a protobuf implementation detail. Users shouldn't use this |
* class directly. |
*/ |
-public final class MapFieldLite<K, V> extends LinkedHashMap<K, V> { |
- |
+public final class MapFieldLite<K, V> implements MutabilityOracle { |
+ private MutatabilityAwareMap<K, V> mapData; |
private boolean isMutable; |
- |
- private MapFieldLite() { |
- this.isMutable = true; |
- } |
- |
+ |
private MapFieldLite(Map<K, V> mapData) { |
- super(mapData); |
+ this.mapData = new MutatabilityAwareMap<K, V>(this, mapData); |
this.isMutable = true; |
} |
- |
+ |
@SuppressWarnings({"rawtypes", "unchecked"}) |
- private static final MapFieldLite EMPTY_MAP_FIELD = new MapFieldLite(); |
+ private static final MapFieldLite EMPTY_MAP_FIELD = |
+ new MapFieldLite(Collections.emptyMap()); |
static { |
EMPTY_MAP_FIELD.makeImmutable(); |
} |
- |
+ |
/** Returns an singleton immutable empty MapFieldLite instance. */ |
@SuppressWarnings({"unchecked", "cast"}) |
public static <K, V> MapFieldLite<K, V> emptyMapField() { |
return (MapFieldLite<K, V>) EMPTY_MAP_FIELD; |
} |
- |
- public void mergeFrom(MapFieldLite<K, V> other) { |
- ensureMutable(); |
- if (!other.isEmpty()) { |
- putAll(other); |
- } |
- } |
- |
- @SuppressWarnings({"unchecked", "cast"}) |
- @Override public Set<Map.Entry<K, V>> entrySet() { |
- return isEmpty() ? Collections.<Map.Entry<K, V>>emptySet() : super.entrySet(); |
- } |
- |
- @Override public void clear() { |
- ensureMutable(); |
- clear(); |
+ |
+ /** Creates a new MapFieldLite instance. */ |
+ public static <K, V> MapFieldLite<K, V> newMapField() { |
+ return new MapFieldLite<K, V>(new LinkedHashMap<K, V>()); |
} |
- |
- @Override public V put(K key, V value) { |
- ensureMutable(); |
- return super.put(key, value); |
+ |
+ /** Gets the content of this MapField as a read-only Map. */ |
+ public Map<K, V> getMap() { |
+ return Collections.unmodifiableMap(mapData); |
} |
- |
- public V put(Map.Entry<K, V> entry) { |
- return put(entry.getKey(), entry.getValue()); |
+ |
+ /** Gets a mutable Map view of this MapField. */ |
+ public Map<K, V> getMutableMap() { |
+ return mapData; |
} |
- |
- @Override public void putAll(Map<? extends K, ? extends V> m) { |
- ensureMutable(); |
- super.putAll(m); |
+ |
+ public void mergeFrom(MapFieldLite<K, V> other) { |
+ mapData.putAll(copy(other.mapData)); |
} |
- |
- @Override public V remove(Object key) { |
- ensureMutable(); |
- return super.remove(key); |
+ |
+ public void clear() { |
+ mapData.clear(); |
} |
- |
+ |
private static boolean equals(Object a, Object b) { |
if (a instanceof byte[] && b instanceof byte[]) { |
return Arrays.equals((byte[]) a, (byte[]) b); |
} |
return a.equals(b); |
} |
- |
+ |
/** |
* Checks whether two {@link Map}s are equal. We don't use the default equals |
* method of {@link Map} because it compares by identity not by content for |
@@ -134,16 +120,20 @@ public final class MapFieldLite<K, V> extends LinkedHashMap<K, V> { |
} |
return true; |
} |
- |
+ |
/** |
* Checks whether two map fields are equal. |
*/ |
@SuppressWarnings("unchecked") |
@Override |
public boolean equals(Object object) { |
- return (object instanceof Map) && equals(this, (Map<K, V>) object); |
+ if (!(object instanceof MapFieldLite)) { |
+ return false; |
+ } |
+ MapFieldLite<K, V> other = (MapFieldLite<K, V>) object; |
+ return equals(mapData, other.mapData); |
} |
- |
+ |
private static int calculateHashCodeForObject(Object a) { |
if (a instanceof byte[]) { |
return Internal.hashCode((byte[]) a); |
@@ -166,14 +156,14 @@ public final class MapFieldLite<K, V> extends LinkedHashMap<K, V> { |
result += calculateHashCodeForObject(entry.getKey()) |
^ calculateHashCodeForObject(entry.getValue()); |
} |
- return result; |
+ return result; |
} |
- |
+ |
@Override |
public int hashCode() { |
- return calculateHashCodeForMap(this); |
+ return calculateHashCodeForMap(mapData); |
} |
- |
+ |
private static Object copy(Object object) { |
if (object instanceof byte[]) { |
byte[] data = (byte[]) object; |
@@ -181,7 +171,7 @@ public final class MapFieldLite<K, V> extends LinkedHashMap<K, V> { |
} |
return object; |
} |
- |
+ |
/** |
* Makes a deep copy of a {@link Map}. Immutable objects in the map will be |
* shared (e.g., integers, strings, immutable messages) and mutable ones will |
@@ -195,12 +185,12 @@ public final class MapFieldLite<K, V> extends LinkedHashMap<K, V> { |
} |
return result; |
} |
- |
+ |
/** Returns a deep copy of this map field. */ |
- public MapFieldLite<K, V> mutableCopy() { |
- return isEmpty() ? new MapFieldLite<K, V>() : new MapFieldLite<K, V>(this); |
+ public MapFieldLite<K, V> copy() { |
+ return new MapFieldLite<K, V>(copy(mapData)); |
} |
- |
+ |
/** |
* Makes this field immutable. All subsequent modifications will throw an |
* {@link UnsupportedOperationException}. |
@@ -208,17 +198,352 @@ public final class MapFieldLite<K, V> extends LinkedHashMap<K, V> { |
public void makeImmutable() { |
isMutable = false; |
} |
- |
+ |
/** |
* Returns whether this field can be modified. |
*/ |
public boolean isMutable() { |
return isMutable; |
} |
- |
- private void ensureMutable() { |
+ |
+ @Override |
+ public void ensureMutable() { |
if (!isMutable()) { |
throw new UnsupportedOperationException(); |
} |
} |
+ |
+ /** |
+ * An internal map that checks for mutability before delegating. |
+ */ |
+ static class MutatabilityAwareMap<K, V> implements Map<K, V> { |
+ private final MutabilityOracle mutabilityOracle; |
+ private final Map<K, V> delegate; |
+ |
+ MutatabilityAwareMap(MutabilityOracle mutabilityOracle, Map<K, V> delegate) { |
+ this.mutabilityOracle = mutabilityOracle; |
+ this.delegate = delegate; |
+ } |
+ |
+ @Override |
+ public int size() { |
+ return delegate.size(); |
+ } |
+ |
+ @Override |
+ public boolean isEmpty() { |
+ return delegate.isEmpty(); |
+ } |
+ |
+ @Override |
+ public boolean containsKey(Object key) { |
+ return delegate.containsKey(key); |
+ } |
+ |
+ @Override |
+ public boolean containsValue(Object value) { |
+ return delegate.containsValue(value); |
+ } |
+ |
+ @Override |
+ public V get(Object key) { |
+ return delegate.get(key); |
+ } |
+ |
+ @Override |
+ public V put(K key, V value) { |
+ mutabilityOracle.ensureMutable(); |
+ return delegate.put(key, value); |
+ } |
+ |
+ @Override |
+ public V remove(Object key) { |
+ mutabilityOracle.ensureMutable(); |
+ return delegate.remove(key); |
+ } |
+ |
+ @Override |
+ public void putAll(Map<? extends K, ? extends V> m) { |
+ mutabilityOracle.ensureMutable(); |
+ delegate.putAll(m); |
+ } |
+ |
+ @Override |
+ public void clear() { |
+ mutabilityOracle.ensureMutable(); |
+ delegate.clear(); |
+ } |
+ |
+ @Override |
+ public Set<K> keySet() { |
+ return new MutatabilityAwareSet<K>(mutabilityOracle, delegate.keySet()); |
+ } |
+ |
+ @Override |
+ public Collection<V> values() { |
+ return new MutatabilityAwareCollection<V>(mutabilityOracle, delegate.values()); |
+ } |
+ |
+ @Override |
+ public Set<java.util.Map.Entry<K, V>> entrySet() { |
+ return new MutatabilityAwareSet<Entry<K, V>>(mutabilityOracle, delegate.entrySet()); |
+ } |
+ |
+ @Override |
+ public boolean equals(Object o) { |
+ return delegate.equals(o); |
+ } |
+ |
+ @Override |
+ public int hashCode() { |
+ return delegate.hashCode(); |
+ } |
+ |
+ @Override |
+ public String toString() { |
+ return delegate.toString(); |
+ } |
+ } |
+ |
+ /** |
+ * An internal collection that checks for mutability before delegating. |
+ */ |
+ private static class MutatabilityAwareCollection<E> implements Collection<E> { |
+ private final MutabilityOracle mutabilityOracle; |
+ private final Collection<E> delegate; |
+ |
+ MutatabilityAwareCollection(MutabilityOracle mutabilityOracle, Collection<E> delegate) { |
+ this.mutabilityOracle = mutabilityOracle; |
+ this.delegate = delegate; |
+ } |
+ |
+ @Override |
+ public int size() { |
+ return delegate.size(); |
+ } |
+ |
+ @Override |
+ public boolean isEmpty() { |
+ return delegate.isEmpty(); |
+ } |
+ |
+ @Override |
+ public boolean contains(Object o) { |
+ return delegate.contains(o); |
+ } |
+ |
+ @Override |
+ public Iterator<E> iterator() { |
+ return new MutatabilityAwareIterator<E>(mutabilityOracle, delegate.iterator()); |
+ } |
+ |
+ @Override |
+ public Object[] toArray() { |
+ return delegate.toArray(); |
+ } |
+ |
+ @Override |
+ public <T> T[] toArray(T[] a) { |
+ return delegate.toArray(a); |
+ } |
+ |
+ @Override |
+ public boolean add(E e) { |
+ // Unsupported operation in the delegate. |
+ throw new UnsupportedOperationException(); |
+ } |
+ |
+ @Override |
+ public boolean remove(Object o) { |
+ mutabilityOracle.ensureMutable(); |
+ return delegate.remove(o); |
+ } |
+ |
+ @Override |
+ public boolean containsAll(Collection<?> c) { |
+ return delegate.containsAll(c); |
+ } |
+ |
+ @Override |
+ public boolean addAll(Collection<? extends E> c) { |
+ // Unsupported operation in the delegate. |
+ throw new UnsupportedOperationException(); |
+ } |
+ |
+ @Override |
+ public boolean removeAll(Collection<?> c) { |
+ mutabilityOracle.ensureMutable(); |
+ return delegate.removeAll(c); |
+ } |
+ |
+ @Override |
+ public boolean retainAll(Collection<?> c) { |
+ mutabilityOracle.ensureMutable(); |
+ return delegate.retainAll(c); |
+ } |
+ |
+ @Override |
+ public void clear() { |
+ mutabilityOracle.ensureMutable(); |
+ delegate.clear(); |
+ } |
+ |
+ @Override |
+ public boolean equals(Object o) { |
+ return delegate.equals(o); |
+ } |
+ |
+ @Override |
+ public int hashCode() { |
+ return delegate.hashCode(); |
+ } |
+ |
+ @Override |
+ public String toString() { |
+ return delegate.toString(); |
+ } |
+ } |
+ |
+ /** |
+ * An internal set that checks for mutability before delegating. |
+ */ |
+ private static class MutatabilityAwareSet<E> implements Set<E> { |
+ private final MutabilityOracle mutabilityOracle; |
+ private final Set<E> delegate; |
+ |
+ MutatabilityAwareSet(MutabilityOracle mutabilityOracle, Set<E> delegate) { |
+ this.mutabilityOracle = mutabilityOracle; |
+ this.delegate = delegate; |
+ } |
+ |
+ @Override |
+ public int size() { |
+ return delegate.size(); |
+ } |
+ |
+ @Override |
+ public boolean isEmpty() { |
+ return delegate.isEmpty(); |
+ } |
+ |
+ @Override |
+ public boolean contains(Object o) { |
+ return delegate.contains(o); |
+ } |
+ |
+ @Override |
+ public Iterator<E> iterator() { |
+ return new MutatabilityAwareIterator<E>(mutabilityOracle, delegate.iterator()); |
+ } |
+ |
+ @Override |
+ public Object[] toArray() { |
+ return delegate.toArray(); |
+ } |
+ |
+ @Override |
+ public <T> T[] toArray(T[] a) { |
+ return delegate.toArray(a); |
+ } |
+ |
+ @Override |
+ public boolean add(E e) { |
+ mutabilityOracle.ensureMutable(); |
+ return delegate.add(e); |
+ } |
+ |
+ @Override |
+ public boolean remove(Object o) { |
+ mutabilityOracle.ensureMutable(); |
+ return delegate.remove(o); |
+ } |
+ |
+ @Override |
+ public boolean containsAll(Collection<?> c) { |
+ return delegate.containsAll(c); |
+ } |
+ |
+ @Override |
+ public boolean addAll(Collection<? extends E> c) { |
+ mutabilityOracle.ensureMutable(); |
+ return delegate.addAll(c); |
+ } |
+ |
+ @Override |
+ public boolean retainAll(Collection<?> c) { |
+ mutabilityOracle.ensureMutable(); |
+ return delegate.retainAll(c); |
+ } |
+ |
+ @Override |
+ public boolean removeAll(Collection<?> c) { |
+ mutabilityOracle.ensureMutable(); |
+ return delegate.removeAll(c); |
+ } |
+ |
+ @Override |
+ public void clear() { |
+ mutabilityOracle.ensureMutable(); |
+ delegate.clear(); |
+ } |
+ |
+ @Override |
+ public boolean equals(Object o) { |
+ return delegate.equals(o); |
+ } |
+ |
+ @Override |
+ public int hashCode() { |
+ return delegate.hashCode(); |
+ } |
+ |
+ @Override |
+ public String toString() { |
+ return delegate.toString(); |
+ } |
+ } |
+ |
+ /** |
+ * An internal iterator that checks for mutability before delegating. |
+ */ |
+ private static class MutatabilityAwareIterator<E> implements Iterator<E> { |
+ private final MutabilityOracle mutabilityOracle; |
+ private final Iterator<E> delegate; |
+ |
+ MutatabilityAwareIterator(MutabilityOracle mutabilityOracle, Iterator<E> delegate) { |
+ this.mutabilityOracle = mutabilityOracle; |
+ this.delegate = delegate; |
+ } |
+ |
+ @Override |
+ public boolean hasNext() { |
+ return delegate.hasNext(); |
+ } |
+ |
+ @Override |
+ public E next() { |
+ return delegate.next(); |
+ } |
+ |
+ @Override |
+ public void remove() { |
+ mutabilityOracle.ensureMutable(); |
+ delegate.remove(); |
+ } |
+ |
+ @Override |
+ public boolean equals(Object obj) { |
+ return delegate.equals(obj); |
+ } |
+ |
+ @Override |
+ public int hashCode() { |
+ return delegate.hashCode(); |
+ } |
+ |
+ @Override |
+ public String toString() { |
+ return delegate.toString(); |
+ } |
+ } |
} |