blob: ff5b9968a4086934e36c4edc67400ea91b663778 [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
Jeff Sharkeyb0c363b22018-12-15 11:53:03 -070027import java.io.File;
Adam Lesinski776abc22014-03-07 11:30:59 -050028import java.lang.reflect.Array;
Jeff Sharkeyda96e132014-07-15 14:54:09 -070029import java.util.ArrayList;
Jeff Sharkey2bd31db2016-01-09 16:58:14 -070030import java.util.Arrays;
Jeff Sharkey42884192016-04-09 16:12:01 -060031import java.util.Collection;
Adam Lesinski082614c2016-03-04 14:33:47 -080032import java.util.Collections;
Jeff Sharkey3e195892016-03-05 19:48:59 -070033import java.util.List;
Makoto Onuki3aaed292017-11-15 16:31:24 -080034import java.util.Map;
Jeff Sharkey59d577a2015-04-11 21:27:21 -070035import java.util.Objects;
Eugene Susla31c9cd12018-12-03 15:41:31 -080036import java.util.function.IntFunction;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037
38/**
39 * ArrayUtils contains some methods that you can call to find out
40 * the most efficient increments by which to grow arrays.
41 */
Jeff Sharkey59d577a2015-04-11 21:27:21 -070042public class ArrayUtils {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043 private static final int CACHE_SIZE = 73;
44 private static Object[] sCache = new Object[CACHE_SIZE];
45
Jeff Sharkeyb0c363b22018-12-15 11:53:03 -070046 public static final File[] EMPTY_FILE = new File[0];
47
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048 private ArrayUtils() { /* cannot be instantiated */ }
49
Adam Lesinski776abc22014-03-07 11:30:59 -050050 public static byte[] newUnpaddedByteArray(int minLen) {
51 return (byte[])VMRuntime.getRuntime().newUnpaddedArray(byte.class, minLen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052 }
53
Adam Lesinski776abc22014-03-07 11:30:59 -050054 public static char[] newUnpaddedCharArray(int minLen) {
55 return (char[])VMRuntime.getRuntime().newUnpaddedArray(char.class, minLen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056 }
57
Adam Lesinski776abc22014-03-07 11:30:59 -050058 public static int[] newUnpaddedIntArray(int minLen) {
59 return (int[])VMRuntime.getRuntime().newUnpaddedArray(int.class, minLen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060 }
61
Adam Lesinski776abc22014-03-07 11:30:59 -050062 public static boolean[] newUnpaddedBooleanArray(int minLen) {
63 return (boolean[])VMRuntime.getRuntime().newUnpaddedArray(boolean.class, minLen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064 }
65
Adam Lesinski776abc22014-03-07 11:30:59 -050066 public static long[] newUnpaddedLongArray(int minLen) {
67 return (long[])VMRuntime.getRuntime().newUnpaddedArray(long.class, minLen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068 }
69
Adam Lesinski776abc22014-03-07 11:30:59 -050070 public static float[] newUnpaddedFloatArray(int minLen) {
71 return (float[])VMRuntime.getRuntime().newUnpaddedArray(float.class, minLen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072 }
73
Adam Lesinski776abc22014-03-07 11:30:59 -050074 public static Object[] newUnpaddedObjectArray(int minLen) {
75 return (Object[])VMRuntime.getRuntime().newUnpaddedArray(Object.class, minLen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076 }
77
Adam Lesinski776abc22014-03-07 11:30:59 -050078 @SuppressWarnings("unchecked")
79 public static <T> T[] newUnpaddedArray(Class<T> clazz, int minLen) {
80 return (T[])VMRuntime.getRuntime().newUnpaddedArray(clazz, minLen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081 }
82
83 /**
84 * Checks if the beginnings of two byte arrays are equal.
85 *
86 * @param array1 the first byte array
87 * @param array2 the second byte array
88 * @param length the number of bytes to check
89 * @return true if they're equal, false otherwise
90 */
91 public static boolean equals(byte[] array1, byte[] array2, int length) {
Christopher Tatefc054342013-03-22 15:01:13 -070092 if (length < 0) {
93 throw new IllegalArgumentException();
94 }
95
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096 if (array1 == array2) {
97 return true;
98 }
99 if (array1 == null || array2 == null || array1.length < length || array2.length < length) {
100 return false;
101 }
102 for (int i = 0; i < length; i++) {
103 if (array1[i] != array2[i]) {
104 return false;
105 }
106 }
107 return true;
108 }
109
110 /**
111 * Returns an empty array of the specified type. The intent is that
112 * it will return the same empty array every time to avoid reallocation,
113 * although this is not guaranteed.
114 */
Adam Lesinski776abc22014-03-07 11:30:59 -0500115 @SuppressWarnings("unchecked")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116 public static <T> T[] emptyArray(Class<T> kind) {
117 if (kind == Object.class) {
Adam Lesinski776abc22014-03-07 11:30:59 -0500118 return (T[]) EmptyArray.OBJECT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119 }
120
Mathieu Chartierb4e50612014-09-10 12:56:21 -0700121 int bucket = (kind.hashCode() & 0x7FFFFFFF) % CACHE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122 Object cache = sCache[bucket];
123
124 if (cache == null || cache.getClass().getComponentType() != kind) {
125 cache = Array.newInstance(kind, 0);
126 sCache[bucket] = cache;
127
128 // Log.e("cache", "new empty " + kind.getName() + " at " + bucket);
129 }
130
131 return (T[]) cache;
132 }
133
134 /**
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700135 * Checks if given array is null or has zero elements.
136 */
Jeff Sharkey42884192016-04-09 16:12:01 -0600137 public static boolean isEmpty(@Nullable Collection<?> array) {
Jeff Sharkey3e195892016-03-05 19:48:59 -0700138 return array == null || array.isEmpty();
139 }
140
141 /**
Makoto Onuki3aaed292017-11-15 16:31:24 -0800142 * Checks if given map is null or has zero elements.
143 */
144 public static boolean isEmpty(@Nullable Map<?, ?> map) {
145 return map == null || map.isEmpty();
146 }
147
148 /**
Jeff Sharkey3e195892016-03-05 19:48:59 -0700149 * Checks if given array is null or has zero elements.
150 */
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700151 public static <T> boolean isEmpty(@Nullable T[] array) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700152 return array == null || array.length == 0;
153 }
154
155 /**
Jeff Sharkey32566012014-12-02 18:30:14 -0800156 * Checks if given array is null or has zero elements.
157 */
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700158 public static boolean isEmpty(@Nullable int[] array) {
Jeff Sharkey32566012014-12-02 18:30:14 -0800159 return array == null || array.length == 0;
160 }
161
162 /**
163 * Checks if given array is null or has zero elements.
164 */
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700165 public static boolean isEmpty(@Nullable long[] array) {
Jeff Sharkey32566012014-12-02 18:30:14 -0800166 return array == null || array.length == 0;
167 }
168
169 /**
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800170 * Checks if given array is null or has zero elements.
171 */
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700172 public static boolean isEmpty(@Nullable byte[] array) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800173 return array == null || array.length == 0;
174 }
175
176 /**
Svetoslav Ganova8bbd762016-05-13 17:08:16 -0700177 * Checks if given array is null or has zero elements.
178 */
179 public static boolean isEmpty(@Nullable boolean[] array) {
180 return array == null || array.length == 0;
181 }
182
183 /**
Eugene Suslaaa43a4b2017-04-21 14:12:00 -0700184 * Length of the given array or 0 if it's null.
185 */
186 public static int size(@Nullable Object[] array) {
187 return array == null ? 0 : array.length;
188 }
189
190 /**
Makoto Onuki5d93b832018-01-10 16:12:39 -0800191 * Length of the given collection or 0 if it's null.
192 */
193 public static int size(@Nullable Collection<?> collection) {
194 return collection == null ? 0 : collection.size();
195 }
196
197 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198 * Checks that value is present as at least one of the elements of the array.
199 * @param array the array to check in
200 * @param value the value to check for
201 * @return true if the value is present in the array
202 */
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700203 public static <T> boolean contains(@Nullable T[] array, T value) {
Jeff Sharkey94c91dc2013-03-06 16:25:50 -0800204 return indexOf(array, value) != -1;
205 }
206
207 /**
208 * Return first index of {@code value} in {@code array}, or {@code -1} if
209 * not found.
210 */
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700211 public static <T> int indexOf(@Nullable T[] array, T value) {
Jeff Sharkey57dcf5b2014-06-18 17:46:05 -0700212 if (array == null) return -1;
Jeff Sharkey94c91dc2013-03-06 16:25:50 -0800213 for (int i = 0; i < array.length; i++) {
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700214 if (Objects.equals(array[i], value)) return i;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800215 }
Jeff Sharkey94c91dc2013-03-06 16:25:50 -0800216 return -1;
217 }
218
219 /**
220 * Test if all {@code check} items are contained in {@code array}.
221 */
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700222 public static <T> boolean containsAll(@Nullable T[] array, T[] check) {
Jeff Sharkey32566012014-12-02 18:30:14 -0800223 if (check == null) return true;
Jeff Sharkey94c91dc2013-03-06 16:25:50 -0800224 for (T checkItem : check) {
225 if (!contains(array, checkItem)) {
226 return false;
227 }
228 }
229 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800230 }
Jeff Sharkey630a1712011-09-26 10:47:10 -0700231
Jeff Sharkey35871f22016-01-29 17:13:29 -0700232 /**
233 * Test if any {@code check} items are contained in {@code array}.
234 */
235 public static <T> boolean containsAny(@Nullable T[] array, T[] check) {
236 if (check == null) return false;
237 for (T checkItem : check) {
238 if (contains(array, checkItem)) {
239 return true;
240 }
241 }
242 return false;
243 }
244
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700245 public static boolean contains(@Nullable int[] array, int value) {
Jeff Sharkey57dcf5b2014-06-18 17:46:05 -0700246 if (array == null) return false;
Jeff Sharkey630a1712011-09-26 10:47:10 -0700247 for (int element : array) {
248 if (element == value) {
249 return true;
250 }
251 }
252 return false;
253 }
Jeff Brown96e942d2011-11-30 19:55:01 -0800254
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700255 public static boolean contains(@Nullable long[] array, long value) {
Jeff Sharkey57dcf5b2014-06-18 17:46:05 -0700256 if (array == null) return false;
dcashman874d0d42014-05-30 09:34:04 -0700257 for (long element : array) {
258 if (element == value) {
259 return true;
260 }
261 }
262 return false;
263 }
264
Roozbeh Pournader889c6502017-02-15 18:19:09 -0800265 public static boolean contains(@Nullable char[] array, char value) {
266 if (array == null) return false;
267 for (char element : array) {
268 if (element == value) {
269 return true;
270 }
271 }
272 return false;
273 }
274
275 /**
276 * Test if all {@code check} items are contained in {@code array}.
277 */
278 public static <T> boolean containsAll(@Nullable char[] array, char[] check) {
279 if (check == null) return true;
280 for (char checkItem : check) {
281 if (!contains(array, checkItem)) {
282 return false;
283 }
284 }
285 return true;
286 }
287
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700288 public static long total(@Nullable long[] array) {
Jeff Sharkey63abc372012-01-11 18:38:16 -0800289 long total = 0;
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700290 if (array != null) {
291 for (long value : array) {
292 total += value;
293 }
Jeff Sharkey63abc372012-01-11 18:38:16 -0800294 }
295 return total;
296 }
297
Chong Zhang167bbfac2016-03-31 09:44:34 -0700298 public static int[] convertToIntArray(List<Integer> list) {
299 int[] array = new int[list.size()];
300 for (int i = 0; i < list.size(); i++) {
301 array[i] = list.get(i);
302 }
303 return array;
304 }
305
Phil Weaverb9f06122017-11-30 10:48:17 -0800306 public static @Nullable long[] convertToLongArray(@Nullable int[] intArray) {
307 if (intArray == null) return null;
308 long[] array = new long[intArray.length];
309 for (int i = 0; i < intArray.length; i++) {
310 array[i] = (long) intArray[i];
311 }
312 return array;
313 }
314
Jeff Sharkey6adc98c2018-07-12 19:47:49 -0600315 @SuppressWarnings("unchecked")
Jeff Sharkeyb89df9e2018-07-26 14:36:59 -0600316 public static @NonNull <T> T[] concatElements(Class<T> kind, @Nullable T[] a, @Nullable T[] b) {
Jeff Sharkey6adc98c2018-07-12 19:47:49 -0600317 final int an = (a != null) ? a.length : 0;
318 final int bn = (b != null) ? b.length : 0;
319 if (an == 0 && bn == 0) {
320 if (kind == String.class) {
321 return (T[]) EmptyArray.STRING;
322 } else if (kind == Object.class) {
323 return (T[]) EmptyArray.OBJECT;
324 }
325 }
326 final T[] res = (T[]) Array.newInstance(kind, an + bn);
327 if (an > 0) System.arraycopy(a, 0, res, 0, an);
328 if (bn > 0) System.arraycopy(b, 0, res, an, bn);
329 return res;
330 }
331
Jeff Brown96e942d2011-11-30 19:55:01 -0800332 /**
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700333 * Adds value to given array if not already present, providing set-like
334 * behavior.
Jeff Brown96e942d2011-11-30 19:55:01 -0800335 */
336 @SuppressWarnings("unchecked")
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700337 public static @NonNull <T> T[] appendElement(Class<T> kind, @Nullable T[] array, T element) {
Svet Ganov8a10ef52017-02-16 20:58:09 -0800338 return appendElement(kind, array, element, false);
339 }
340
341 /**
342 * Adds value to given array.
343 */
344 @SuppressWarnings("unchecked")
345 public static @NonNull <T> T[] appendElement(Class<T> kind, @Nullable T[] array, T element,
346 boolean allowDuplicates) {
Jeff Brown96e942d2011-11-30 19:55:01 -0800347 final T[] result;
348 final int end;
349 if (array != null) {
Svet Ganov8a10ef52017-02-16 20:58:09 -0800350 if (!allowDuplicates && contains(array, element)) return array;
Jeff Brown96e942d2011-11-30 19:55:01 -0800351 end = array.length;
352 result = (T[])Array.newInstance(kind, end + 1);
353 System.arraycopy(array, 0, result, 0, end);
354 } else {
355 end = 0;
356 result = (T[])Array.newInstance(kind, 1);
357 }
358 result[end] = element;
359 return result;
360 }
361
362 /**
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700363 * Removes value from given array if present, providing set-like behavior.
Jeff Brown96e942d2011-11-30 19:55:01 -0800364 */
365 @SuppressWarnings("unchecked")
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700366 public static @Nullable <T> T[] removeElement(Class<T> kind, @Nullable T[] array, T element) {
Jeff Brown96e942d2011-11-30 19:55:01 -0800367 if (array != null) {
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700368 if (!contains(array, element)) return array;
Jeff Brown96e942d2011-11-30 19:55:01 -0800369 final int length = array.length;
370 for (int i = 0; i < length; i++) {
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700371 if (Objects.equals(array[i], element)) {
Jeff Brown96e942d2011-11-30 19:55:01 -0800372 if (length == 1) {
373 return null;
374 }
375 T[] result = (T[])Array.newInstance(kind, length - 1);
376 System.arraycopy(array, 0, result, 0, i);
377 System.arraycopy(array, i + 1, result, i, length - i - 1);
378 return result;
379 }
380 }
381 }
382 return array;
383 }
Jeff Sharkey854b2b12012-04-13 16:03:40 -0700384
dcashman874d0d42014-05-30 09:34:04 -0700385 /**
Svet Ganov8a10ef52017-02-16 20:58:09 -0800386 * Adds value to given array.
dcashman874d0d42014-05-30 09:34:04 -0700387 */
Svet Ganov8a10ef52017-02-16 20:58:09 -0800388 public static @NonNull int[] appendInt(@Nullable int[] cur, int val,
389 boolean allowDuplicates) {
Jeff Sharkey854b2b12012-04-13 16:03:40 -0700390 if (cur == null) {
391 return new int[] { val };
392 }
393 final int N = cur.length;
Svet Ganov8a10ef52017-02-16 20:58:09 -0800394 if (!allowDuplicates) {
395 for (int i = 0; i < N; i++) {
396 if (cur[i] == val) {
397 return cur;
398 }
Jeff Sharkey854b2b12012-04-13 16:03:40 -0700399 }
400 }
401 int[] ret = new int[N + 1];
402 System.arraycopy(cur, 0, ret, 0, N);
403 ret[N] = val;
404 return ret;
405 }
406
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700407 /**
Svet Ganov8a10ef52017-02-16 20:58:09 -0800408 * Adds value to given array if not already present, providing set-like
409 * behavior.
410 */
411 public static @NonNull int[] appendInt(@Nullable int[] cur, int val) {
412 return appendInt(cur, val, false);
413 }
414
415 /**
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700416 * Removes value from given array if present, providing set-like behavior.
417 */
418 public static @Nullable int[] removeInt(@Nullable int[] cur, int val) {
Jeff Sharkey854b2b12012-04-13 16:03:40 -0700419 if (cur == null) {
420 return null;
421 }
422 final int N = cur.length;
423 for (int i = 0; i < N; i++) {
424 if (cur[i] == val) {
425 int[] ret = new int[N - 1];
426 if (i > 0) {
427 System.arraycopy(cur, 0, ret, 0, i);
428 }
429 if (i < (N - 1)) {
430 System.arraycopy(cur, i + 1, ret, i, N - i - 1);
431 }
432 return ret;
433 }
434 }
435 return cur;
436 }
dcashman874d0d42014-05-30 09:34:04 -0700437
438 /**
Svet Ganov52153f42015-08-11 08:59:12 -0700439 * Removes value from given array if present, providing set-like behavior.
440 */
441 public static @Nullable String[] removeString(@Nullable String[] cur, String val) {
442 if (cur == null) {
443 return null;
444 }
445 final int N = cur.length;
446 for (int i = 0; i < N; i++) {
447 if (Objects.equals(cur[i], val)) {
448 String[] ret = new String[N - 1];
449 if (i > 0) {
450 System.arraycopy(cur, 0, ret, 0, i);
451 }
452 if (i < (N - 1)) {
453 System.arraycopy(cur, i + 1, ret, i, N - i - 1);
454 }
455 return ret;
456 }
457 }
458 return cur;
459 }
460
461 /**
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700462 * Adds value to given array if not already present, providing set-like
463 * behavior.
dcashman874d0d42014-05-30 09:34:04 -0700464 */
Dianne Hackborn3accca02013-09-20 09:32:11 -0700465 public static @NonNull long[] appendLong(@Nullable long[] cur, long val,
466 boolean allowDuplicates) {
dcashman874d0d42014-05-30 09:34:04 -0700467 if (cur == null) {
468 return new long[] { val };
469 }
470 final int N = cur.length;
Dianne Hackborn3accca02013-09-20 09:32:11 -0700471 if (!allowDuplicates) {
472 for (int i = 0; i < N; i++) {
473 if (cur[i] == val) {
474 return cur;
475 }
dcashman874d0d42014-05-30 09:34:04 -0700476 }
477 }
478 long[] ret = new long[N + 1];
479 System.arraycopy(cur, 0, ret, 0, N);
480 ret[N] = val;
481 return ret;
482 }
483
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700484 /**
Dianne Hackborn3accca02013-09-20 09:32:11 -0700485 * Adds value to given array if not already present, providing set-like
486 * behavior.
487 */
488 public static @NonNull long[] appendLong(@Nullable long[] cur, long val) {
489 return appendLong(cur, val, false);
490 }
491
492 /**
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700493 * Removes value from given array if present, providing set-like behavior.
494 */
495 public static @Nullable long[] removeLong(@Nullable long[] cur, long val) {
dcashman874d0d42014-05-30 09:34:04 -0700496 if (cur == null) {
497 return null;
498 }
499 final int N = cur.length;
500 for (int i = 0; i < N; i++) {
501 if (cur[i] == val) {
502 long[] ret = new long[N - 1];
503 if (i > 0) {
504 System.arraycopy(cur, 0, ret, 0, i);
505 }
506 if (i < (N - 1)) {
507 System.arraycopy(cur, i + 1, ret, i, N - i - 1);
508 }
509 return ret;
510 }
511 }
512 return cur;
513 }
Jeff Sharkey57dcf5b2014-06-18 17:46:05 -0700514
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700515 public static @Nullable long[] cloneOrNull(@Nullable long[] array) {
Jeff Sharkey57dcf5b2014-06-18 17:46:05 -0700516 return (array != null) ? array.clone() : null;
517 }
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700518
Jeff Sharkey2bd31db2016-01-09 16:58:14 -0700519 public static @Nullable <T> ArraySet<T> cloneOrNull(@Nullable ArraySet<T> array) {
520 return (array != null) ? new ArraySet<T>(array) : null;
521 }
522
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700523 public static @NonNull <T> ArraySet<T> add(@Nullable ArraySet<T> cur, T val) {
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700524 if (cur == null) {
525 cur = new ArraySet<>();
526 }
527 cur.add(val);
528 return cur;
529 }
530
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700531 public static @Nullable <T> ArraySet<T> remove(@Nullable ArraySet<T> cur, T val) {
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700532 if (cur == null) {
533 return null;
534 }
535 cur.remove(val);
536 if (cur.isEmpty()) {
537 return null;
538 } else {
539 return cur;
540 }
541 }
542
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700543 public static @NonNull <T> ArrayList<T> add(@Nullable ArrayList<T> cur, T val) {
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700544 if (cur == null) {
545 cur = new ArrayList<>();
546 }
547 cur.add(val);
548 return cur;
549 }
550
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700551 public static @Nullable <T> ArrayList<T> remove(@Nullable ArrayList<T> cur, T val) {
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700552 if (cur == null) {
553 return null;
554 }
555 cur.remove(val);
556 if (cur.isEmpty()) {
557 return null;
558 } else {
559 return cur;
560 }
561 }
562
Jeff Sharkey42884192016-04-09 16:12:01 -0600563 public static <T> boolean contains(@Nullable Collection<T> cur, T val) {
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700564 return (cur != null) ? cur.contains(val) : false;
565 }
Adam Lesinski72478f02015-06-17 15:39:43 -0700566
Jeff Sharkey2bd31db2016-01-09 16:58:14 -0700567 public static @Nullable <T> T[] trimToSize(@Nullable T[] array, int size) {
568 if (array == null || size == 0) {
569 return null;
570 } else if (array.length == size) {
571 return array;
572 } else {
573 return Arrays.copyOf(array, size);
574 }
575 }
576
Adam Lesinski72478f02015-06-17 15:39:43 -0700577 /**
578 * Returns true if the two ArrayLists are equal with respect to the objects they contain.
579 * The objects must be in the same order and be reference equal (== not .equals()).
580 */
581 public static <T> boolean referenceEquals(ArrayList<T> a, ArrayList<T> b) {
582 if (a == b) {
583 return true;
584 }
585
586 final int sizeA = a.size();
587 final int sizeB = b.size();
588 if (a == null || b == null || sizeA != sizeB) {
589 return false;
590 }
591
592 boolean diff = false;
593 for (int i = 0; i < sizeA && !diff; i++) {
594 diff |= a.get(i) != b.get(i);
595 }
596 return !diff;
597 }
Adam Lesinski082614c2016-03-04 14:33:47 -0800598
599 /**
600 * Removes elements that match the predicate in an efficient way that alters the order of
601 * elements in the collection. This should only be used if order is not important.
602 * @param collection The ArrayList from which to remove elements.
603 * @param predicate The predicate that each element is tested against.
604 * @return the number of elements removed.
605 */
606 public static <T> int unstableRemoveIf(@Nullable ArrayList<T> collection,
607 @NonNull java.util.function.Predicate<T> predicate) {
608 if (collection == null) {
609 return 0;
610 }
611
612 final int size = collection.size();
613 int leftIdx = 0;
614 int rightIdx = size - 1;
615 while (leftIdx <= rightIdx) {
616 // Find the next element to remove moving left to right.
617 while (leftIdx < size && !predicate.test(collection.get(leftIdx))) {
618 leftIdx++;
619 }
620
621 // Find the next element to keep moving right to left.
622 while (rightIdx > leftIdx && predicate.test(collection.get(rightIdx))) {
623 rightIdx--;
624 }
625
626 if (leftIdx >= rightIdx) {
627 // Done.
628 break;
629 }
630
631 Collections.swap(collection, leftIdx, rightIdx);
632 leftIdx++;
633 rightIdx--;
634 }
635
636 // leftIdx is now at the end.
637 for (int i = size - 1; i >= leftIdx; i--) {
638 collection.remove(i);
639 }
640 return size - leftIdx;
641 }
Jeff Sharkey2abd66c2017-05-05 15:26:13 -0600642
Jeff Sharkey2e471452018-01-19 18:02:47 +0900643 public static @NonNull int[] defeatNullable(@Nullable int[] val) {
644 return (val != null) ? val : EmptyArray.INT;
645 }
646
Jeff Sharkey2abd66c2017-05-05 15:26:13 -0600647 public static @NonNull String[] defeatNullable(@Nullable String[] val) {
648 return (val != null) ? val : EmptyArray.STRING;
649 }
Neil Fuller8a1683f2018-07-03 18:46:10 +0100650
Jeff Sharkeyb0c363b22018-12-15 11:53:03 -0700651 public static @NonNull File[] defeatNullable(@Nullable File[] val) {
652 return (val != null) ? val : EMPTY_FILE;
653 }
654
Neil Fuller8a1683f2018-07-03 18:46:10 +0100655 /**
656 * Throws {@link ArrayIndexOutOfBoundsException} if the index is out of bounds.
657 *
658 * @param len length of the array. Must be non-negative
659 * @param index the index to check
660 * @throws ArrayIndexOutOfBoundsException if the {@code index} is out of bounds of the array
661 */
662 public static void checkBounds(int len, int index) {
663 if (index < 0 || len <= index) {
664 throw new ArrayIndexOutOfBoundsException("length=" + len + "; index=" + index);
665 }
666 }
Eugene Susla31c9cd12018-12-03 15:41:31 -0800667
668 /**
669 * Returns an array with values from {@code val} minus {@code null} values
670 *
671 * @param arrayConstructor typically {@code T[]::new} e.g. {@code String[]::new}
672 */
673 public static <T> T[] filterNotNull(T[] val, IntFunction<T[]> arrayConstructor) {
674 int nullCount = 0;
675 int size = size(val);
676 for (int i = 0; i < size; i++) {
677 if (val[i] == null) {
678 nullCount++;
679 }
680 }
681 if (nullCount == 0) {
682 return val;
683 }
684 T[] result = arrayConstructor.apply(size - nullCount);
685 int outIdx = 0;
686 for (int i = 0; i < size; i++) {
687 if (val[i] != null) {
688 result[outIdx++] = val[i];
689 }
690 }
691 return result;
692 }
Eugene Susla8758d322019-01-24 16:31:15 -0800693
Jeff Sharkeyd95d0d22019-01-31 17:51:32 -0700694 public static boolean startsWith(byte[] cur, byte[] val) {
695 if (cur == null || val == null) return false;
696 if (cur.length < val.length) return false;
697 for (int i = 0; i < val.length; i++) {
698 if (cur[i] != val[i]) return false;
699 }
700 return true;
701 }
702
Eugene Susla8758d322019-01-24 16:31:15 -0800703 /**
704 * Returns the first element from the array for which
705 * condition {@code predicate} is true, or null if there is no such element
706 */
707 public static @Nullable <T> T find(@Nullable T[] items,
708 @NonNull java.util.function.Predicate<T> predicate) {
709 if (isEmpty(items)) return null;
710 for (final T item : items) {
711 if (predicate.test(item)) return item;
712 }
713 return null;
714 }
Jeff Sharkeybffd2502019-02-28 16:39:12 -0700715
716 public static String deepToString(Object value) {
717 if (value != null && value.getClass().isArray()) {
718 if (value.getClass() == boolean[].class) {
719 return Arrays.toString((boolean[]) value);
720 } else if (value.getClass() == byte[].class) {
721 return Arrays.toString((byte[]) value);
722 } else if (value.getClass() == char[].class) {
723 return Arrays.toString((char[]) value);
724 } else if (value.getClass() == double[].class) {
725 return Arrays.toString((double[]) value);
726 } else if (value.getClass() == float[].class) {
727 return Arrays.toString((float[]) value);
728 } else if (value.getClass() == int[].class) {
729 return Arrays.toString((int[]) value);
730 } else if (value.getClass() == long[].class) {
731 return Arrays.toString((long[]) value);
732 } else if (value.getClass() == short[].class) {
733 return Arrays.toString((short[]) value);
734 } else {
735 return Arrays.deepToString((Object[]) value);
736 }
737 } else {
738 return String.valueOf(value);
739 }
740 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800741}