1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.text;
18 
19 import android.annotation.IntRange;
20 import android.annotation.NonNull;
21 
22 import com.android.internal.util.ArrayUtils;
23 
24 import libcore.util.EmptyArray;
25 
26 /**
27  * Implements a growing array of int primitives.
28  *
29  * These arrays are NOT thread safe.
30  *
31  * @hide
32  */
33 public final class AutoGrowArray {
34     private static final int MIN_CAPACITY_INCREMENT = 12;
35     private static final int MAX_CAPACITY_TO_BE_KEPT = 10000;
36 
37     /**
38      * Returns next capacity size.
39      *
40      * The returned capacity is larger than requested capacity.
41      */
computeNewCapacity(int currentSize, int requested)42     private static int computeNewCapacity(int currentSize, int requested) {
43         final int targetCapacity = currentSize + (currentSize < (MIN_CAPACITY_INCREMENT / 2)
44                 ?  MIN_CAPACITY_INCREMENT : currentSize >> 1);
45         return targetCapacity > requested ? targetCapacity : requested;
46     }
47 
48     /**
49      * An auto growing byte array.
50      */
51     public static class ByteArray {
52 
53         private @NonNull byte[] mValues;
54         private @IntRange(from = 0) int mSize;
55 
56         /**
57          * Creates an empty ByteArray with the default initial capacity.
58          */
ByteArray()59         public ByteArray() {
60             this(10);
61         }
62 
63         /**
64          * Creates an empty ByteArray with the specified initial capacity.
65          */
ByteArray(@ntRangefrom = 0) int initialCapacity)66         public ByteArray(@IntRange(from = 0) int initialCapacity) {
67             if (initialCapacity == 0) {
68                 mValues = EmptyArray.BYTE;
69             } else {
70                 mValues = ArrayUtils.newUnpaddedByteArray(initialCapacity);
71             }
72             mSize = 0;
73         }
74 
75         /**
76          * Changes the size of this ByteArray. If this ByteArray is shrinked, the backing array
77          * capacity is unchanged.
78          */
resize(@ntRangefrom = 0) int newSize)79         public void resize(@IntRange(from = 0) int newSize) {
80             if (newSize > mValues.length) {
81                 ensureCapacity(newSize - mSize);
82             }
83             mSize = newSize;
84         }
85 
86         /**
87          * Appends the specified value to the end of this array.
88          */
append(byte value)89         public void append(byte value) {
90             ensureCapacity(1);
91             mValues[mSize++] = value;
92         }
93 
94         /**
95          * Ensures capacity to append at least <code>count</code> values.
96          */
ensureCapacity(@ntRange int count)97         private void ensureCapacity(@IntRange int count) {
98             final int requestedSize = mSize + count;
99             if (requestedSize >= mValues.length) {
100                 final int newCapacity = computeNewCapacity(mSize, requestedSize);
101                 final byte[] newValues = ArrayUtils.newUnpaddedByteArray(newCapacity);
102                 System.arraycopy(mValues, 0, newValues, 0, mSize);
103                 mValues = newValues;
104             }
105         }
106 
107         /**
108          * Removes all values from this array.
109          */
clear()110         public void clear() {
111             mSize = 0;
112         }
113 
114         /**
115          * Removes all values from this array and release the internal array object if it is too
116          * large.
117          */
clearWithReleasingLargeArray()118         public void clearWithReleasingLargeArray() {
119             clear();
120             if (mValues.length > MAX_CAPACITY_TO_BE_KEPT) {
121                 mValues = EmptyArray.BYTE;
122             }
123         }
124 
125         /**
126          * Returns the value at the specified position in this array.
127          */
get(@ntRangefrom = 0) int index)128         public byte get(@IntRange(from = 0) int index) {
129             return mValues[index];
130         }
131 
132         /**
133          * Sets the value at the specified position in this array.
134          */
set(@ntRangefrom = 0) int index, byte value)135         public void set(@IntRange(from = 0) int index, byte value) {
136             mValues[index] = value;
137         }
138 
139         /**
140          * Returns the number of values in this array.
141          */
size()142         public @IntRange(from = 0) int size() {
143             return mSize;
144         }
145 
146         /**
147          * Returns internal raw array.
148          *
149          * Note that this array may have larger size than you requested.
150          * Use size() instead for getting the actual array size.
151          */
getRawArray()152         public @NonNull byte[] getRawArray() {
153             return mValues;
154         }
155     }
156 
157     /**
158      * An auto growing int array.
159      */
160     public static class IntArray {
161 
162         private @NonNull int[] mValues;
163         private @IntRange(from = 0) int mSize;
164 
165         /**
166          * Creates an empty IntArray with the default initial capacity.
167          */
IntArray()168         public IntArray() {
169             this(10);
170         }
171 
172         /**
173          * Creates an empty IntArray with the specified initial capacity.
174          */
IntArray(@ntRangefrom = 0) int initialCapacity)175         public IntArray(@IntRange(from = 0) int initialCapacity) {
176             if (initialCapacity == 0) {
177                 mValues = EmptyArray.INT;
178             } else {
179                 mValues = ArrayUtils.newUnpaddedIntArray(initialCapacity);
180             }
181             mSize = 0;
182         }
183 
184         /**
185          * Changes the size of this IntArray. If this IntArray is shrinked, the backing array
186          * capacity is unchanged.
187          */
resize(@ntRangefrom = 0) int newSize)188         public void resize(@IntRange(from = 0) int newSize) {
189             if (newSize > mValues.length) {
190                 ensureCapacity(newSize - mSize);
191             }
192             mSize = newSize;
193         }
194 
195         /**
196          * Appends the specified value to the end of this array.
197          */
append(int value)198         public void append(int value) {
199             ensureCapacity(1);
200             mValues[mSize++] = value;
201         }
202 
203         /**
204          * Ensures capacity to append at least <code>count</code> values.
205          */
ensureCapacity(@ntRangefrom = 0) int count)206         private void ensureCapacity(@IntRange(from = 0) int count) {
207             final int requestedSize = mSize + count;
208             if (requestedSize >= mValues.length) {
209                 final int newCapacity = computeNewCapacity(mSize, requestedSize);
210                 final int[] newValues = ArrayUtils.newUnpaddedIntArray(newCapacity);
211                 System.arraycopy(mValues, 0, newValues, 0, mSize);
212                 mValues = newValues;
213             }
214         }
215 
216         /**
217          * Removes all values from this array.
218          */
clear()219         public void clear() {
220             mSize = 0;
221         }
222 
223         /**
224          * Removes all values from this array and release the internal array object if it is too
225          * large.
226          */
clearWithReleasingLargeArray()227         public void clearWithReleasingLargeArray() {
228             clear();
229             if (mValues.length > MAX_CAPACITY_TO_BE_KEPT) {
230                 mValues = EmptyArray.INT;
231             }
232         }
233 
234         /**
235          * Returns the value at the specified position in this array.
236          */
get(@ntRangefrom = 0) int index)237         public int get(@IntRange(from = 0) int index) {
238             return mValues[index];
239         }
240 
241         /**
242          * Sets the value at the specified position in this array.
243          */
set(@ntRangefrom = 0) int index, int value)244         public void set(@IntRange(from = 0) int index, int value) {
245             mValues[index] = value;
246         }
247 
248         /**
249          * Returns the number of values in this array.
250          */
size()251         public @IntRange(from = 0) int size() {
252             return mSize;
253         }
254 
255         /**
256          * Returns internal raw array.
257          *
258          * Note that this array may have larger size than you requested.
259          * Use size() instead for getting the actual array size.
260          */
getRawArray()261         public @NonNull int[] getRawArray() {
262             return mValues;
263         }
264     }
265 
266     /**
267      * An auto growing float array.
268      */
269     public static class FloatArray {
270 
271         private @NonNull float[] mValues;
272         private @IntRange(from = 0) int mSize;
273 
274         /**
275          * Creates an empty FloatArray with the default initial capacity.
276          */
FloatArray()277         public FloatArray() {
278             this(10);
279         }
280 
281         /**
282          * Creates an empty FloatArray with the specified initial capacity.
283          */
FloatArray(@ntRangefrom = 0) int initialCapacity)284         public FloatArray(@IntRange(from = 0) int initialCapacity) {
285             if (initialCapacity == 0) {
286                 mValues = EmptyArray.FLOAT;
287             } else {
288                 mValues = ArrayUtils.newUnpaddedFloatArray(initialCapacity);
289             }
290             mSize = 0;
291         }
292 
293         /**
294          * Changes the size of this FloatArray. If this FloatArray is shrinked, the backing array
295          * capacity is unchanged.
296          */
resize(@ntRangefrom = 0) int newSize)297         public void resize(@IntRange(from = 0) int newSize) {
298             if (newSize > mValues.length) {
299                 ensureCapacity(newSize - mSize);
300             }
301             mSize = newSize;
302         }
303 
304         /**
305          * Appends the specified value to the end of this array.
306          */
append(float value)307         public void append(float value) {
308             ensureCapacity(1);
309             mValues[mSize++] = value;
310         }
311 
312         /**
313          * Ensures capacity to append at least <code>count</code> values.
314          */
ensureCapacity(int count)315         private void ensureCapacity(int count) {
316             final int requestedSize = mSize + count;
317             if (requestedSize >= mValues.length) {
318                 final int newCapacity = computeNewCapacity(mSize, requestedSize);
319                 final float[] newValues = ArrayUtils.newUnpaddedFloatArray(newCapacity);
320                 System.arraycopy(mValues, 0, newValues, 0, mSize);
321                 mValues = newValues;
322             }
323         }
324 
325         /**
326          * Removes all values from this array.
327          */
clear()328         public void clear() {
329             mSize = 0;
330         }
331 
332         /**
333          * Removes all values from this array and release the internal array object if it is too
334          * large.
335          */
clearWithReleasingLargeArray()336         public void clearWithReleasingLargeArray() {
337             clear();
338             if (mValues.length > MAX_CAPACITY_TO_BE_KEPT) {
339                 mValues = EmptyArray.FLOAT;
340             }
341         }
342 
343         /**
344          * Returns the value at the specified position in this array.
345          */
get(@ntRangefrom = 0) int index)346         public float get(@IntRange(from = 0) int index) {
347             return mValues[index];
348         }
349 
350         /**
351          * Sets the value at the specified position in this array.
352          */
set(@ntRangefrom = 0) int index, float value)353         public void set(@IntRange(from = 0) int index, float value) {
354             mValues[index] = value;
355         }
356 
357         /**
358          * Returns the number of values in this array.
359          */
size()360         public @IntRange(from = 0) int size() {
361             return mSize;
362         }
363 
364         /**
365          * Returns internal raw array.
366          *
367          * Note that this array may have larger size than you requested.
368          * Use size() instead for getting the actual array size.
369          */
getRawArray()370         public @NonNull float[] getRawArray() {
371             return mValues;
372         }
373     }
374 }
375