blob: ee73b90097af34f38b5285a181f869d735e30e31 [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 Sharkey2bd31db2016-01-09 16:58:14 -070029import java.util.Arrays;
Adam Lesinski082614c2016-03-04 14:33:47 -080030import java.util.Collections;
Jeff Sharkey3e195892016-03-05 19:48:59 -070031import java.util.List;
Jeff Sharkey59d577a2015-04-11 21:27:21 -070032import java.util.Objects;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033
34/**
35 * ArrayUtils contains some methods that you can call to find out
36 * the most efficient increments by which to grow arrays.
37 */
Jeff Sharkey59d577a2015-04-11 21:27:21 -070038public class ArrayUtils {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039 private static final int CACHE_SIZE = 73;
40 private static Object[] sCache = new Object[CACHE_SIZE];
41
42 private ArrayUtils() { /* cannot be instantiated */ }
43
Adam Lesinski776abc22014-03-07 11:30:59 -050044 public static byte[] newUnpaddedByteArray(int minLen) {
45 return (byte[])VMRuntime.getRuntime().newUnpaddedArray(byte.class, minLen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046 }
47
Adam Lesinski776abc22014-03-07 11:30:59 -050048 public static char[] newUnpaddedCharArray(int minLen) {
49 return (char[])VMRuntime.getRuntime().newUnpaddedArray(char.class, minLen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050 }
51
Adam Lesinski776abc22014-03-07 11:30:59 -050052 public static int[] newUnpaddedIntArray(int minLen) {
53 return (int[])VMRuntime.getRuntime().newUnpaddedArray(int.class, minLen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054 }
55
Adam Lesinski776abc22014-03-07 11:30:59 -050056 public static boolean[] newUnpaddedBooleanArray(int minLen) {
57 return (boolean[])VMRuntime.getRuntime().newUnpaddedArray(boolean.class, minLen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058 }
59
Adam Lesinski776abc22014-03-07 11:30:59 -050060 public static long[] newUnpaddedLongArray(int minLen) {
61 return (long[])VMRuntime.getRuntime().newUnpaddedArray(long.class, minLen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062 }
63
Adam Lesinski776abc22014-03-07 11:30:59 -050064 public static float[] newUnpaddedFloatArray(int minLen) {
65 return (float[])VMRuntime.getRuntime().newUnpaddedArray(float.class, minLen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080066 }
67
Adam Lesinski776abc22014-03-07 11:30:59 -050068 public static Object[] newUnpaddedObjectArray(int minLen) {
69 return (Object[])VMRuntime.getRuntime().newUnpaddedArray(Object.class, minLen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070 }
71
Adam Lesinski776abc22014-03-07 11:30:59 -050072 @SuppressWarnings("unchecked")
73 public static <T> T[] newUnpaddedArray(Class<T> clazz, int minLen) {
74 return (T[])VMRuntime.getRuntime().newUnpaddedArray(clazz, minLen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080075 }
76
77 /**
78 * Checks if the beginnings of two byte arrays are equal.
79 *
80 * @param array1 the first byte array
81 * @param array2 the second byte array
82 * @param length the number of bytes to check
83 * @return true if they're equal, false otherwise
84 */
85 public static boolean equals(byte[] array1, byte[] array2, int length) {
Christopher Tatefc054342013-03-22 15:01:13 -070086 if (length < 0) {
87 throw new IllegalArgumentException();
88 }
89
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090 if (array1 == array2) {
91 return true;
92 }
93 if (array1 == null || array2 == null || array1.length < length || array2.length < length) {
94 return false;
95 }
96 for (int i = 0; i < length; i++) {
97 if (array1[i] != array2[i]) {
98 return false;
99 }
100 }
101 return true;
102 }
103
104 /**
105 * Returns an empty array of the specified type. The intent is that
106 * it will return the same empty array every time to avoid reallocation,
107 * although this is not guaranteed.
108 */
Adam Lesinski776abc22014-03-07 11:30:59 -0500109 @SuppressWarnings("unchecked")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110 public static <T> T[] emptyArray(Class<T> kind) {
111 if (kind == Object.class) {
Adam Lesinski776abc22014-03-07 11:30:59 -0500112 return (T[]) EmptyArray.OBJECT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113 }
114
Mathieu Chartierb4e50612014-09-10 12:56:21 -0700115 int bucket = (kind.hashCode() & 0x7FFFFFFF) % CACHE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116 Object cache = sCache[bucket];
117
118 if (cache == null || cache.getClass().getComponentType() != kind) {
119 cache = Array.newInstance(kind, 0);
120 sCache[bucket] = cache;
121
122 // Log.e("cache", "new empty " + kind.getName() + " at " + bucket);
123 }
124
125 return (T[]) cache;
126 }
127
128 /**
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700129 * Checks if given array is null or has zero elements.
130 */
Jeff Sharkey3e195892016-03-05 19:48:59 -0700131 public static boolean isEmpty(@Nullable List<?> array) {
132 return array == null || array.isEmpty();
133 }
134
135 /**
136 * Checks if given array is null or has zero elements.
137 */
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700138 public static <T> boolean isEmpty(@Nullable T[] array) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700139 return array == null || array.length == 0;
140 }
141
142 /**
Jeff Sharkey32566012014-12-02 18:30:14 -0800143 * Checks if given array is null or has zero elements.
144 */
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700145 public static boolean isEmpty(@Nullable int[] array) {
Jeff Sharkey32566012014-12-02 18:30:14 -0800146 return array == null || array.length == 0;
147 }
148
149 /**
150 * Checks if given array is null or has zero elements.
151 */
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700152 public static boolean isEmpty(@Nullable long[] array) {
Jeff Sharkey32566012014-12-02 18:30:14 -0800153 return array == null || array.length == 0;
154 }
155
156 /**
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800157 * Checks if given array is null or has zero elements.
158 */
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700159 public static boolean isEmpty(@Nullable byte[] array) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800160 return array == null || array.length == 0;
161 }
162
163 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164 * Checks that value is present as at least one of the elements of the array.
165 * @param array the array to check in
166 * @param value the value to check for
167 * @return true if the value is present in the array
168 */
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700169 public static <T> boolean contains(@Nullable T[] array, T value) {
Jeff Sharkey94c91dc2013-03-06 16:25:50 -0800170 return indexOf(array, value) != -1;
171 }
172
173 /**
174 * Return first index of {@code value} in {@code array}, or {@code -1} if
175 * not found.
176 */
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700177 public static <T> int indexOf(@Nullable T[] array, T value) {
Jeff Sharkey57dcf5b2014-06-18 17:46:05 -0700178 if (array == null) return -1;
Jeff Sharkey94c91dc2013-03-06 16:25:50 -0800179 for (int i = 0; i < array.length; i++) {
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700180 if (Objects.equals(array[i], value)) return i;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800181 }
Jeff Sharkey94c91dc2013-03-06 16:25:50 -0800182 return -1;
183 }
184
185 /**
186 * Test if all {@code check} items are contained in {@code array}.
187 */
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700188 public static <T> boolean containsAll(@Nullable T[] array, T[] check) {
Jeff Sharkey32566012014-12-02 18:30:14 -0800189 if (check == null) return true;
Jeff Sharkey94c91dc2013-03-06 16:25:50 -0800190 for (T checkItem : check) {
191 if (!contains(array, checkItem)) {
192 return false;
193 }
194 }
195 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800196 }
Jeff Sharkey630a1712011-09-26 10:47:10 -0700197
Jeff Sharkey35871f22016-01-29 17:13:29 -0700198 /**
199 * Test if any {@code check} items are contained in {@code array}.
200 */
201 public static <T> boolean containsAny(@Nullable T[] array, T[] check) {
202 if (check == null) return false;
203 for (T checkItem : check) {
204 if (contains(array, checkItem)) {
205 return true;
206 }
207 }
208 return false;
209 }
210
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700211 public static boolean contains(@Nullable int[] array, int value) {
Jeff Sharkey57dcf5b2014-06-18 17:46:05 -0700212 if (array == null) return false;
Jeff Sharkey630a1712011-09-26 10:47:10 -0700213 for (int element : array) {
214 if (element == value) {
215 return true;
216 }
217 }
218 return false;
219 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800220
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700221 public static boolean contains(@Nullable long[] array, long value) {
Jeff Sharkey57dcf5b2014-06-18 17:46:05 -0700222 if (array == null) return false;
dcashman874d0d42014-05-30 09:34:04 -0700223 for (long element : array) {
224 if (element == value) {
225 return true;
226 }
227 }
228 return false;
229 }
230
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700231 public static long total(@Nullable long[] array) {
Jeff Sharkey63abc372012-01-11 18:38:16 -0800232 long total = 0;
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700233 if (array != null) {
234 for (long value : array) {
235 total += value;
236 }
Jeff Sharkey63abc372012-01-11 18:38:16 -0800237 }
238 return total;
239 }
240
Jeff Brown96e942d2011-11-30 19:55:01 -0800241 /**
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700242 * Adds value to given array if not already present, providing set-like
243 * behavior.
Jeff Brown96e942d2011-11-30 19:55:01 -0800244 */
245 @SuppressWarnings("unchecked")
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700246 public static @NonNull <T> T[] appendElement(Class<T> kind, @Nullable T[] array, T element) {
Jeff Brown96e942d2011-11-30 19:55:01 -0800247 final T[] result;
248 final int end;
249 if (array != null) {
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700250 if (contains(array, element)) return array;
Jeff Brown96e942d2011-11-30 19:55:01 -0800251 end = array.length;
252 result = (T[])Array.newInstance(kind, end + 1);
253 System.arraycopy(array, 0, result, 0, end);
254 } else {
255 end = 0;
256 result = (T[])Array.newInstance(kind, 1);
257 }
258 result[end] = element;
259 return result;
260 }
261
262 /**
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700263 * Removes value from given array if present, providing set-like behavior.
Jeff Brown96e942d2011-11-30 19:55:01 -0800264 */
265 @SuppressWarnings("unchecked")
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700266 public static @Nullable <T> T[] removeElement(Class<T> kind, @Nullable T[] array, T element) {
Jeff Brown96e942d2011-11-30 19:55:01 -0800267 if (array != null) {
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700268 if (!contains(array, element)) return array;
Jeff Brown96e942d2011-11-30 19:55:01 -0800269 final int length = array.length;
270 for (int i = 0; i < length; i++) {
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700271 if (Objects.equals(array[i], element)) {
Jeff Brown96e942d2011-11-30 19:55:01 -0800272 if (length == 1) {
273 return null;
274 }
275 T[] result = (T[])Array.newInstance(kind, length - 1);
276 System.arraycopy(array, 0, result, 0, i);
277 System.arraycopy(array, i + 1, result, i, length - i - 1);
278 return result;
279 }
280 }
281 }
282 return array;
283 }
Jeff Sharkey854b2b12012-04-13 16:03:40 -0700284
dcashman874d0d42014-05-30 09:34:04 -0700285 /**
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700286 * Adds value to given array if not already present, providing set-like
287 * behavior.
dcashman874d0d42014-05-30 09:34:04 -0700288 */
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700289 public static @NonNull int[] appendInt(@Nullable int[] cur, int val) {
Jeff Sharkey854b2b12012-04-13 16:03:40 -0700290 if (cur == null) {
291 return new int[] { val };
292 }
293 final int N = cur.length;
294 for (int i = 0; i < N; i++) {
295 if (cur[i] == val) {
296 return cur;
297 }
298 }
299 int[] ret = new int[N + 1];
300 System.arraycopy(cur, 0, ret, 0, N);
301 ret[N] = val;
302 return ret;
303 }
304
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700305 /**
306 * Removes value from given array if present, providing set-like behavior.
307 */
308 public static @Nullable int[] removeInt(@Nullable int[] cur, int val) {
Jeff Sharkey854b2b12012-04-13 16:03:40 -0700309 if (cur == null) {
310 return null;
311 }
312 final int N = cur.length;
313 for (int i = 0; i < N; i++) {
314 if (cur[i] == val) {
315 int[] ret = new int[N - 1];
316 if (i > 0) {
317 System.arraycopy(cur, 0, ret, 0, i);
318 }
319 if (i < (N - 1)) {
320 System.arraycopy(cur, i + 1, ret, i, N - i - 1);
321 }
322 return ret;
323 }
324 }
325 return cur;
326 }
dcashman874d0d42014-05-30 09:34:04 -0700327
328 /**
Svet Ganov52153f42015-08-11 08:59:12 -0700329 * Removes value from given array if present, providing set-like behavior.
330 */
331 public static @Nullable String[] removeString(@Nullable String[] cur, String val) {
332 if (cur == null) {
333 return null;
334 }
335 final int N = cur.length;
336 for (int i = 0; i < N; i++) {
337 if (Objects.equals(cur[i], val)) {
338 String[] ret = new String[N - 1];
339 if (i > 0) {
340 System.arraycopy(cur, 0, ret, 0, i);
341 }
342 if (i < (N - 1)) {
343 System.arraycopy(cur, i + 1, ret, i, N - i - 1);
344 }
345 return ret;
346 }
347 }
348 return cur;
349 }
350
351 /**
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700352 * Adds value to given array if not already present, providing set-like
353 * behavior.
dcashman874d0d42014-05-30 09:34:04 -0700354 */
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700355 public static @NonNull long[] appendLong(@Nullable long[] cur, long val) {
dcashman874d0d42014-05-30 09:34:04 -0700356 if (cur == null) {
357 return new long[] { val };
358 }
359 final int N = cur.length;
360 for (int i = 0; i < N; i++) {
361 if (cur[i] == val) {
362 return cur;
363 }
364 }
365 long[] ret = new long[N + 1];
366 System.arraycopy(cur, 0, ret, 0, N);
367 ret[N] = val;
368 return ret;
369 }
370
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700371 /**
372 * Removes value from given array if present, providing set-like behavior.
373 */
374 public static @Nullable long[] removeLong(@Nullable long[] cur, long val) {
dcashman874d0d42014-05-30 09:34:04 -0700375 if (cur == null) {
376 return null;
377 }
378 final int N = cur.length;
379 for (int i = 0; i < N; i++) {
380 if (cur[i] == val) {
381 long[] ret = new long[N - 1];
382 if (i > 0) {
383 System.arraycopy(cur, 0, ret, 0, i);
384 }
385 if (i < (N - 1)) {
386 System.arraycopy(cur, i + 1, ret, i, N - i - 1);
387 }
388 return ret;
389 }
390 }
391 return cur;
392 }
Jeff Sharkey57dcf5b2014-06-18 17:46:05 -0700393
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700394 public static @Nullable long[] cloneOrNull(@Nullable long[] array) {
Jeff Sharkey57dcf5b2014-06-18 17:46:05 -0700395 return (array != null) ? array.clone() : null;
396 }
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700397
Jeff Sharkey2bd31db2016-01-09 16:58:14 -0700398 public static @Nullable <T> ArraySet<T> cloneOrNull(@Nullable ArraySet<T> array) {
399 return (array != null) ? new ArraySet<T>(array) : null;
400 }
401
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700402 public static @NonNull <T> ArraySet<T> add(@Nullable ArraySet<T> cur, T val) {
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700403 if (cur == null) {
404 cur = new ArraySet<>();
405 }
406 cur.add(val);
407 return cur;
408 }
409
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700410 public static @Nullable <T> ArraySet<T> remove(@Nullable ArraySet<T> cur, T val) {
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700411 if (cur == null) {
412 return null;
413 }
414 cur.remove(val);
415 if (cur.isEmpty()) {
416 return null;
417 } else {
418 return cur;
419 }
420 }
421
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700422 public static <T> boolean contains(@Nullable ArraySet<T> cur, T val) {
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700423 return (cur != null) ? cur.contains(val) : false;
424 }
425
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700426 public static @NonNull <T> ArrayList<T> add(@Nullable ArrayList<T> cur, T val) {
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700427 if (cur == null) {
428 cur = new ArrayList<>();
429 }
430 cur.add(val);
431 return cur;
432 }
433
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700434 public static @Nullable <T> ArrayList<T> remove(@Nullable ArrayList<T> cur, T val) {
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700435 if (cur == null) {
436 return null;
437 }
438 cur.remove(val);
439 if (cur.isEmpty()) {
440 return null;
441 } else {
442 return cur;
443 }
444 }
445
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700446 public static <T> boolean contains(@Nullable ArrayList<T> cur, T val) {
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700447 return (cur != null) ? cur.contains(val) : false;
448 }
Adam Lesinski72478f02015-06-17 15:39:43 -0700449
Jeff Sharkey2bd31db2016-01-09 16:58:14 -0700450 public static @Nullable <T> T[] trimToSize(@Nullable T[] array, int size) {
451 if (array == null || size == 0) {
452 return null;
453 } else if (array.length == size) {
454 return array;
455 } else {
456 return Arrays.copyOf(array, size);
457 }
458 }
459
Adam Lesinski72478f02015-06-17 15:39:43 -0700460 /**
461 * Returns true if the two ArrayLists are equal with respect to the objects they contain.
462 * The objects must be in the same order and be reference equal (== not .equals()).
463 */
464 public static <T> boolean referenceEquals(ArrayList<T> a, ArrayList<T> b) {
465 if (a == b) {
466 return true;
467 }
468
469 final int sizeA = a.size();
470 final int sizeB = b.size();
471 if (a == null || b == null || sizeA != sizeB) {
472 return false;
473 }
474
475 boolean diff = false;
476 for (int i = 0; i < sizeA && !diff; i++) {
477 diff |= a.get(i) != b.get(i);
478 }
479 return !diff;
480 }
Adam Lesinski082614c2016-03-04 14:33:47 -0800481
482 /**
483 * Removes elements that match the predicate in an efficient way that alters the order of
484 * elements in the collection. This should only be used if order is not important.
485 * @param collection The ArrayList from which to remove elements.
486 * @param predicate The predicate that each element is tested against.
487 * @return the number of elements removed.
488 */
489 public static <T> int unstableRemoveIf(@Nullable ArrayList<T> collection,
490 @NonNull java.util.function.Predicate<T> predicate) {
491 if (collection == null) {
492 return 0;
493 }
494
495 final int size = collection.size();
496 int leftIdx = 0;
497 int rightIdx = size - 1;
498 while (leftIdx <= rightIdx) {
499 // Find the next element to remove moving left to right.
500 while (leftIdx < size && !predicate.test(collection.get(leftIdx))) {
501 leftIdx++;
502 }
503
504 // Find the next element to keep moving right to left.
505 while (rightIdx > leftIdx && predicate.test(collection.get(rightIdx))) {
506 rightIdx--;
507 }
508
509 if (leftIdx >= rightIdx) {
510 // Done.
511 break;
512 }
513
514 Collections.swap(collection, leftIdx, rightIdx);
515 leftIdx++;
516 rightIdx--;
517 }
518
519 // leftIdx is now at the end.
520 for (int i = size - 1; i >= leftIdx; i--) {
521 collection.remove(i);
522 }
523 return size - leftIdx;
524 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800525}