1 /* 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 17 package com.android.internal.util; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.compat.annotation.UnsupportedAppUsage; 22 import android.util.ArraySet; 23 24 import dalvik.system.VMRuntime; 25 26 import libcore.util.EmptyArray; 27 28 import java.io.File; 29 import java.lang.reflect.Array; 30 import java.util.ArrayList; 31 import java.util.Arrays; 32 import java.util.Collection; 33 import java.util.Collections; 34 import java.util.List; 35 import java.util.Map; 36 import java.util.Objects; 37 import java.util.function.IntFunction; 38 39 /** 40 * ArrayUtils contains some methods that you can call to find out 41 * the most efficient increments by which to grow arrays. 42 */ 43 public class ArrayUtils { 44 private static final int CACHE_SIZE = 73; 45 private static Object[] sCache = new Object[CACHE_SIZE]; 46 47 public static final File[] EMPTY_FILE = new File[0]; 48 ArrayUtils()49 private ArrayUtils() { /* cannot be instantiated */ } 50 newUnpaddedByteArray(int minLen)51 public static byte[] newUnpaddedByteArray(int minLen) { 52 return (byte[])VMRuntime.getRuntime().newUnpaddedArray(byte.class, minLen); 53 } 54 newUnpaddedCharArray(int minLen)55 public static char[] newUnpaddedCharArray(int minLen) { 56 return (char[])VMRuntime.getRuntime().newUnpaddedArray(char.class, minLen); 57 } 58 59 @UnsupportedAppUsage newUnpaddedIntArray(int minLen)60 public static int[] newUnpaddedIntArray(int minLen) { 61 return (int[])VMRuntime.getRuntime().newUnpaddedArray(int.class, minLen); 62 } 63 newUnpaddedBooleanArray(int minLen)64 public static boolean[] newUnpaddedBooleanArray(int minLen) { 65 return (boolean[])VMRuntime.getRuntime().newUnpaddedArray(boolean.class, minLen); 66 } 67 newUnpaddedLongArray(int minLen)68 public static long[] newUnpaddedLongArray(int minLen) { 69 return (long[])VMRuntime.getRuntime().newUnpaddedArray(long.class, minLen); 70 } 71 newUnpaddedFloatArray(int minLen)72 public static float[] newUnpaddedFloatArray(int minLen) { 73 return (float[])VMRuntime.getRuntime().newUnpaddedArray(float.class, minLen); 74 } 75 newUnpaddedObjectArray(int minLen)76 public static Object[] newUnpaddedObjectArray(int minLen) { 77 return (Object[])VMRuntime.getRuntime().newUnpaddedArray(Object.class, minLen); 78 } 79 80 @UnsupportedAppUsage 81 @SuppressWarnings("unchecked") newUnpaddedArray(Class<T> clazz, int minLen)82 public static <T> T[] newUnpaddedArray(Class<T> clazz, int minLen) { 83 return (T[])VMRuntime.getRuntime().newUnpaddedArray(clazz, minLen); 84 } 85 86 /** 87 * Checks if the beginnings of two byte arrays are equal. 88 * 89 * @param array1 the first byte array 90 * @param array2 the second byte array 91 * @param length the number of bytes to check 92 * @return true if they're equal, false otherwise 93 */ equals(byte[] array1, byte[] array2, int length)94 public static boolean equals(byte[] array1, byte[] array2, int length) { 95 if (length < 0) { 96 throw new IllegalArgumentException(); 97 } 98 99 if (array1 == array2) { 100 return true; 101 } 102 if (array1 == null || array2 == null || array1.length < length || array2.length < length) { 103 return false; 104 } 105 for (int i = 0; i < length; i++) { 106 if (array1[i] != array2[i]) { 107 return false; 108 } 109 } 110 return true; 111 } 112 113 /** 114 * Returns an empty array of the specified type. The intent is that 115 * it will return the same empty array every time to avoid reallocation, 116 * although this is not guaranteed. 117 */ 118 @UnsupportedAppUsage 119 @SuppressWarnings("unchecked") emptyArray(Class<T> kind)120 public static <T> T[] emptyArray(Class<T> kind) { 121 if (kind == Object.class) { 122 return (T[]) EmptyArray.OBJECT; 123 } 124 125 int bucket = (kind.hashCode() & 0x7FFFFFFF) % CACHE_SIZE; 126 Object cache = sCache[bucket]; 127 128 if (cache == null || cache.getClass().getComponentType() != kind) { 129 cache = Array.newInstance(kind, 0); 130 sCache[bucket] = cache; 131 132 // Log.e("cache", "new empty " + kind.getName() + " at " + bucket); 133 } 134 135 return (T[]) cache; 136 } 137 138 /** 139 * Returns the same array or an empty one if it's null. 140 */ emptyIfNull(@ullable T[] items, Class<T> kind)141 public static @NonNull <T> T[] emptyIfNull(@Nullable T[] items, Class<T> kind) { 142 return items != null ? items : emptyArray(kind); 143 } 144 145 /** 146 * Checks if given array is null or has zero elements. 147 */ isEmpty(@ullable Collection<?> array)148 public static boolean isEmpty(@Nullable Collection<?> array) { 149 return array == null || array.isEmpty(); 150 } 151 152 /** 153 * Checks if given map is null or has zero elements. 154 */ isEmpty(@ullable Map<?, ?> map)155 public static boolean isEmpty(@Nullable Map<?, ?> map) { 156 return map == null || map.isEmpty(); 157 } 158 159 /** 160 * Checks if given array is null or has zero elements. 161 */ 162 @UnsupportedAppUsage isEmpty(@ullable T[] array)163 public static <T> boolean isEmpty(@Nullable T[] array) { 164 return array == null || array.length == 0; 165 } 166 167 /** 168 * Checks if given array is null or has zero elements. 169 */ isEmpty(@ullable int[] array)170 public static boolean isEmpty(@Nullable int[] array) { 171 return array == null || array.length == 0; 172 } 173 174 /** 175 * Checks if given array is null or has zero elements. 176 */ isEmpty(@ullable long[] array)177 public static boolean isEmpty(@Nullable long[] array) { 178 return array == null || array.length == 0; 179 } 180 181 /** 182 * Checks if given array is null or has zero elements. 183 */ isEmpty(@ullable byte[] array)184 public static boolean isEmpty(@Nullable byte[] array) { 185 return array == null || array.length == 0; 186 } 187 188 /** 189 * Checks if given array is null or has zero elements. 190 */ isEmpty(@ullable boolean[] array)191 public static boolean isEmpty(@Nullable boolean[] array) { 192 return array == null || array.length == 0; 193 } 194 195 /** 196 * Length of the given array or 0 if it's null. 197 */ size(@ullable Object[] array)198 public static int size(@Nullable Object[] array) { 199 return array == null ? 0 : array.length; 200 } 201 202 /** 203 * Length of the given collection or 0 if it's null. 204 */ size(@ullable Collection<?> collection)205 public static int size(@Nullable Collection<?> collection) { 206 return collection == null ? 0 : collection.size(); 207 } 208 209 /** 210 * Checks that value is present as at least one of the elements of the array. 211 * @param array the array to check in 212 * @param value the value to check for 213 * @return true if the value is present in the array 214 */ 215 @UnsupportedAppUsage contains(@ullable T[] array, T value)216 public static <T> boolean contains(@Nullable T[] array, T value) { 217 return indexOf(array, value) != -1; 218 } 219 220 /** 221 * Return first index of {@code value} in {@code array}, or {@code -1} if 222 * not found. 223 */ 224 @UnsupportedAppUsage indexOf(@ullable T[] array, T value)225 public static <T> int indexOf(@Nullable T[] array, T value) { 226 if (array == null) return -1; 227 for (int i = 0; i < array.length; i++) { 228 if (Objects.equals(array[i], value)) return i; 229 } 230 return -1; 231 } 232 233 /** 234 * Test if all {@code check} items are contained in {@code array}. 235 */ containsAll(@ullable T[] array, T[] check)236 public static <T> boolean containsAll(@Nullable T[] array, T[] check) { 237 if (check == null) return true; 238 for (T checkItem : check) { 239 if (!contains(array, checkItem)) { 240 return false; 241 } 242 } 243 return true; 244 } 245 246 /** 247 * Test if any {@code check} items are contained in {@code array}. 248 */ containsAny(@ullable T[] array, T[] check)249 public static <T> boolean containsAny(@Nullable T[] array, T[] check) { 250 if (check == null) return false; 251 for (T checkItem : check) { 252 if (contains(array, checkItem)) { 253 return true; 254 } 255 } 256 return false; 257 } 258 259 @UnsupportedAppUsage contains(@ullable int[] array, int value)260 public static boolean contains(@Nullable int[] array, int value) { 261 if (array == null) return false; 262 for (int element : array) { 263 if (element == value) { 264 return true; 265 } 266 } 267 return false; 268 } 269 contains(@ullable long[] array, long value)270 public static boolean contains(@Nullable long[] array, long value) { 271 if (array == null) return false; 272 for (long element : array) { 273 if (element == value) { 274 return true; 275 } 276 } 277 return false; 278 } 279 contains(@ullable char[] array, char value)280 public static boolean contains(@Nullable char[] array, char value) { 281 if (array == null) return false; 282 for (char element : array) { 283 if (element == value) { 284 return true; 285 } 286 } 287 return false; 288 } 289 290 /** 291 * Test if all {@code check} items are contained in {@code array}. 292 */ containsAll(@ullable char[] array, char[] check)293 public static <T> boolean containsAll(@Nullable char[] array, char[] check) { 294 if (check == null) return true; 295 for (char checkItem : check) { 296 if (!contains(array, checkItem)) { 297 return false; 298 } 299 } 300 return true; 301 } 302 total(@ullable long[] array)303 public static long total(@Nullable long[] array) { 304 long total = 0; 305 if (array != null) { 306 for (long value : array) { 307 total += value; 308 } 309 } 310 return total; 311 } 312 convertToIntArray(List<Integer> list)313 public static int[] convertToIntArray(List<Integer> list) { 314 int[] array = new int[list.size()]; 315 for (int i = 0; i < list.size(); i++) { 316 array[i] = list.get(i); 317 } 318 return array; 319 } 320 convertToLongArray(@ullable int[] intArray)321 public static @Nullable long[] convertToLongArray(@Nullable int[] intArray) { 322 if (intArray == null) return null; 323 long[] array = new long[intArray.length]; 324 for (int i = 0; i < intArray.length; i++) { 325 array[i] = (long) intArray[i]; 326 } 327 return array; 328 } 329 330 /** 331 * Combine multiple arrays into a single array. 332 * 333 * @param kind The class of the array elements 334 * @param arrays The arrays to combine 335 * @param <T> The class of the array elements (inferred from kind). 336 * @return A single array containing all the elements of the parameter arrays. 337 */ 338 @SuppressWarnings("unchecked") concatElements(Class<T> kind, @Nullable T[]... arrays)339 public static @NonNull <T> T[] concatElements(Class<T> kind, @Nullable T[]... arrays) { 340 if (arrays == null || arrays.length == 0) { 341 return createEmptyArray(kind); 342 } 343 344 int totalLength = 0; 345 for (T[] item : arrays) { 346 if (item == null) { 347 continue; 348 } 349 350 totalLength += item.length; 351 } 352 353 // Optimization for entirely empty arrays. 354 if (totalLength == 0) { 355 return createEmptyArray(kind); 356 } 357 358 final T[] all = (T[]) Array.newInstance(kind, totalLength); 359 int pos = 0; 360 for (T[] item : arrays) { 361 if (item == null || item.length == 0) { 362 continue; 363 } 364 System.arraycopy(item, 0, all, pos, item.length); 365 pos += item.length; 366 } 367 return all; 368 } 369 createEmptyArray(Class<T> kind)370 private static @NonNull <T> T[] createEmptyArray(Class<T> kind) { 371 if (kind == String.class) { 372 return (T[]) EmptyArray.STRING; 373 } else if (kind == Object.class) { 374 return (T[]) EmptyArray.OBJECT; 375 } 376 377 return (T[]) Array.newInstance(kind, 0); 378 } 379 380 381 /** 382 * Adds value to given array if not already present, providing set-like 383 * behavior. 384 */ 385 @UnsupportedAppUsage 386 @SuppressWarnings("unchecked") appendElement(Class<T> kind, @Nullable T[] array, T element)387 public static @NonNull <T> T[] appendElement(Class<T> kind, @Nullable T[] array, T element) { 388 return appendElement(kind, array, element, false); 389 } 390 391 /** 392 * Adds value to given array. 393 */ 394 @SuppressWarnings("unchecked") appendElement(Class<T> kind, @Nullable T[] array, T element, boolean allowDuplicates)395 public static @NonNull <T> T[] appendElement(Class<T> kind, @Nullable T[] array, T element, 396 boolean allowDuplicates) { 397 final T[] result; 398 final int end; 399 if (array != null) { 400 if (!allowDuplicates && contains(array, element)) return array; 401 end = array.length; 402 result = (T[])Array.newInstance(kind, end + 1); 403 System.arraycopy(array, 0, result, 0, end); 404 } else { 405 end = 0; 406 result = (T[])Array.newInstance(kind, 1); 407 } 408 result[end] = element; 409 return result; 410 } 411 412 /** 413 * Removes value from given array if present, providing set-like behavior. 414 */ 415 @UnsupportedAppUsage 416 @SuppressWarnings("unchecked") removeElement(Class<T> kind, @Nullable T[] array, T element)417 public static @Nullable <T> T[] removeElement(Class<T> kind, @Nullable T[] array, T element) { 418 if (array != null) { 419 if (!contains(array, element)) return array; 420 final int length = array.length; 421 for (int i = 0; i < length; i++) { 422 if (Objects.equals(array[i], element)) { 423 if (length == 1) { 424 return null; 425 } 426 T[] result = (T[])Array.newInstance(kind, length - 1); 427 System.arraycopy(array, 0, result, 0, i); 428 System.arraycopy(array, i + 1, result, i, length - i - 1); 429 return result; 430 } 431 } 432 } 433 return array; 434 } 435 436 /** 437 * Adds value to given array. 438 */ appendInt(@ullable int[] cur, int val, boolean allowDuplicates)439 public static @NonNull int[] appendInt(@Nullable int[] cur, int val, 440 boolean allowDuplicates) { 441 if (cur == null) { 442 return new int[] { val }; 443 } 444 final int N = cur.length; 445 if (!allowDuplicates) { 446 for (int i = 0; i < N; i++) { 447 if (cur[i] == val) { 448 return cur; 449 } 450 } 451 } 452 int[] ret = new int[N + 1]; 453 System.arraycopy(cur, 0, ret, 0, N); 454 ret[N] = val; 455 return ret; 456 } 457 458 /** 459 * Adds value to given array if not already present, providing set-like 460 * behavior. 461 */ 462 @UnsupportedAppUsage appendInt(@ullable int[] cur, int val)463 public static @NonNull int[] appendInt(@Nullable int[] cur, int val) { 464 return appendInt(cur, val, false); 465 } 466 467 /** 468 * Removes value from given array if present, providing set-like behavior. 469 */ removeInt(@ullable int[] cur, int val)470 public static @Nullable int[] removeInt(@Nullable int[] cur, int val) { 471 if (cur == null) { 472 return null; 473 } 474 final int N = cur.length; 475 for (int i = 0; i < N; i++) { 476 if (cur[i] == val) { 477 int[] ret = new int[N - 1]; 478 if (i > 0) { 479 System.arraycopy(cur, 0, ret, 0, i); 480 } 481 if (i < (N - 1)) { 482 System.arraycopy(cur, i + 1, ret, i, N - i - 1); 483 } 484 return ret; 485 } 486 } 487 return cur; 488 } 489 490 /** 491 * Removes value from given array if present, providing set-like behavior. 492 */ removeString(@ullable String[] cur, String val)493 public static @Nullable String[] removeString(@Nullable String[] cur, String val) { 494 if (cur == null) { 495 return null; 496 } 497 final int N = cur.length; 498 for (int i = 0; i < N; i++) { 499 if (Objects.equals(cur[i], val)) { 500 String[] ret = new String[N - 1]; 501 if (i > 0) { 502 System.arraycopy(cur, 0, ret, 0, i); 503 } 504 if (i < (N - 1)) { 505 System.arraycopy(cur, i + 1, ret, i, N - i - 1); 506 } 507 return ret; 508 } 509 } 510 return cur; 511 } 512 513 /** 514 * Adds value to given array if not already present, providing set-like 515 * behavior. 516 */ appendLong(@ullable long[] cur, long val, boolean allowDuplicates)517 public static @NonNull long[] appendLong(@Nullable long[] cur, long val, 518 boolean allowDuplicates) { 519 if (cur == null) { 520 return new long[] { val }; 521 } 522 final int N = cur.length; 523 if (!allowDuplicates) { 524 for (int i = 0; i < N; i++) { 525 if (cur[i] == val) { 526 return cur; 527 } 528 } 529 } 530 long[] ret = new long[N + 1]; 531 System.arraycopy(cur, 0, ret, 0, N); 532 ret[N] = val; 533 return ret; 534 } 535 536 /** 537 * Adds value to given array if not already present, providing set-like 538 * behavior. 539 */ appendLong(@ullable long[] cur, long val)540 public static @NonNull long[] appendLong(@Nullable long[] cur, long val) { 541 return appendLong(cur, val, false); 542 } 543 544 /** 545 * Removes value from given array if present, providing set-like behavior. 546 */ removeLong(@ullable long[] cur, long val)547 public static @Nullable long[] removeLong(@Nullable long[] cur, long val) { 548 if (cur == null) { 549 return null; 550 } 551 final int N = cur.length; 552 for (int i = 0; i < N; i++) { 553 if (cur[i] == val) { 554 long[] ret = new long[N - 1]; 555 if (i > 0) { 556 System.arraycopy(cur, 0, ret, 0, i); 557 } 558 if (i < (N - 1)) { 559 System.arraycopy(cur, i + 1, ret, i, N - i - 1); 560 } 561 return ret; 562 } 563 } 564 return cur; 565 } 566 cloneOrNull(@ullable long[] array)567 public static @Nullable long[] cloneOrNull(@Nullable long[] array) { 568 return (array != null) ? array.clone() : null; 569 } 570 571 /** 572 * Clones an array or returns null if the array is null. 573 */ cloneOrNull(@ullable T[] array)574 public static @Nullable <T> T[] cloneOrNull(@Nullable T[] array) { 575 return (array != null) ? array.clone() : null; 576 } 577 cloneOrNull(@ullable ArraySet<T> array)578 public static @Nullable <T> ArraySet<T> cloneOrNull(@Nullable ArraySet<T> array) { 579 return (array != null) ? new ArraySet<T>(array) : null; 580 } 581 add(@ullable ArraySet<T> cur, T val)582 public static @NonNull <T> ArraySet<T> add(@Nullable ArraySet<T> cur, T val) { 583 if (cur == null) { 584 cur = new ArraySet<>(); 585 } 586 cur.add(val); 587 return cur; 588 } 589 remove(@ullable ArraySet<T> cur, T val)590 public static @Nullable <T> ArraySet<T> remove(@Nullable ArraySet<T> cur, T val) { 591 if (cur == null) { 592 return null; 593 } 594 cur.remove(val); 595 if (cur.isEmpty()) { 596 return null; 597 } else { 598 return cur; 599 } 600 } 601 add(@ullable ArrayList<T> cur, T val)602 public static @NonNull <T> ArrayList<T> add(@Nullable ArrayList<T> cur, T val) { 603 if (cur == null) { 604 cur = new ArrayList<>(); 605 } 606 cur.add(val); 607 return cur; 608 } 609 add(@ullable ArrayList<T> cur, int index, T val)610 public static @NonNull <T> ArrayList<T> add(@Nullable ArrayList<T> cur, int index, T val) { 611 if (cur == null) { 612 cur = new ArrayList<>(); 613 } 614 cur.add(index, val); 615 return cur; 616 } 617 remove(@ullable ArrayList<T> cur, T val)618 public static @Nullable <T> ArrayList<T> remove(@Nullable ArrayList<T> cur, T val) { 619 if (cur == null) { 620 return null; 621 } 622 cur.remove(val); 623 if (cur.isEmpty()) { 624 return null; 625 } else { 626 return cur; 627 } 628 } 629 contains(@ullable Collection<T> cur, T val)630 public static <T> boolean contains(@Nullable Collection<T> cur, T val) { 631 return (cur != null) ? cur.contains(val) : false; 632 } 633 trimToSize(@ullable T[] array, int size)634 public static @Nullable <T> T[] trimToSize(@Nullable T[] array, int size) { 635 if (array == null || size == 0) { 636 return null; 637 } else if (array.length == size) { 638 return array; 639 } else { 640 return Arrays.copyOf(array, size); 641 } 642 } 643 644 /** 645 * Returns true if the two ArrayLists are equal with respect to the objects they contain. 646 * The objects must be in the same order and be reference equal (== not .equals()). 647 */ referenceEquals(ArrayList<T> a, ArrayList<T> b)648 public static <T> boolean referenceEquals(ArrayList<T> a, ArrayList<T> b) { 649 if (a == b) { 650 return true; 651 } 652 653 final int sizeA = a.size(); 654 final int sizeB = b.size(); 655 if (a == null || b == null || sizeA != sizeB) { 656 return false; 657 } 658 659 boolean diff = false; 660 for (int i = 0; i < sizeA && !diff; i++) { 661 diff |= a.get(i) != b.get(i); 662 } 663 return !diff; 664 } 665 666 /** 667 * Removes elements that match the predicate in an efficient way that alters the order of 668 * elements in the collection. This should only be used if order is not important. 669 * @param collection The ArrayList from which to remove elements. 670 * @param predicate The predicate that each element is tested against. 671 * @return the number of elements removed. 672 */ unstableRemoveIf(@ullable ArrayList<T> collection, @NonNull java.util.function.Predicate<T> predicate)673 public static <T> int unstableRemoveIf(@Nullable ArrayList<T> collection, 674 @NonNull java.util.function.Predicate<T> predicate) { 675 if (collection == null) { 676 return 0; 677 } 678 679 final int size = collection.size(); 680 int leftIdx = 0; 681 int rightIdx = size - 1; 682 while (leftIdx <= rightIdx) { 683 // Find the next element to remove moving left to right. 684 while (leftIdx < size && !predicate.test(collection.get(leftIdx))) { 685 leftIdx++; 686 } 687 688 // Find the next element to keep moving right to left. 689 while (rightIdx > leftIdx && predicate.test(collection.get(rightIdx))) { 690 rightIdx--; 691 } 692 693 if (leftIdx >= rightIdx) { 694 // Done. 695 break; 696 } 697 698 Collections.swap(collection, leftIdx, rightIdx); 699 leftIdx++; 700 rightIdx--; 701 } 702 703 // leftIdx is now at the end. 704 for (int i = size - 1; i >= leftIdx; i--) { 705 collection.remove(i); 706 } 707 return size - leftIdx; 708 } 709 defeatNullable(@ullable int[] val)710 public static @NonNull int[] defeatNullable(@Nullable int[] val) { 711 return (val != null) ? val : EmptyArray.INT; 712 } 713 defeatNullable(@ullable String[] val)714 public static @NonNull String[] defeatNullable(@Nullable String[] val) { 715 return (val != null) ? val : EmptyArray.STRING; 716 } 717 defeatNullable(@ullable File[] val)718 public static @NonNull File[] defeatNullable(@Nullable File[] val) { 719 return (val != null) ? val : EMPTY_FILE; 720 } 721 722 /** 723 * Throws {@link ArrayIndexOutOfBoundsException} if the index is out of bounds. 724 * 725 * @param len length of the array. Must be non-negative 726 * @param index the index to check 727 * @throws ArrayIndexOutOfBoundsException if the {@code index} is out of bounds of the array 728 */ checkBounds(int len, int index)729 public static void checkBounds(int len, int index) { 730 if (index < 0 || len <= index) { 731 throw new ArrayIndexOutOfBoundsException("length=" + len + "; index=" + index); 732 } 733 } 734 735 /** 736 * Returns an array with values from {@code val} minus {@code null} values 737 * 738 * @param arrayConstructor typically {@code T[]::new} e.g. {@code String[]::new} 739 */ filterNotNull(T[] val, IntFunction<T[]> arrayConstructor)740 public static <T> T[] filterNotNull(T[] val, IntFunction<T[]> arrayConstructor) { 741 int nullCount = 0; 742 int size = size(val); 743 for (int i = 0; i < size; i++) { 744 if (val[i] == null) { 745 nullCount++; 746 } 747 } 748 if (nullCount == 0) { 749 return val; 750 } 751 T[] result = arrayConstructor.apply(size - nullCount); 752 int outIdx = 0; 753 for (int i = 0; i < size; i++) { 754 if (val[i] != null) { 755 result[outIdx++] = val[i]; 756 } 757 } 758 return result; 759 } 760 761 /** 762 * Returns an array containing elements from the given one that match the given predicate. 763 */ filter(@ullable T[] items, @NonNull IntFunction<T[]> arrayConstructor, @NonNull java.util.function.Predicate<T> predicate)764 public static @Nullable <T> T[] filter(@Nullable T[] items, 765 @NonNull IntFunction<T[]> arrayConstructor, 766 @NonNull java.util.function.Predicate<T> predicate) { 767 if (isEmpty(items)) { 768 return items; 769 } 770 771 int matchesCount = 0; 772 int size = size(items); 773 for (int i = 0; i < size; i++) { 774 if (predicate.test(items[i])) { 775 matchesCount++; 776 } 777 } 778 if (matchesCount == 0) { 779 return items; 780 } 781 if (matchesCount == items.length) { 782 return items; 783 } 784 if (matchesCount == 0) { 785 return null; 786 } 787 T[] result = arrayConstructor.apply(matchesCount); 788 int outIdx = 0; 789 for (int i = 0; i < size; i++) { 790 if (predicate.test(items[i])) { 791 result[outIdx++] = items[i]; 792 } 793 } 794 return result; 795 } 796 startsWith(byte[] cur, byte[] val)797 public static boolean startsWith(byte[] cur, byte[] val) { 798 if (cur == null || val == null) return false; 799 if (cur.length < val.length) return false; 800 for (int i = 0; i < val.length; i++) { 801 if (cur[i] != val[i]) return false; 802 } 803 return true; 804 } 805 806 /** 807 * Returns the first element from the array for which 808 * condition {@code predicate} is true, or null if there is no such element 809 */ find(@ullable T[] items, @NonNull java.util.function.Predicate<T> predicate)810 public static @Nullable <T> T find(@Nullable T[] items, 811 @NonNull java.util.function.Predicate<T> predicate) { 812 if (isEmpty(items)) return null; 813 for (final T item : items) { 814 if (predicate.test(item)) return item; 815 } 816 return null; 817 } 818 deepToString(Object value)819 public static String deepToString(Object value) { 820 if (value != null && value.getClass().isArray()) { 821 if (value.getClass() == boolean[].class) { 822 return Arrays.toString((boolean[]) value); 823 } else if (value.getClass() == byte[].class) { 824 return Arrays.toString((byte[]) value); 825 } else if (value.getClass() == char[].class) { 826 return Arrays.toString((char[]) value); 827 } else if (value.getClass() == double[].class) { 828 return Arrays.toString((double[]) value); 829 } else if (value.getClass() == float[].class) { 830 return Arrays.toString((float[]) value); 831 } else if (value.getClass() == int[].class) { 832 return Arrays.toString((int[]) value); 833 } else if (value.getClass() == long[].class) { 834 return Arrays.toString((long[]) value); 835 } else if (value.getClass() == short[].class) { 836 return Arrays.toString((short[]) value); 837 } else { 838 return Arrays.deepToString((Object[]) value); 839 } 840 } else { 841 return String.valueOf(value); 842 } 843 } 844 firstOrNull(T[] items)845 public static @Nullable <T> T firstOrNull(T[] items) { 846 return items.length > 0 ? items[0] : null; 847 } 848 } 849