blob: f190d8cf9f0a90d8faa0c4eef570ce2040f640b1 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 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
17package com.android.internal.util;
18
Jeff Sharkey59d577a2015-04-11 21:27:21 -070019import android.annotation.NonNull;
20import android.annotation.Nullable;
Jeff Sharkeyda96e132014-07-15 14:54:09 -070021import android.util.ArraySet;
22
Adam Lesinski776abc22014-03-07 11:30:59 -050023import dalvik.system.VMRuntime;
Jeff Sharkeyda96e132014-07-15 14:54:09 -070024
Adam Lesinski776abc22014-03-07 11:30:59 -050025import libcore.util.EmptyArray;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026
Adam Lesinski776abc22014-03-07 11:30:59 -050027import java.lang.reflect.Array;
Jeff Sharkeyda96e132014-07-15 14:54:09 -070028import java.util.ArrayList;
Jeff Sharkey59d577a2015-04-11 21:27:21 -070029import java.util.Objects;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030
31/**
32 * ArrayUtils contains some methods that you can call to find out
33 * the most efficient increments by which to grow arrays.
34 */
Jeff Sharkey59d577a2015-04-11 21:27:21 -070035public class ArrayUtils {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036 private static final int CACHE_SIZE = 73;
37 private static Object[] sCache = new Object[CACHE_SIZE];
38
39 private ArrayUtils() { /* cannot be instantiated */ }
40
Adam Lesinski776abc22014-03-07 11:30:59 -050041 public static byte[] newUnpaddedByteArray(int minLen) {
42 return (byte[])VMRuntime.getRuntime().newUnpaddedArray(byte.class, minLen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043 }
44
Adam Lesinski776abc22014-03-07 11:30:59 -050045 public static char[] newUnpaddedCharArray(int minLen) {
46 return (char[])VMRuntime.getRuntime().newUnpaddedArray(char.class, minLen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047 }
48
Adam Lesinski776abc22014-03-07 11:30:59 -050049 public static int[] newUnpaddedIntArray(int minLen) {
50 return (int[])VMRuntime.getRuntime().newUnpaddedArray(int.class, minLen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051 }
52
Adam Lesinski776abc22014-03-07 11:30:59 -050053 public static boolean[] newUnpaddedBooleanArray(int minLen) {
54 return (boolean[])VMRuntime.getRuntime().newUnpaddedArray(boolean.class, minLen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055 }
56
Adam Lesinski776abc22014-03-07 11:30:59 -050057 public static long[] newUnpaddedLongArray(int minLen) {
58 return (long[])VMRuntime.getRuntime().newUnpaddedArray(long.class, minLen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059 }
60
Adam Lesinski776abc22014-03-07 11:30:59 -050061 public static float[] newUnpaddedFloatArray(int minLen) {
62 return (float[])VMRuntime.getRuntime().newUnpaddedArray(float.class, minLen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063 }
64
Adam Lesinski776abc22014-03-07 11:30:59 -050065 public static Object[] newUnpaddedObjectArray(int minLen) {
66 return (Object[])VMRuntime.getRuntime().newUnpaddedArray(Object.class, minLen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067 }
68
Adam Lesinski776abc22014-03-07 11:30:59 -050069 @SuppressWarnings("unchecked")
70 public static <T> T[] newUnpaddedArray(Class<T> clazz, int minLen) {
71 return (T[])VMRuntime.getRuntime().newUnpaddedArray(clazz, minLen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072 }
73
74 /**
75 * Checks if the beginnings of two byte arrays are equal.
76 *
77 * @param array1 the first byte array
78 * @param array2 the second byte array
79 * @param length the number of bytes to check
80 * @return true if they're equal, false otherwise
81 */
82 public static boolean equals(byte[] array1, byte[] array2, int length) {
Christopher Tatefc054342013-03-22 15:01:13 -070083 if (length < 0) {
84 throw new IllegalArgumentException();
85 }
86
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087 if (array1 == array2) {
88 return true;
89 }
90 if (array1 == null || array2 == null || array1.length < length || array2.length < length) {
91 return false;
92 }
93 for (int i = 0; i < length; i++) {
94 if (array1[i] != array2[i]) {
95 return false;
96 }
97 }
98 return true;
99 }
100
101 /**
102 * Returns an empty array of the specified type. The intent is that
103 * it will return the same empty array every time to avoid reallocation,
104 * although this is not guaranteed.
105 */
Adam Lesinski776abc22014-03-07 11:30:59 -0500106 @SuppressWarnings("unchecked")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107 public static <T> T[] emptyArray(Class<T> kind) {
108 if (kind == Object.class) {
Adam Lesinski776abc22014-03-07 11:30:59 -0500109 return (T[]) EmptyArray.OBJECT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110 }
111
Mathieu Chartierb4e50612014-09-10 12:56:21 -0700112 int bucket = (kind.hashCode() & 0x7FFFFFFF) % CACHE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113 Object cache = sCache[bucket];
114
115 if (cache == null || cache.getClass().getComponentType() != kind) {
116 cache = Array.newInstance(kind, 0);
117 sCache[bucket] = cache;
118
119 // Log.e("cache", "new empty " + kind.getName() + " at " + bucket);
120 }
121
122 return (T[]) cache;
123 }
124
125 /**
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700126 * Checks if given array is null or has zero elements.
127 */
128 public static <T> boolean isEmpty(T[] array) {
129 return array == null || array.length == 0;
130 }
131
132 /**
Jeff Sharkey32566012014-12-02 18:30:14 -0800133 * Checks if given array is null or has zero elements.
134 */
135 public static boolean isEmpty(int[] array) {
136 return array == null || array.length == 0;
137 }
138
139 /**
140 * Checks if given array is null or has zero elements.
141 */
142 public static boolean isEmpty(long[] array) {
143 return array == null || array.length == 0;
144 }
145
146 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147 * Checks that value is present as at least one of the elements of the array.
148 * @param array the array to check in
149 * @param value the value to check for
150 * @return true if the value is present in the array
151 */
152 public static <T> boolean contains(T[] array, T value) {
Jeff Sharkey94c91dc2013-03-06 16:25:50 -0800153 return indexOf(array, value) != -1;
154 }
155
156 /**
157 * Return first index of {@code value} in {@code array}, or {@code -1} if
158 * not found.
159 */
160 public static <T> int indexOf(T[] array, T value) {
Jeff Sharkey57dcf5b2014-06-18 17:46:05 -0700161 if (array == null) return -1;
Jeff Sharkey94c91dc2013-03-06 16:25:50 -0800162 for (int i = 0; i < array.length; i++) {
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700163 if (Objects.equals(array[i], value)) return i;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164 }
Jeff Sharkey94c91dc2013-03-06 16:25:50 -0800165 return -1;
166 }
167
168 /**
169 * Test if all {@code check} items are contained in {@code array}.
170 */
171 public static <T> boolean containsAll(T[] array, T[] check) {
Jeff Sharkey32566012014-12-02 18:30:14 -0800172 if (check == null) return true;
Jeff Sharkey94c91dc2013-03-06 16:25:50 -0800173 for (T checkItem : check) {
174 if (!contains(array, checkItem)) {
175 return false;
176 }
177 }
178 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800179 }
Jeff Sharkey630a1712011-09-26 10:47:10 -0700180
181 public static boolean contains(int[] array, int value) {
Jeff Sharkey57dcf5b2014-06-18 17:46:05 -0700182 if (array == null) return false;
Jeff Sharkey630a1712011-09-26 10:47:10 -0700183 for (int element : array) {
184 if (element == value) {
185 return true;
186 }
187 }
188 return false;
189 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800190
dcashman874d0d42014-05-30 09:34:04 -0700191 public static boolean contains(long[] array, long value) {
Jeff Sharkey57dcf5b2014-06-18 17:46:05 -0700192 if (array == null) return false;
dcashman874d0d42014-05-30 09:34:04 -0700193 for (long element : array) {
194 if (element == value) {
195 return true;
196 }
197 }
198 return false;
199 }
200
Jeff Sharkey63abc372012-01-11 18:38:16 -0800201 public static long total(long[] array) {
202 long total = 0;
203 for (long value : array) {
204 total += value;
205 }
206 return total;
207 }
208
Jeff Brown96e942d2011-11-30 19:55:01 -0800209 /**
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700210 * Adds value to given array if not already present, providing set-like
211 * behavior.
Jeff Brown96e942d2011-11-30 19:55:01 -0800212 */
213 @SuppressWarnings("unchecked")
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700214 public static @NonNull <T> T[] appendElement(Class<T> kind, @Nullable T[] array, T element) {
Jeff Brown96e942d2011-11-30 19:55:01 -0800215 final T[] result;
216 final int end;
217 if (array != null) {
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700218 if (contains(array, element)) return array;
Jeff Brown96e942d2011-11-30 19:55:01 -0800219 end = array.length;
220 result = (T[])Array.newInstance(kind, end + 1);
221 System.arraycopy(array, 0, result, 0, end);
222 } else {
223 end = 0;
224 result = (T[])Array.newInstance(kind, 1);
225 }
226 result[end] = element;
227 return result;
228 }
229
230 /**
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700231 * Removes value from given array if present, providing set-like behavior.
Jeff Brown96e942d2011-11-30 19:55:01 -0800232 */
233 @SuppressWarnings("unchecked")
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700234 public static @Nullable <T> T[] removeElement(Class<T> kind, @Nullable T[] array, T element) {
Jeff Brown96e942d2011-11-30 19:55:01 -0800235 if (array != null) {
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700236 if (!contains(array, element)) return array;
Jeff Brown96e942d2011-11-30 19:55:01 -0800237 final int length = array.length;
238 for (int i = 0; i < length; i++) {
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700239 if (Objects.equals(array[i], element)) {
Jeff Brown96e942d2011-11-30 19:55:01 -0800240 if (length == 1) {
241 return null;
242 }
243 T[] result = (T[])Array.newInstance(kind, length - 1);
244 System.arraycopy(array, 0, result, 0, i);
245 System.arraycopy(array, i + 1, result, i, length - i - 1);
246 return result;
247 }
248 }
249 }
250 return array;
251 }
Jeff Sharkey854b2b12012-04-13 16:03:40 -0700252
dcashman874d0d42014-05-30 09:34:04 -0700253 /**
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700254 * Adds value to given array if not already present, providing set-like
255 * behavior.
dcashman874d0d42014-05-30 09:34:04 -0700256 */
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700257 public static @NonNull int[] appendInt(@Nullable int[] cur, int val) {
Jeff Sharkey854b2b12012-04-13 16:03:40 -0700258 if (cur == null) {
259 return new int[] { val };
260 }
261 final int N = cur.length;
262 for (int i = 0; i < N; i++) {
263 if (cur[i] == val) {
264 return cur;
265 }
266 }
267 int[] ret = new int[N + 1];
268 System.arraycopy(cur, 0, ret, 0, N);
269 ret[N] = val;
270 return ret;
271 }
272
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700273 /**
274 * Removes value from given array if present, providing set-like behavior.
275 */
276 public static @Nullable int[] removeInt(@Nullable int[] cur, int val) {
Jeff Sharkey854b2b12012-04-13 16:03:40 -0700277 if (cur == null) {
278 return null;
279 }
280 final int N = cur.length;
281 for (int i = 0; i < N; i++) {
282 if (cur[i] == val) {
283 int[] ret = new int[N - 1];
284 if (i > 0) {
285 System.arraycopy(cur, 0, ret, 0, i);
286 }
287 if (i < (N - 1)) {
288 System.arraycopy(cur, i + 1, ret, i, N - i - 1);
289 }
290 return ret;
291 }
292 }
293 return cur;
294 }
dcashman874d0d42014-05-30 09:34:04 -0700295
296 /**
Svet Ganov52153f42015-08-11 08:59:12 -0700297 * Removes value from given array if present, providing set-like behavior.
298 */
299 public static @Nullable String[] removeString(@Nullable String[] cur, String val) {
300 if (cur == null) {
301 return null;
302 }
303 final int N = cur.length;
304 for (int i = 0; i < N; i++) {
305 if (Objects.equals(cur[i], val)) {
306 String[] ret = new String[N - 1];
307 if (i > 0) {
308 System.arraycopy(cur, 0, ret, 0, i);
309 }
310 if (i < (N - 1)) {
311 System.arraycopy(cur, i + 1, ret, i, N - i - 1);
312 }
313 return ret;
314 }
315 }
316 return cur;
317 }
318
319 /**
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700320 * Adds value to given array if not already present, providing set-like
321 * behavior.
dcashman874d0d42014-05-30 09:34:04 -0700322 */
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700323 public static @NonNull long[] appendLong(@Nullable long[] cur, long val) {
dcashman874d0d42014-05-30 09:34:04 -0700324 if (cur == null) {
325 return new long[] { val };
326 }
327 final int N = cur.length;
328 for (int i = 0; i < N; i++) {
329 if (cur[i] == val) {
330 return cur;
331 }
332 }
333 long[] ret = new long[N + 1];
334 System.arraycopy(cur, 0, ret, 0, N);
335 ret[N] = val;
336 return ret;
337 }
338
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700339 /**
340 * Removes value from given array if present, providing set-like behavior.
341 */
342 public static @Nullable long[] removeLong(@Nullable long[] cur, long val) {
dcashman874d0d42014-05-30 09:34:04 -0700343 if (cur == null) {
344 return null;
345 }
346 final int N = cur.length;
347 for (int i = 0; i < N; i++) {
348 if (cur[i] == val) {
349 long[] ret = new long[N - 1];
350 if (i > 0) {
351 System.arraycopy(cur, 0, ret, 0, i);
352 }
353 if (i < (N - 1)) {
354 System.arraycopy(cur, i + 1, ret, i, N - i - 1);
355 }
356 return ret;
357 }
358 }
359 return cur;
360 }
Jeff Sharkey57dcf5b2014-06-18 17:46:05 -0700361
362 public static long[] cloneOrNull(long[] array) {
363 return (array != null) ? array.clone() : null;
364 }
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700365
366 public static <T> ArraySet<T> add(ArraySet<T> cur, T val) {
367 if (cur == null) {
368 cur = new ArraySet<>();
369 }
370 cur.add(val);
371 return cur;
372 }
373
374 public static <T> ArraySet<T> remove(ArraySet<T> cur, T val) {
375 if (cur == null) {
376 return null;
377 }
378 cur.remove(val);
379 if (cur.isEmpty()) {
380 return null;
381 } else {
382 return cur;
383 }
384 }
385
386 public static <T> boolean contains(ArraySet<T> cur, T val) {
387 return (cur != null) ? cur.contains(val) : false;
388 }
389
390 public static <T> ArrayList<T> add(ArrayList<T> cur, T val) {
391 if (cur == null) {
392 cur = new ArrayList<>();
393 }
394 cur.add(val);
395 return cur;
396 }
397
398 public static <T> ArrayList<T> remove(ArrayList<T> cur, T val) {
399 if (cur == null) {
400 return null;
401 }
402 cur.remove(val);
403 if (cur.isEmpty()) {
404 return null;
405 } else {
406 return cur;
407 }
408 }
409
410 public static <T> boolean contains(ArrayList<T> cur, T val) {
411 return (cur != null) ? cur.contains(val) : false;
412 }
Adam Lesinski72478f02015-06-17 15:39:43 -0700413
414 /**
415 * Returns true if the two ArrayLists are equal with respect to the objects they contain.
416 * The objects must be in the same order and be reference equal (== not .equals()).
417 */
418 public static <T> boolean referenceEquals(ArrayList<T> a, ArrayList<T> b) {
419 if (a == b) {
420 return true;
421 }
422
423 final int sizeA = a.size();
424 final int sizeB = b.size();
425 if (a == null || b == null || sizeA != sizeB) {
426 return false;
427 }
428
429 boolean diff = false;
430 for (int i = 0; i < sizeA && !diff; i++) {
431 diff |= a.get(i) != b.get(i);
432 }
433 return !diff;
434 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800435}