| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291 |
- // Protocol Buffers - Google's data interchange format
- // Copyright 2014 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.nano;
- /**
- * A custom version of {@code android.util.SparseArray} with the minimal API
- * for storing {@link FieldData} objects.
- *
- * <p>This class is an internal implementation detail of nano and should not
- * be called directly by clients.
- *
- * Based on {@code android.support.v4.util.SpareArrayCompat}.
- */
- public final class FieldArray implements Cloneable {
- private static final FieldData DELETED = new FieldData();
- private boolean mGarbage = false;
- private int[] mFieldNumbers;
- private FieldData[] mData;
- private int mSize;
- /**
- * Creates a new FieldArray containing no fields.
- */
- FieldArray() {
- this(10);
- }
- /**
- * Creates a new FieldArray containing no mappings that will not
- * require any additional memory allocation to store the specified
- * number of mappings.
- */
- FieldArray(int initialCapacity) {
- initialCapacity = idealIntArraySize(initialCapacity);
- mFieldNumbers = new int[initialCapacity];
- mData = new FieldData[initialCapacity];
- mSize = 0;
- }
- /**
- * Gets the FieldData mapped from the specified fieldNumber, or <code>null</code>
- * if no such mapping has been made.
- */
- FieldData get(int fieldNumber) {
- int i = binarySearch(fieldNumber);
- if (i < 0 || mData[i] == DELETED) {
- return null;
- } else {
- return mData[i];
- }
- }
- /**
- * Removes the data from the specified fieldNumber, if there was any.
- */
- void remove(int fieldNumber) {
- int i = binarySearch(fieldNumber);
- if (i >= 0 && mData[i] != DELETED) {
- mData[i] = DELETED;
- mGarbage = true;
- }
- }
- private void gc() {
- int n = mSize;
- int o = 0;
- int[] keys = mFieldNumbers;
- FieldData[] values = mData;
- for (int i = 0; i < n; i++) {
- FieldData val = values[i];
- if (val != DELETED) {
- if (i != o) {
- keys[o] = keys[i];
- values[o] = val;
- values[i] = null;
- }
- o++;
- }
- }
- mGarbage = false;
- mSize = o;
- }
- /**
- * Adds a mapping from the specified fieldNumber to the specified data,
- * replacing the previous mapping if there was one.
- */
- void put(int fieldNumber, FieldData data) {
- int i = binarySearch(fieldNumber);
- if (i >= 0) {
- mData[i] = data;
- } else {
- i = ~i;
- if (i < mSize && mData[i] == DELETED) {
- mFieldNumbers[i] = fieldNumber;
- mData[i] = data;
- return;
- }
- if (mGarbage && mSize >= mFieldNumbers.length) {
- gc();
- // Search again because indices may have changed.
- i = ~ binarySearch(fieldNumber);
- }
- if (mSize >= mFieldNumbers.length) {
- int n = idealIntArraySize(mSize + 1);
- int[] nkeys = new int[n];
- FieldData[] nvalues = new FieldData[n];
- System.arraycopy(mFieldNumbers, 0, nkeys, 0, mFieldNumbers.length);
- System.arraycopy(mData, 0, nvalues, 0, mData.length);
- mFieldNumbers = nkeys;
- mData = nvalues;
- }
- if (mSize - i != 0) {
- System.arraycopy(mFieldNumbers, i, mFieldNumbers, i + 1, mSize - i);
- System.arraycopy(mData, i, mData, i + 1, mSize - i);
- }
- mFieldNumbers[i] = fieldNumber;
- mData[i] = data;
- mSize++;
- }
- }
- /**
- * Returns the number of key-value mappings that this FieldArray
- * currently stores.
- */
- int size() {
- if (mGarbage) {
- gc();
- }
- return mSize;
- }
- public boolean isEmpty() {
- return size() == 0;
- }
- /**
- * Given an index in the range <code>0...size()-1</code>, returns
- * the value from the <code>index</code>th key-value mapping that this
- * FieldArray stores.
- */
- FieldData dataAt(int index) {
- if (mGarbage) {
- gc();
- }
- return mData[index];
- }
- @Override
- public boolean equals(Object o) {
- if (o == this) {
- return true;
- }
- if (!(o instanceof FieldArray)) {
- return false;
- }
- FieldArray other = (FieldArray) o;
- if (size() != other.size()) { // size() will call gc() if necessary.
- return false;
- }
- return arrayEquals(mFieldNumbers, other.mFieldNumbers, mSize) &&
- arrayEquals(mData, other.mData, mSize);
- }
- @Override
- public int hashCode() {
- if (mGarbage) {
- gc();
- }
- int result = 17;
- for (int i = 0; i < mSize; i++) {
- result = 31 * result + mFieldNumbers[i];
- result = 31 * result + mData[i].hashCode();
- }
- return result;
- }
- private int idealIntArraySize(int need) {
- return idealByteArraySize(need * 4) / 4;
- }
- private int idealByteArraySize(int need) {
- for (int i = 4; i < 32; i++)
- if (need <= (1 << i) - 12)
- return (1 << i) - 12;
- return need;
- }
- private int binarySearch(int value) {
- int lo = 0;
- int hi = mSize - 1;
- while (lo <= hi) {
- int mid = (lo + hi) >>> 1;
- int midVal = mFieldNumbers[mid];
- if (midVal < value) {
- lo = mid + 1;
- } else if (midVal > value) {
- hi = mid - 1;
- } else {
- return mid; // value found
- }
- }
- return ~lo; // value not present
- }
- private boolean arrayEquals(int[] a, int[] b, int size) {
- for (int i = 0; i < size; i++) {
- if (a[i] != b[i]) {
- return false;
- }
- }
- return true;
- }
- private boolean arrayEquals(FieldData[] a, FieldData[] b, int size) {
- for (int i = 0; i < size; i++) {
- if (!a[i].equals(b[i])) {
- return false;
- }
- }
- return true;
- }
- @Override
- public final FieldArray clone() {
- // Trigger GC so we compact and don't copy DELETED elements.
- int size = size();
- FieldArray clone = new FieldArray(size);
- System.arraycopy(mFieldNumbers, 0, clone.mFieldNumbers, 0, size);
- for (int i = 0; i < size; i++) {
- if (mData[i] != null) {
- clone.mData[i] = mData[i].clone();
- }
- }
- clone.mSize = size;
- return clone;
- }
- }
|