/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.text; import android.annotation.IntRange; import android.annotation.NonNull; import com.android.internal.util.ArrayUtils; import libcore.util.EmptyArray; /** * Implements a growing array of int primitives. * * These arrays are NOT thread safe. * * @hide */ public final class AutoGrowArray { private static final int MIN_CAPACITY_INCREMENT = 12; private static final int MAX_CAPACITY_TO_BE_KEPT = 10000; /** * Returns next capacity size. * * The returned capacity is larger than requested capacity. */ private static int computeNewCapacity(int currentSize, int requested) { final int targetCapacity = currentSize + (currentSize < (MIN_CAPACITY_INCREMENT / 2) ? MIN_CAPACITY_INCREMENT : currentSize >> 1); return targetCapacity > requested ? targetCapacity : requested; } /** * An auto growing byte array. */ public static class ByteArray { private @NonNull byte[] mValues; private @IntRange(from = 0) int mSize; /** * Creates an empty ByteArray with the default initial capacity. */ public ByteArray() { this(10); } /** * Creates an empty ByteArray with the specified initial capacity. */ public ByteArray(@IntRange(from = 0) int initialCapacity) { if (initialCapacity == 0) { mValues = EmptyArray.BYTE; } else { mValues = ArrayUtils.newUnpaddedByteArray(initialCapacity); } mSize = 0; } /** * Changes the size of this ByteArray. If this ByteArray is shrinked, the backing array * capacity is unchanged. */ public void resize(@IntRange(from = 0) int newSize) { if (newSize > mValues.length) { ensureCapacity(newSize - mSize); } mSize = newSize; } /** * Appends the specified value to the end of this array. */ public void append(byte value) { ensureCapacity(1); mValues[mSize++] = value; } /** * Ensures capacity to append at least count values. */ private void ensureCapacity(@IntRange int count) { final int requestedSize = mSize + count; if (requestedSize >= mValues.length) { final int newCapacity = computeNewCapacity(mSize, requestedSize); final byte[] newValues = ArrayUtils.newUnpaddedByteArray(newCapacity); System.arraycopy(mValues, 0, newValues, 0, mSize); mValues = newValues; } } /** * Removes all values from this array. */ public void clear() { mSize = 0; } /** * Removes all values from this array and release the internal array object if it is too * large. */ public void clearWithReleasingLargeArray() { clear(); if (mValues.length > MAX_CAPACITY_TO_BE_KEPT) { mValues = EmptyArray.BYTE; } } /** * Returns the value at the specified position in this array. */ public byte get(@IntRange(from = 0) int index) { return mValues[index]; } /** * Sets the value at the specified position in this array. */ public void set(@IntRange(from = 0) int index, byte value) { mValues[index] = value; } /** * Returns the number of values in this array. */ public @IntRange(from = 0) int size() { return mSize; } /** * Returns internal raw array. * * Note that this array may have larger size than you requested. * Use size() instead for getting the actual array size. */ public @NonNull byte[] getRawArray() { return mValues; } } /** * An auto growing int array. */ public static class IntArray { private @NonNull int[] mValues; private @IntRange(from = 0) int mSize; /** * Creates an empty IntArray with the default initial capacity. */ public IntArray() { this(10); } /** * Creates an empty IntArray with the specified initial capacity. */ public IntArray(@IntRange(from = 0) int initialCapacity) { if (initialCapacity == 0) { mValues = EmptyArray.INT; } else { mValues = ArrayUtils.newUnpaddedIntArray(initialCapacity); } mSize = 0; } /** * Changes the size of this IntArray. If this IntArray is shrinked, the backing array * capacity is unchanged. */ public void resize(@IntRange(from = 0) int newSize) { if (newSize > mValues.length) { ensureCapacity(newSize - mSize); } mSize = newSize; } /** * Appends the specified value to the end of this array. */ public void append(int value) { ensureCapacity(1); mValues[mSize++] = value; } /** * Ensures capacity to append at least count values. */ private void ensureCapacity(@IntRange(from = 0) int count) { final int requestedSize = mSize + count; if (requestedSize >= mValues.length) { final int newCapacity = computeNewCapacity(mSize, requestedSize); final int[] newValues = ArrayUtils.newUnpaddedIntArray(newCapacity); System.arraycopy(mValues, 0, newValues, 0, mSize); mValues = newValues; } } /** * Removes all values from this array. */ public void clear() { mSize = 0; } /** * Removes all values from this array and release the internal array object if it is too * large. */ public void clearWithReleasingLargeArray() { clear(); if (mValues.length > MAX_CAPACITY_TO_BE_KEPT) { mValues = EmptyArray.INT; } } /** * Returns the value at the specified position in this array. */ public int get(@IntRange(from = 0) int index) { return mValues[index]; } /** * Sets the value at the specified position in this array. */ public void set(@IntRange(from = 0) int index, int value) { mValues[index] = value; } /** * Returns the number of values in this array. */ public @IntRange(from = 0) int size() { return mSize; } /** * Returns internal raw array. * * Note that this array may have larger size than you requested. * Use size() instead for getting the actual array size. */ public @NonNull int[] getRawArray() { return mValues; } } /** * An auto growing float array. */ public static class FloatArray { private @NonNull float[] mValues; private @IntRange(from = 0) int mSize; /** * Creates an empty FloatArray with the default initial capacity. */ public FloatArray() { this(10); } /** * Creates an empty FloatArray with the specified initial capacity. */ public FloatArray(@IntRange(from = 0) int initialCapacity) { if (initialCapacity == 0) { mValues = EmptyArray.FLOAT; } else { mValues = ArrayUtils.newUnpaddedFloatArray(initialCapacity); } mSize = 0; } /** * Changes the size of this FloatArray. If this FloatArray is shrinked, the backing array * capacity is unchanged. */ public void resize(@IntRange(from = 0) int newSize) { if (newSize > mValues.length) { ensureCapacity(newSize - mSize); } mSize = newSize; } /** * Appends the specified value to the end of this array. */ public void append(float value) { ensureCapacity(1); mValues[mSize++] = value; } /** * Ensures capacity to append at least count values. */ private void ensureCapacity(int count) { final int requestedSize = mSize + count; if (requestedSize >= mValues.length) { final int newCapacity = computeNewCapacity(mSize, requestedSize); final float[] newValues = ArrayUtils.newUnpaddedFloatArray(newCapacity); System.arraycopy(mValues, 0, newValues, 0, mSize); mValues = newValues; } } /** * Removes all values from this array. */ public void clear() { mSize = 0; } /** * Removes all values from this array and release the internal array object if it is too * large. */ public void clearWithReleasingLargeArray() { clear(); if (mValues.length > MAX_CAPACITY_TO_BE_KEPT) { mValues = EmptyArray.FLOAT; } } /** * Returns the value at the specified position in this array. */ public float get(@IntRange(from = 0) int index) { return mValues[index]; } /** * Sets the value at the specified position in this array. */ public void set(@IntRange(from = 0) int index, float value) { mValues[index] = value; } /** * Returns the number of values in this array. */ public @IntRange(from = 0) int size() { return mSize; } /** * Returns internal raw array. * * Note that this array may have larger size than you requested. * Use size() instead for getting the actual array size. */ public @NonNull float[] getRawArray() { return mValues; } } }