1b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Protocol Buffers - Google's data interchange format
2b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Copyright 2008 Google Inc.  All rights reserved.
3b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// https://developers.google.com/protocol-buffers/
4b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//
5b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Redistribution and use in source and binary forms, with or without
6b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// modification, are permitted provided that the following conditions are
7b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// met:
8b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//
9b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//     * Redistributions of source code must retain the above copyright
10b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// notice, this list of conditions and the following disclaimer.
11b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//     * Redistributions in binary form must reproduce the above
12b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// copyright notice, this list of conditions and the following disclaimer
13b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// in the documentation and/or other materials provided with the
14b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// distribution.
15b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//     * Neither the name of Google Inc. nor the names of its
16b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// contributors may be used to endorse or promote products derived from
17b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// this software without specific prior written permission.
18b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//
19b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
31b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerpackage com.google.protobuf.nano;
32b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
33b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerimport com.google.protobuf.nano.MapFactories.MapFactory;
34b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
35b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerimport java.io.IOException;
36b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerimport java.nio.charset.Charset;
37b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerimport java.util.Arrays;
38b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerimport java.util.Map;
39b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerimport java.util.Map.Entry;
40b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
41b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer/**
42b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * The classes contained within are used internally by the Protocol Buffer
43b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * library and generated message implementations. They are public only because
44b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * those generated messages do not reside in the {@code protobuf} package.
45b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Others should not use this class directly.
46b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer *
47b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @author kenton@google.com (Kenton Varda)
48b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */
49b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerpublic final class InternalNano {
50b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
51b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static final int TYPE_DOUBLE   = 1;
52b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static final int TYPE_FLOAT    = 2;
53b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static final int TYPE_INT64    = 3;
54b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static final int TYPE_UINT64   = 4;
55b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static final int TYPE_INT32    = 5;
56b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static final int TYPE_FIXED64  = 6;
57b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static final int TYPE_FIXED32  = 7;
58b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static final int TYPE_BOOL     = 8;
59b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static final int TYPE_STRING   = 9;
60b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static final int TYPE_GROUP    = 10;
61b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static final int TYPE_MESSAGE  = 11;
62b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static final int TYPE_BYTES    = 12;
63b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static final int TYPE_UINT32   = 13;
64b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static final int TYPE_ENUM     = 14;
65b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static final int TYPE_SFIXED32 = 15;
66b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static final int TYPE_SFIXED64 = 16;
67b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static final int TYPE_SINT32   = 17;
68b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static final int TYPE_SINT64   = 18;
69b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
70b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  protected static final Charset UTF_8 = Charset.forName("UTF-8");
71b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  protected static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
72b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
73b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  private InternalNano() {}
74b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
75b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
76b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * An object to provide synchronization when lazily initializing static fields
77b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * of {@link MessageNano} subclasses.
78b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * <p>
79b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * To enable earlier versions of ProGuard to inline short methods from a
80b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * generated MessageNano subclass to the call sites, that class must not have
81b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * a class initializer, which will be created if there is any static variable
82b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * initializers. To lazily initialize the static variables in a thread-safe
83b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * manner, the initialization code will synchronize on this object.
84b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
85b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static final Object LAZY_INIT_LOCK = new Object();
86b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
87b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
88b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Helper called by generated code to construct default values for string
89b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * fields.
90b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * <p>
91b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * The protocol compiler does not actually contain a UTF-8 decoder -- it
92b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * just pushes UTF-8-encoded text around without touching it.  The one place
93b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * where this presents a problem is when generating Java string literals.
94b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Unicode characters in the string literal would normally need to be encoded
95b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * using a Unicode escape sequence, which would require decoding them.
96b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * To get around this, protoc instead embeds the UTF-8 bytes into the
97b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * generated code and leaves it to the runtime library to decode them.
98b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * <p>
99b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * It gets worse, though.  If protoc just generated a byte array, like:
100b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   *   new byte[] {0x12, 0x34, 0x56, 0x78}
101b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Java actually generates *code* which allocates an array and then fills
102b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * in each value.  This is much less efficient than just embedding the bytes
103b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * directly into the bytecode.  To get around this, we need another
104b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * work-around.  String literals are embedded directly, so protoc actually
105b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * generates a string literal corresponding to the bytes.  The easiest way
106b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * to do this is to use the ISO-8859-1 character set, which corresponds to
107b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * the first 256 characters of the Unicode range.  Protoc can then use
108b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * good old CEscape to generate the string.
109b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * <p>
110b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * So we have a string literal which represents a set of bytes which
111b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * represents another string.  This function -- stringDefaultValue --
112b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * converts from the generated string to the string we actually want.  The
113b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * generated code calls this automatically.
114b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
115b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static String stringDefaultValue(String bytes) {
116b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return new String(bytes.getBytes(ISO_8859_1), InternalNano.UTF_8);
117b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
118b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
119b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
120b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Helper called by generated code to construct default values for bytes
121b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * fields.
122b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * <p>
123b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * This is a lot like {@link #stringDefaultValue}, but for bytes fields.
124b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * In this case we only need the second of the two hacks -- allowing us to
125b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * embed raw bytes as a string literal with ISO-8859-1 encoding.
126b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
127b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static byte[] bytesDefaultValue(String bytes) {
128b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return bytes.getBytes(ISO_8859_1);
129b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
130b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
131b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
132b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Helper function to convert a string into UTF-8 while turning the
133b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * UnsupportedEncodingException to a RuntimeException.
134b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
135b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static byte[] copyFromUtf8(final String text) {
136b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return text.getBytes(InternalNano.UTF_8);
137b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
138b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
139b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
140b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Checks repeated int field equality; null-value and 0-length fields are
141b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * considered equal.
142b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
143b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static boolean equals(int[] field1, int[] field2) {
144b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (field1 == null || field1.length == 0) {
145b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return field2 == null || field2.length == 0;
146b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    } else {
147b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return Arrays.equals(field1, field2);
148b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
149b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
150b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
151b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
152b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Checks repeated long field equality; null-value and 0-length fields are
153b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * considered equal.
154b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
155b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static boolean equals(long[] field1, long[] field2) {
156b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (field1 == null || field1.length == 0) {
157b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return field2 == null || field2.length == 0;
158b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    } else {
159b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return Arrays.equals(field1, field2);
160b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
161b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
162b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
163b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
164b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Checks repeated float field equality; null-value and 0-length fields are
165b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * considered equal.
166b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
167b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static boolean equals(float[] field1, float[] field2) {
168b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (field1 == null || field1.length == 0) {
169b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return field2 == null || field2.length == 0;
170b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    } else {
171b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return Arrays.equals(field1, field2);
172b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
173b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
174b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
175b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
176b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Checks repeated double field equality; null-value and 0-length fields are
177b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * considered equal.
178b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
179b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static boolean equals(double[] field1, double[] field2) {
180b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (field1 == null || field1.length == 0) {
181b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return field2 == null || field2.length == 0;
182b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    } else {
183b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return Arrays.equals(field1, field2);
184b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
185b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
186b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
187b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
188b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Checks repeated boolean field equality; null-value and 0-length fields are
189b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * considered equal.
190b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
191b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static boolean equals(boolean[] field1, boolean[] field2) {
192b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (field1 == null || field1.length == 0) {
193b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return field2 == null || field2.length == 0;
194b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    } else {
195b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return Arrays.equals(field1, field2);
196b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
197b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
198b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
199b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
200b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Checks repeated bytes field equality. Only non-null elements are tested.
201b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Returns true if the two fields have the same sequence of non-null
202b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * elements. Null-value fields and fields of any length with only null
203b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * elements are considered equal.
204b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
205b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static boolean equals(byte[][] field1, byte[][] field2) {
206b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    int index1 = 0;
207b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    int length1 = field1 == null ? 0 : field1.length;
208b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    int index2 = 0;
209b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    int length2 = field2 == null ? 0 : field2.length;
210b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    while (true) {
211b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      while (index1 < length1 && field1[index1] == null) {
212b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        index1++;
213b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
214b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      while (index2 < length2 && field2[index2] == null) {
215b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        index2++;
216b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
217b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      boolean atEndOf1 = index1 >= length1;
218b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      boolean atEndOf2 = index2 >= length2;
219b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (atEndOf1 && atEndOf2) {
220b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // no more non-null elements to test in both arrays
221b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return true;
222b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } else if (atEndOf1 != atEndOf2) {
223b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // one of the arrays have extra non-null elements
224b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return false;
225b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } else if (!Arrays.equals(field1[index1], field2[index2])) {
226b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // element mismatch
227b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return false;
228b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
229b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      index1++;
230b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      index2++;
231b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
232b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
233b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
234b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
235b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Checks repeated string/message field equality. Only non-null elements are
236b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * tested. Returns true if the two fields have the same sequence of non-null
237b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * elements. Null-value fields and fields of any length with only null
238b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * elements are considered equal.
239b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
240b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static boolean equals(Object[] field1, Object[] field2) {
241b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    int index1 = 0;
242b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    int length1 = field1 == null ? 0 : field1.length;
243b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    int index2 = 0;
244b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    int length2 = field2 == null ? 0 : field2.length;
245b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    while (true) {
246b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      while (index1 < length1 && field1[index1] == null) {
247b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        index1++;
248b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
249b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      while (index2 < length2 && field2[index2] == null) {
250b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        index2++;
251b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
252b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      boolean atEndOf1 = index1 >= length1;
253b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      boolean atEndOf2 = index2 >= length2;
254b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (atEndOf1 && atEndOf2) {
255b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // no more non-null elements to test in both arrays
256b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return true;
257b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } else if (atEndOf1 != atEndOf2) {
258b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // one of the arrays have extra non-null elements
259b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return false;
260b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } else if (!field1[index1].equals(field2[index2])) {
261b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // element mismatch
262b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return false;
263b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
264b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      index1++;
265b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      index2++;
266b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
267b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
268b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
269b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
270b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Computes the hash code of a repeated int field. Null-value and 0-length
271b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * fields have the same hash code.
272b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
273b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int hashCode(int[] field) {
274b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return field == null || field.length == 0 ? 0 : Arrays.hashCode(field);
275b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
276b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
277b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
278b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Computes the hash code of a repeated long field. Null-value and 0-length
279b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * fields have the same hash code.
280b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
281b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int hashCode(long[] field) {
282b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return field == null || field.length == 0 ? 0 : Arrays.hashCode(field);
283b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
284b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
285b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
286b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Computes the hash code of a repeated float field. Null-value and 0-length
287b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * fields have the same hash code.
288b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
289b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int hashCode(float[] field) {
290b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return field == null || field.length == 0 ? 0 : Arrays.hashCode(field);
291b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
292b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
293b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
294b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Computes the hash code of a repeated double field. Null-value and 0-length
295b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * fields have the same hash code.
296b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
297b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int hashCode(double[] field) {
298b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return field == null || field.length == 0 ? 0 : Arrays.hashCode(field);
299b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
300b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
301b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
302b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Computes the hash code of a repeated boolean field. Null-value and 0-length
303b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * fields have the same hash code.
304b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
305b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int hashCode(boolean[] field) {
306b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return field == null || field.length == 0 ? 0 : Arrays.hashCode(field);
307b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
308b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
309b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
310b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Computes the hash code of a repeated bytes field. Only the sequence of all
311b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * non-null elements are used in the computation. Null-value fields and fields
312b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * of any length with only null elements have the same hash code.
313b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
314b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int hashCode(byte[][] field) {
315b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    int result = 0;
316b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    for (int i = 0, size = field == null ? 0 : field.length; i < size; i++) {
317b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      byte[] element = field[i];
318b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (element != null) {
319b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        result = 31 * result + Arrays.hashCode(element);
320b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
321b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
322b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return result;
323b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
324b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
325b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
326b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Computes the hash code of a repeated string/message field. Only the
327b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * sequence of all non-null elements are used in the computation. Null-value
328b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * fields and fields of any length with only null elements have the same hash
329b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * code.
330b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
331b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static int hashCode(Object[] field) {
332b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    int result = 0;
333b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    for (int i = 0, size = field == null ? 0 : field.length; i < size; i++) {
334b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      Object element = field[i];
335b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (element != null) {
336b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        result = 31 * result + element.hashCode();
337b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
338b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
339b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return result;
340b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
341b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  private static Object primitiveDefaultValue(int type) {
342b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    switch (type) {
343b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      case TYPE_BOOL:
344b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return Boolean.FALSE;
345b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      case TYPE_BYTES:
346b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return WireFormatNano.EMPTY_BYTES;
347b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      case TYPE_STRING:
348b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return "";
349b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      case TYPE_FLOAT:
350b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return Float.valueOf(0);
351b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      case TYPE_DOUBLE:
352b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return Double.valueOf(0);
353b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      case TYPE_ENUM:
354b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      case TYPE_FIXED32:
355b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      case TYPE_INT32:
356b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      case TYPE_UINT32:
357b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      case TYPE_SINT32:
358b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      case TYPE_SFIXED32:
359b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return Integer.valueOf(0);
360b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      case TYPE_INT64:
361b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      case TYPE_UINT64:
362b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      case TYPE_SINT64:
363b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      case TYPE_FIXED64:
364b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      case TYPE_SFIXED64:
365b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return Long.valueOf(0L);
366b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      case TYPE_MESSAGE:
367b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      case TYPE_GROUP:
368b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      default:
369b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throw new IllegalArgumentException(
370b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            "Type: " + type + " is not a primitive type.");
371b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
372b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
373b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
374b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
375b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Merges the map entry into the map field. Note this is only supposed to
376b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * be called by generated messages.
377b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   *
378b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * @param map the map field; may be null, in which case a map will be
379b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   *        instantiated using the {@link MapFactories.MapFactory}
380b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * @param input the input byte buffer
381b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * @param keyType key type, as defined in InternalNano.TYPE_*
382b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * @param valueType value type, as defined in InternalNano.TYPE_*
383b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * @param value an new instance of the value, if the value is a TYPE_MESSAGE;
384b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   *        otherwise this parameter can be null and will be ignored.
385b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * @param keyTag wire tag for the key
386b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * @param valueTag wire tag for the value
387b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * @return the map field
388b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * @throws IOException
389b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
390b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  @SuppressWarnings("unchecked")
391b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static final <K, V> Map<K, V> mergeMapEntry(
392b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      CodedInputByteBufferNano input,
393b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      Map<K, V> map,
394b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      MapFactory mapFactory,
395b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      int keyType,
396b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      int valueType,
397b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      V value,
398b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      int keyTag,
399b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      int valueTag) throws IOException {
400b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    map = mapFactory.forMap(map);
401b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    final int length = input.readRawVarint32();
402b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    final int oldLimit = input.pushLimit(length);
403b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    K key = null;
404b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    while (true) {
405b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      int tag = input.readTag();
406b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (tag == 0) {
407b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        break;
408b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
409b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (tag == keyTag) {
410b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        key = (K) input.readPrimitiveField(keyType);
411b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } else if (tag == valueTag) {
412b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        if (valueType == TYPE_MESSAGE) {
413b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          input.readMessage((MessageNano) value);
414b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        } else {
415b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          value = (V) input.readPrimitiveField(valueType);
416b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
417b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      } else {
418b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        if (!input.skipField(tag)) {
419b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          break;
420b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
421b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
422b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
423b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    input.checkLastTagWas(0);
424b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    input.popLimit(oldLimit);
425b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
426b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (key == null) {
427b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // key can only be primitive types.
428b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      key = (K) primitiveDefaultValue(keyType);
429b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
430b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
431b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (value == null) {
432b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // message type value will be initialized by code-gen.
433b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      value = (V) primitiveDefaultValue(valueType);
434b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
435b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
436b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    map.put(key, value);
437b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return map;
438b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
439b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
440b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static <K, V> void serializeMapField(
441b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      CodedOutputByteBufferNano output,
442b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      Map<K, V> map, int number, int keyType, int valueType)
443b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          throws IOException {
444b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    for (Entry<K, V> entry: map.entrySet()) {
445b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      K key = entry.getKey();
446b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      V value = entry.getValue();
447b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (key == null || value == null) {
448b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throw new IllegalStateException(
449b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            "keys and values in maps cannot be null");
450b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
451b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      int entrySize =
452b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          CodedOutputByteBufferNano.computeFieldSize(1, keyType, key) +
453b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          CodedOutputByteBufferNano.computeFieldSize(2, valueType, value);
454b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      output.writeTag(number, WireFormatNano.WIRETYPE_LENGTH_DELIMITED);
455b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      output.writeRawVarint32(entrySize);
456b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      output.writeField(1, keyType, key);
457b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      output.writeField(2, valueType, value);
458b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
459b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
460b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
461b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static <K, V> int computeMapFieldSize(
462b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      Map<K, V> map, int number, int keyType, int valueType) {
463b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    int size = 0;
464b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    int tagSize = CodedOutputByteBufferNano.computeTagSize(number);
465b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    for (Entry<K, V> entry: map.entrySet()) {
466b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      K key = entry.getKey();
467b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      V value = entry.getValue();
468b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (key == null || value == null) {
469b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        throw new IllegalStateException(
470b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer            "keys and values in maps cannot be null");
471b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
472b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      int entrySize =
473b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          CodedOutputByteBufferNano.computeFieldSize(1, keyType, key) +
474b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          CodedOutputByteBufferNano.computeFieldSize(2, valueType, value);
475b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      size += tagSize + entrySize
476b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          + CodedOutputByteBufferNano.computeRawVarint32Size(entrySize);
477b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
478b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return size;
479b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
480b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
481b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
482b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * Checks whether two {@link Map} are equal. We don't use the default equals
483b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * method of {@link Map} because it compares by identity not by content for
484b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * byte arrays.
485b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
486b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static <K, V> boolean equals(Map<K, V> a, Map<K, V> b) {
487b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (a == b) {
488b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return true;
489b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
490b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (a == null) {
491b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return b.size() == 0;
492b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
493b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (b == null) {
494b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return a.size() == 0;
495b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
496b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (a.size() != b.size()) {
497b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return false;
498b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
499b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    for (Entry<K, V> entry : a.entrySet()) {
500b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (!b.containsKey(entry.getKey())) {
501b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return false;
502b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
503b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (!equalsMapValue(entry.getValue(), b.get(entry.getKey()))) {
504b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return false;
505b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
506b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
507b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return true;
508b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
509b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
510b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  private static boolean equalsMapValue(Object a, Object b) {
511b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (a == null || b == null) {
512b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      throw new IllegalStateException(
513b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          "keys and values in maps cannot be null");
514b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
515b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (a instanceof byte[] && b instanceof byte[]) {
516b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return Arrays.equals((byte[]) a, (byte[]) b);
517b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
518b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return a.equals(b);
519b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
520b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
521b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static <K, V> int hashCode(Map<K, V> map) {
522b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (map == null) {
523b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return 0;
524b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
525b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    int result = 0;
526b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    for (Entry<K, V> entry : map.entrySet()) {
527b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      result += hashCodeForMap(entry.getKey())
528b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          ^ hashCodeForMap(entry.getValue());
529b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
530b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return result;
531b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
532b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
533b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  private static int hashCodeForMap(Object o) {
534b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (o instanceof byte[]) {
535b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return Arrays.hashCode((byte[]) o);
536b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
537b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return o.hashCode();
538b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
539b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
540b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // This avoids having to make FieldArray public.
541b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  public static void cloneUnknownFieldData(ExtendableMessageNano original,
542b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      ExtendableMessageNano cloned) {
543b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (original.unknownFieldData != null) {
544b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      cloned.unknownFieldData = (FieldArray) original.unknownFieldData.clone();
545b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
546b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
547b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
548