1cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira// Protocol Buffers - Google's data interchange format
2cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira// Copyright 2014 Google Inc.  All rights reserved.
3cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira// http://code.google.com/p/protobuf/
4cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira//
5cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira// Redistribution and use in source and binary forms, with or without
6cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira// modification, are permitted provided that the following conditions are
7cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira// met:
8cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira//
9cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira//     * Redistributions of source code must retain the above copyright
10cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira// notice, this list of conditions and the following disclaimer.
11cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira//     * Redistributions in binary form must reproduce the above
12cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira// copyright notice, this list of conditions and the following disclaimer
13cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira// in the documentation and/or other materials provided with the
14cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira// distribution.
15cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira//     * Neither the name of Google Inc. nor the names of its
16cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira// contributors may be used to endorse or promote products derived from
17cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira// this software without specific prior written permission.
18cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira//
19cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
31cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveirapackage com.google.protobuf.nano;
32cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
33cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
34cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira/**
35cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira * A custom version of {@link android.util.SparseArray} with the minimal API
36cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira * for storing {@link FieldData} objects.
37cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira *
38cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira * Based on {@link android.support.v4.util.SpareArrayCompat}.
39cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira */
40cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveiraclass FieldArray {
41cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    private static final FieldData DELETED = new FieldData();
42cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    private boolean mGarbage = false;
43cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
44cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    private int[] mFieldNumbers;
45cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    private FieldData[] mData;
46cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    private int mSize;
47cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
48cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    /**
49cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira     * Creates a new FieldArray containing no fields.
50cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira     */
51cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    public FieldArray() {
52cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        this(10);
53cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    }
54cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
55cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    /**
56cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira     * Creates a new FieldArray containing no mappings that will not
57cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira     * require any additional memory allocation to store the specified
58cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira     * number of mappings.
59cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira     */
60cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    public FieldArray(int initialCapacity) {
61cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        initialCapacity = idealIntArraySize(initialCapacity);
62cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        mFieldNumbers = new int[initialCapacity];
63cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        mData = new FieldData[initialCapacity];
64cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        mSize = 0;
65cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    }
66cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
67cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    /**
68cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira     * Gets the FieldData mapped from the specified fieldNumber, or <code>null</code>
69cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira     * if no such mapping has been made.
70cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira     */
71cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    public FieldData get(int fieldNumber) {
72cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        int i = binarySearch(fieldNumber);
73cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
74cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        if (i < 0 || mData[i] == DELETED) {
75cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            return null;
76cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        } else {
77cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            return mData[i];
78cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        }
79cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    }
80cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
81cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    /**
82cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira     * Removes the data from the specified fieldNumber, if there was any.
83cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira     */
84cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    public void remove(int fieldNumber) {
85cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        int i = binarySearch(fieldNumber);
86cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
87cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        if (i >= 0 && mData[i] != DELETED) {
88cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            mData[i] = DELETED;
89cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            mGarbage = true;
90cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        }
91cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    }
92cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
93cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    private void gc() {
94cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        int n = mSize;
95cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        int o = 0;
96cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        int[] keys = mFieldNumbers;
97cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        FieldData[] values = mData;
98cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
99cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        for (int i = 0; i < n; i++) {
100cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            FieldData val = values[i];
101cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
102cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            if (val != DELETED) {
103cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira                if (i != o) {
104cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira                    keys[o] = keys[i];
105cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira                    values[o] = val;
106cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira                    values[i] = null;
107cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira                }
108cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
109cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira                o++;
110cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            }
111cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        }
112cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
113cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        mGarbage = false;
114cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        mSize = o;
115cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    }
116cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
117cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    /**
118cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira     * Adds a mapping from the specified fieldNumber to the specified data,
119cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira     * replacing the previous mapping if there was one.
120cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira     */
121cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    public void put(int fieldNumber, FieldData data) {
122cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        int i = binarySearch(fieldNumber);
123cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
124cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        if (i >= 0) {
125cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            mData[i] = data;
126cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        } else {
127cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            i = ~i;
128cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
129cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            if (i < mSize && mData[i] == DELETED) {
130cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira                mFieldNumbers[i] = fieldNumber;
131cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira                mData[i] = data;
132cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira                return;
133cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            }
134cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
135cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            if (mGarbage && mSize >= mFieldNumbers.length) {
136cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira                gc();
137cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
138cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira                // Search again because indices may have changed.
139cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira                i = ~ binarySearch(fieldNumber);
140cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            }
141cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
142cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            if (mSize >= mFieldNumbers.length) {
143cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira                int n = idealIntArraySize(mSize + 1);
144cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
145cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira                int[] nkeys = new int[n];
146cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira                FieldData[] nvalues = new FieldData[n];
147cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
148cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira                System.arraycopy(mFieldNumbers, 0, nkeys, 0, mFieldNumbers.length);
149cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira                System.arraycopy(mData, 0, nvalues, 0, mData.length);
150cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
151cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira                mFieldNumbers = nkeys;
152cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira                mData = nvalues;
153cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            }
154cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
155cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            if (mSize - i != 0) {
156cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira                System.arraycopy(mFieldNumbers, i, mFieldNumbers, i + 1, mSize - i);
157cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira                System.arraycopy(mData, i, mData, i + 1, mSize - i);
158cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            }
159cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
160cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            mFieldNumbers[i] = fieldNumber;
161cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            mData[i] = data;
162cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            mSize++;
163cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        }
164cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    }
165cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
166cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    /**
167cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira     * Returns the number of key-value mappings that this FieldArray
168cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira     * currently stores.
169cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira     */
170cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    public int size() {
171cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        if (mGarbage) {
172cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            gc();
173cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        }
174cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
175cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        return mSize;
176cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    }
177cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
178cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    public boolean isEmpty() {
179cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        return size() == 0;
180cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    }
181cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
182cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    /**
183cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira     * Given an index in the range <code>0...size()-1</code>, returns
184cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira     * the value from the <code>index</code>th key-value mapping that this
185cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira     * FieldArray stores.
186cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira     */
187cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    public FieldData dataAt(int index) {
188cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        if (mGarbage) {
189cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            gc();
190cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        }
191cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
192cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        return mData[index];
193cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    }
194cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
195cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    @Override
196cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    public boolean equals(Object o) {
197cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        if (o == this) {
198cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            return true;
199cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        }
200cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        if (!(o instanceof FieldArray)) {
201cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            return false;
202cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        }
203cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
204cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        FieldArray other = (FieldArray) o;
205cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        if (size() != other.size()) {  // size() will call gc() if necessary.
206cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            return false;
207cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        }
208cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        return arrayEquals(mFieldNumbers, other.mFieldNumbers, mSize) &&
209cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira                arrayEquals(mData, other.mData, mSize);
210cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    }
211cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
212cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    @Override
213cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    public int hashCode() {
214cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        if (mGarbage) {
215cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            gc();
216cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        }
217cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        int result = 17;
218cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        for (int i = 0; i < mSize; i++) {
219cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            result = 31 * result + mFieldNumbers[i];
220cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            result = 31 * result + mData[i].hashCode();
221cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        }
222cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        return result;
223cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    }
224cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
225cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    private int idealIntArraySize(int need) {
226cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        return idealByteArraySize(need * 4) / 4;
227cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    }
228cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
229cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    private int idealByteArraySize(int need) {
230cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        for (int i = 4; i < 32; i++)
231cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            if (need <= (1 << i) - 12)
232cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira                return (1 << i) - 12;
233cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
234cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        return need;
235cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    }
236cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
237cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    private int binarySearch(int value) {
238cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        int lo = 0;
239cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        int hi = mSize - 1;
240cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
241cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        while (lo <= hi) {
242cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            int mid = (lo + hi) >>> 1;
243cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            int midVal = mFieldNumbers[mid];
244cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
245cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            if (midVal < value) {
246cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira                lo = mid + 1;
247cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            } else if (midVal > value) {
248cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira                hi = mid - 1;
249cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            } else {
250cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira                return mid; // value found
251cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            }
252cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        }
253cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        return ~lo; // value not present
254cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    }
255cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
256cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    private boolean arrayEquals(int[] a, int[] b, int size) {
257cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        for (int i = 0; i < size; i++) {
258cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            if (a[i] != b[i]) {
259cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira                return false;
260cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            }
261cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        }
262cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        return true;
263cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    }
264cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira
265cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    private boolean arrayEquals(FieldData[] a, FieldData[] b, int size) {
266cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        for (int i = 0; i < size; i++) {
267cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            if (!a[i].equals(b[i])) {
268cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira                return false;
269cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira            }
270cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        }
271cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira        return true;
272cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira    }
273cf1b416ae1327a26dd53a691fc1b3e30eec8e6a6Juan Silveira}
274