• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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 com.android.net.module.util;
18 
19 import android.annotation.NonNull;
20 
21 import com.android.internal.annotations.VisibleForTesting;
22 
23 import java.util.Arrays;
24 import java.util.StringJoiner;
25 import java.util.function.IntConsumer;
26 import java.util.function.IntPredicate;
27 
28 /**
29  * A growing array of primitive ints.
30  *
31  * <p>This is similar to ArrayList&lt;Integer&gt;, but avoids the cost of boxing (each Integer costs
32  * 16 bytes) and creation / garbage collection of individual Integer objects.
33  *
34  * <p>This class does not use any heuristic for growing capacity, so every call to
35  * {@link #add(int)} may reallocate the backing array. Callers should use
36  * {@link #ensureHasCapacity(int)} to minimize this behavior when they plan to add several values.
37  */
38 public class GrowingIntArray {
39     private int[] mValues;
40     private int mLength;
41 
42     /**
43      * Create an empty GrowingIntArray with the given capacity.
44      */
GrowingIntArray(int initialCapacity)45     public GrowingIntArray(int initialCapacity) {
46         mValues = new int[initialCapacity];
47         mLength = 0;
48     }
49 
50     /**
51      * Create a GrowingIntArray with an initial array of values.
52      *
53      * <p>The array will be used as-is and may be modified, so callers must stop using it after
54      * calling this constructor.
55      */
GrowingIntArray(int[] initialValues)56     protected GrowingIntArray(int[] initialValues) {
57         mValues = initialValues;
58         mLength = initialValues.length;
59     }
60 
61     /**
62      * Add a value to the array.
63      */
add(int value)64     public void add(int value) {
65         ensureHasCapacity(1);
66         mValues[mLength] = value;
67         mLength++;
68     }
69 
70     /**
71      * Get the current number of values in the array.
72      */
length()73     public int length() {
74         return mLength;
75     }
76 
77     /**
78      * Get the value at a given index.
79      *
80      * @throws ArrayIndexOutOfBoundsException if the index is out of bounds.
81      */
get(int index)82     public int get(int index) {
83         if (index < 0 || index >= mLength) {
84             throw new ArrayIndexOutOfBoundsException(index);
85         }
86         return mValues[index];
87     }
88 
89     /**
90      * Iterate over all values in the array.
91      */
forEach(@onNull IntConsumer consumer)92     public void forEach(@NonNull IntConsumer consumer) {
93         for (int i = 0; i < mLength; i++) {
94             consumer.accept(mValues[i]);
95         }
96     }
97 
98     /**
99      * Remove all values matching a predicate.
100      *
101      * @return true if at least one value was removed.
102      */
removeValues(@onNull IntPredicate predicate)103     public boolean removeValues(@NonNull IntPredicate predicate) {
104         int newQueueLength = 0;
105         for (int i = 0; i < mLength; i++) {
106             final int cb = mValues[i];
107             if (!predicate.test(cb)) {
108                 mValues[newQueueLength] = cb;
109                 newQueueLength++;
110             }
111         }
112         if (mLength != newQueueLength) {
113             mLength = newQueueLength;
114             return true;
115         }
116         return false;
117     }
118 
119     /**
120      * Indicates whether the array contains the given value.
121      */
contains(int value)122     public boolean contains(int value) {
123         for (int i = 0; i < mLength; i++) {
124             if (mValues[i] == value) {
125                 return true;
126             }
127         }
128         return false;
129     }
130 
131     /**
132      * Remove all values from the array.
133      */
clear()134     public void clear() {
135         mLength = 0;
136     }
137 
138     /**
139      * Ensure at least the given number of values can be added to the array without reallocating.
140      *
141      * @param capacity The minimum number of additional values the array must be able to hold.
142      */
ensureHasCapacity(int capacity)143     public void ensureHasCapacity(int capacity) {
144         if (mValues.length >= mLength + capacity) {
145             return;
146         }
147         mValues = Arrays.copyOf(mValues, mLength + capacity);
148     }
149 
150     @VisibleForTesting
getBackingArrayLength()151     int getBackingArrayLength() {
152         return mValues.length;
153     }
154 
155     /**
156      * Shrink the array backing this class to the minimum required length.
157      */
shrinkToLength()158     public void shrinkToLength() {
159         if (mValues.length != mLength) {
160             mValues = Arrays.copyOf(mValues, mLength);
161         }
162     }
163 
164     /**
165      * Get values as array by shrinking the internal array to length and returning it.
166      *
167      * <p>This avoids reallocations if the array is already the correct length, but callers should
168      * stop using this instance of {@link GrowingIntArray} if they use the array returned by this
169      * method.
170      */
getMinimizedBackingArray()171     public int[] getMinimizedBackingArray() {
172         shrinkToLength();
173         return mValues;
174     }
175 
176     /**
177      * Get the String representation of an item in the array, for use by {@link #toString()}.
178      */
valueToString(int item)179     protected String valueToString(int item) {
180         return String.valueOf(item);
181     }
182 
183     @NonNull
184     @Override
toString()185     public String toString() {
186         final StringJoiner joiner = new StringJoiner(",", "[", "]");
187         forEach(item -> joiner.add(valueToString(item)));
188         return joiner.toString();
189     }
190 }
191