diff options
Diffstat (limited to 'java/src/main/java/com/google/protobuf/MapFieldLite.java')
-rw-r--r-- | java/src/main/java/com/google/protobuf/MapFieldLite.java | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/java/src/main/java/com/google/protobuf/MapFieldLite.java b/java/src/main/java/com/google/protobuf/MapFieldLite.java new file mode 100644 index 00000000..eea36d9e --- /dev/null +++ b/java/src/main/java/com/google/protobuf/MapFieldLite.java @@ -0,0 +1,182 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * 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 class MapFieldLite<K, V> { + private Map<K, V> mapData; + + private MapFieldLite(Map<K, V> mapData) { + this.mapData = mapData; + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + private static final MapFieldLite EMPTY_MAP_FIELD = + new MapFieldLite(Collections.emptyMap()); + + /** 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; + } + + /** Creates a new MapFieldLite instance. */ + public static <K, V> MapFieldLite<K, V> newMapField() { + return new MapFieldLite<K, V>(new HashMap<K, V>()); + } + + /** Gets the content of this MapField as a read-only Map. */ + public Map<K, V> getMap() { + return Collections.unmodifiableMap(mapData); + } + + /** Gets a mutable Map view of this MapField. */ + public Map<K, V> getMutableMap() { + return mapData; + } + + public void mergeFrom(MapFieldLite<K, V> other) { + mapData.putAll(copy(other.mapData)); + } + + 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 + * byte arrays. + */ + static <K, V> boolean equals(Map<K, V> a, Map<K, V> b) { + if (a == b) { + return true; + } + if (a.size() != a.size()) { + return false; + } + for (Map.Entry<K, V> entry : a.entrySet()) { + if (!b.containsKey(entry.getKey())) { + return false; + } + if (!equals(entry.getValue(), b.get(entry.getKey()))) { + return false; + } + } + return true; + } + + /** + * Checks whether two map fields are equal. + */ + @SuppressWarnings("unchecked") + @Override + public boolean equals(Object 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 LiteralByteString.hashCode((byte[]) a); + } + if (a instanceof Internal.EnumLite) { + return Internal.hashEnum((Internal.EnumLite) a); + } + return a.hashCode(); + } + + /** + * Calculates the hash code for a {@link Map}. We don't use the default hash + * code method of {@link Map} because for byte arrays and protobuf enums it + * use {@link Object#hashCode()}. + */ + static <K, V> int calculateHashCodeForMap(Map<K, V> a) { + int result = 0; + for (Map.Entry<K, V> entry : a.entrySet()) { + result += calculateHashCodeForObject(entry.getKey()) + ^ calculateHashCodeForObject(entry.getValue()); + } + return result; + } + + @Override + public int hashCode() { + return calculateHashCodeForMap(mapData); + } + + private static Object copy(Object object) { + if (object instanceof byte[]) { + byte[] data = (byte[]) object; + return Arrays.copyOf(data, data.length); + } + 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 + * have a copy (e.g., byte arrays, mutable messages). + */ + @SuppressWarnings("unchecked") + static <K, V> Map<K, V> copy(Map<K, V> map) { + Map<K, V> result = new HashMap<K, V>(); + for (Map.Entry<K, V> entry : map.entrySet()) { + result.put(entry.getKey(), (V) copy(entry.getValue())); + } + return result; + } + + /** Returns a deep copy of this map field. */ + public MapFieldLite<K, V> copy() { + return new MapFieldLite<K, V>(copy(mapData)); + } +} |