ArrayUtils.java revision 2bd31dbd023a11d90061c7b6831dd06454c928af
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 17package com.android.internal.util; 18 19import android.annotation.NonNull; 20import android.annotation.Nullable; 21import android.util.ArraySet; 22 23import dalvik.system.VMRuntime; 24 25import libcore.util.EmptyArray; 26 27import java.lang.reflect.Array; 28import java.util.ArrayList; 29import java.util.Arrays; 30import java.util.Objects; 31 32/** 33 * ArrayUtils contains some methods that you can call to find out 34 * the most efficient increments by which to grow arrays. 35 */ 36public class ArrayUtils { 37 private static final int CACHE_SIZE = 73; 38 private static Object[] sCache = new Object[CACHE_SIZE]; 39 40 private ArrayUtils() { /* cannot be instantiated */ } 41 42 public static byte[] newUnpaddedByteArray(int minLen) { 43 return (byte[])VMRuntime.getRuntime().newUnpaddedArray(byte.class, minLen); 44 } 45 46 public static char[] newUnpaddedCharArray(int minLen) { 47 return (char[])VMRuntime.getRuntime().newUnpaddedArray(char.class, minLen); 48 } 49 50 public static int[] newUnpaddedIntArray(int minLen) { 51 return (int[])VMRuntime.getRuntime().newUnpaddedArray(int.class, minLen); 52 } 53 54 public static boolean[] newUnpaddedBooleanArray(int minLen) { 55 return (boolean[])VMRuntime.getRuntime().newUnpaddedArray(boolean.class, minLen); 56 } 57 58 public static long[] newUnpaddedLongArray(int minLen) { 59 return (long[])VMRuntime.getRuntime().newUnpaddedArray(long.class, minLen); 60 } 61 62 public static float[] newUnpaddedFloatArray(int minLen) { 63 return (float[])VMRuntime.getRuntime().newUnpaddedArray(float.class, minLen); 64 } 65 66 public static Object[] newUnpaddedObjectArray(int minLen) { 67 return (Object[])VMRuntime.getRuntime().newUnpaddedArray(Object.class, minLen); 68 } 69 70 @SuppressWarnings("unchecked") 71 public static <T> T[] newUnpaddedArray(Class<T> clazz, int minLen) { 72 return (T[])VMRuntime.getRuntime().newUnpaddedArray(clazz, minLen); 73 } 74 75 /** 76 * Checks if the beginnings of two byte arrays are equal. 77 * 78 * @param array1 the first byte array 79 * @param array2 the second byte array 80 * @param length the number of bytes to check 81 * @return true if they're equal, false otherwise 82 */ 83 public static boolean equals(byte[] array1, byte[] array2, int length) { 84 if (length < 0) { 85 throw new IllegalArgumentException(); 86 } 87 88 if (array1 == array2) { 89 return true; 90 } 91 if (array1 == null || array2 == null || array1.length < length || array2.length < length) { 92 return false; 93 } 94 for (int i = 0; i < length; i++) { 95 if (array1[i] != array2[i]) { 96 return false; 97 } 98 } 99 return true; 100 } 101 102 /** 103 * Returns an empty array of the specified type. The intent is that 104 * it will return the same empty array every time to avoid reallocation, 105 * although this is not guaranteed. 106 */ 107 @SuppressWarnings("unchecked") 108 public static <T> T[] emptyArray(Class<T> kind) { 109 if (kind == Object.class) { 110 return (T[]) EmptyArray.OBJECT; 111 } 112 113 int bucket = (kind.hashCode() & 0x7FFFFFFF) % CACHE_SIZE; 114 Object cache = sCache[bucket]; 115 116 if (cache == null || cache.getClass().getComponentType() != kind) { 117 cache = Array.newInstance(kind, 0); 118 sCache[bucket] = cache; 119 120 // Log.e("cache", "new empty " + kind.getName() + " at " + bucket); 121 } 122 123 return (T[]) cache; 124 } 125 126 /** 127 * Checks if given array is null or has zero elements. 128 */ 129 public static <T> boolean isEmpty(@Nullable T[] array) { 130 return array == null || array.length == 0; 131 } 132 133 /** 134 * Checks if given array is null or has zero elements. 135 */ 136 public static boolean isEmpty(@Nullable int[] array) { 137 return array == null || array.length == 0; 138 } 139 140 /** 141 * Checks if given array is null or has zero elements. 142 */ 143 public static boolean isEmpty(@Nullable long[] array) { 144 return array == null || array.length == 0; 145 } 146 147 /** 148 * Checks if given array is null or has zero elements. 149 */ 150 public static boolean isEmpty(@Nullable byte[] array) { 151 return array == null || array.length == 0; 152 } 153 154 /** 155 * Checks that value is present as at least one of the elements of the array. 156 * @param array the array to check in 157 * @param value the value to check for 158 * @return true if the value is present in the array 159 */ 160 public static <T> boolean contains(@Nullable T[] array, T value) { 161 return indexOf(array, value) != -1; 162 } 163 164 /** 165 * Return first index of {@code value} in {@code array}, or {@code -1} if 166 * not found. 167 */ 168 public static <T> int indexOf(@Nullable T[] array, T value) { 169 if (array == null) return -1; 170 for (int i = 0; i < array.length; i++) { 171 if (Objects.equals(array[i], value)) return i; 172 } 173 return -1; 174 } 175 176 /** 177 * Test if all {@code check} items are contained in {@code array}. 178 */ 179 public static <T> boolean containsAll(@Nullable T[] array, T[] check) { 180 if (check == null) return true; 181 for (T checkItem : check) { 182 if (!contains(array, checkItem)) { 183 return false; 184 } 185 } 186 return true; 187 } 188 189 public static boolean contains(@Nullable int[] array, int value) { 190 if (array == null) return false; 191 for (int element : array) { 192 if (element == value) { 193 return true; 194 } 195 } 196 return false; 197 } 198 199 public static boolean contains(@Nullable long[] array, long value) { 200 if (array == null) return false; 201 for (long element : array) { 202 if (element == value) { 203 return true; 204 } 205 } 206 return false; 207 } 208 209 public static long total(@Nullable long[] array) { 210 long total = 0; 211 if (array != null) { 212 for (long value : array) { 213 total += value; 214 } 215 } 216 return total; 217 } 218 219 /** 220 * Adds value to given array if not already present, providing set-like 221 * behavior. 222 */ 223 @SuppressWarnings("unchecked") 224 public static @NonNull <T> T[] appendElement(Class<T> kind, @Nullable T[] array, T element) { 225 final T[] result; 226 final int end; 227 if (array != null) { 228 if (contains(array, element)) return array; 229 end = array.length; 230 result = (T[])Array.newInstance(kind, end + 1); 231 System.arraycopy(array, 0, result, 0, end); 232 } else { 233 end = 0; 234 result = (T[])Array.newInstance(kind, 1); 235 } 236 result[end] = element; 237 return result; 238 } 239 240 /** 241 * Removes value from given array if present, providing set-like behavior. 242 */ 243 @SuppressWarnings("unchecked") 244 public static @Nullable <T> T[] removeElement(Class<T> kind, @Nullable T[] array, T element) { 245 if (array != null) { 246 if (!contains(array, element)) return array; 247 final int length = array.length; 248 for (int i = 0; i < length; i++) { 249 if (Objects.equals(array[i], element)) { 250 if (length == 1) { 251 return null; 252 } 253 T[] result = (T[])Array.newInstance(kind, length - 1); 254 System.arraycopy(array, 0, result, 0, i); 255 System.arraycopy(array, i + 1, result, i, length - i - 1); 256 return result; 257 } 258 } 259 } 260 return array; 261 } 262 263 /** 264 * Adds value to given array if not already present, providing set-like 265 * behavior. 266 */ 267 public static @NonNull int[] appendInt(@Nullable int[] cur, int val) { 268 if (cur == null) { 269 return new int[] { val }; 270 } 271 final int N = cur.length; 272 for (int i = 0; i < N; i++) { 273 if (cur[i] == val) { 274 return cur; 275 } 276 } 277 int[] ret = new int[N + 1]; 278 System.arraycopy(cur, 0, ret, 0, N); 279 ret[N] = val; 280 return ret; 281 } 282 283 /** 284 * Removes value from given array if present, providing set-like behavior. 285 */ 286 public static @Nullable int[] removeInt(@Nullable int[] cur, int val) { 287 if (cur == null) { 288 return null; 289 } 290 final int N = cur.length; 291 for (int i = 0; i < N; i++) { 292 if (cur[i] == val) { 293 int[] ret = new int[N - 1]; 294 if (i > 0) { 295 System.arraycopy(cur, 0, ret, 0, i); 296 } 297 if (i < (N - 1)) { 298 System.arraycopy(cur, i + 1, ret, i, N - i - 1); 299 } 300 return ret; 301 } 302 } 303 return cur; 304 } 305 306 /** 307 * Removes value from given array if present, providing set-like behavior. 308 */ 309 public static @Nullable String[] removeString(@Nullable String[] cur, String val) { 310 if (cur == null) { 311 return null; 312 } 313 final int N = cur.length; 314 for (int i = 0; i < N; i++) { 315 if (Objects.equals(cur[i], val)) { 316 String[] ret = new String[N - 1]; 317 if (i > 0) { 318 System.arraycopy(cur, 0, ret, 0, i); 319 } 320 if (i < (N - 1)) { 321 System.arraycopy(cur, i + 1, ret, i, N - i - 1); 322 } 323 return ret; 324 } 325 } 326 return cur; 327 } 328 329 /** 330 * Adds value to given array if not already present, providing set-like 331 * behavior. 332 */ 333 public static @NonNull long[] appendLong(@Nullable long[] cur, long val) { 334 if (cur == null) { 335 return new long[] { val }; 336 } 337 final int N = cur.length; 338 for (int i = 0; i < N; i++) { 339 if (cur[i] == val) { 340 return cur; 341 } 342 } 343 long[] ret = new long[N + 1]; 344 System.arraycopy(cur, 0, ret, 0, N); 345 ret[N] = val; 346 return ret; 347 } 348 349 /** 350 * Removes value from given array if present, providing set-like behavior. 351 */ 352 public static @Nullable long[] removeLong(@Nullable long[] cur, long val) { 353 if (cur == null) { 354 return null; 355 } 356 final int N = cur.length; 357 for (int i = 0; i < N; i++) { 358 if (cur[i] == val) { 359 long[] ret = new long[N - 1]; 360 if (i > 0) { 361 System.arraycopy(cur, 0, ret, 0, i); 362 } 363 if (i < (N - 1)) { 364 System.arraycopy(cur, i + 1, ret, i, N - i - 1); 365 } 366 return ret; 367 } 368 } 369 return cur; 370 } 371 372 public static @Nullable long[] cloneOrNull(@Nullable long[] array) { 373 return (array != null) ? array.clone() : null; 374 } 375 376 public static @Nullable <T> ArraySet<T> cloneOrNull(@Nullable ArraySet<T> array) { 377 return (array != null) ? new ArraySet<T>(array) : null; 378 } 379 380 public static @NonNull <T> ArraySet<T> add(@Nullable ArraySet<T> cur, T val) { 381 if (cur == null) { 382 cur = new ArraySet<>(); 383 } 384 cur.add(val); 385 return cur; 386 } 387 388 public static @Nullable <T> ArraySet<T> remove(@Nullable ArraySet<T> cur, T val) { 389 if (cur == null) { 390 return null; 391 } 392 cur.remove(val); 393 if (cur.isEmpty()) { 394 return null; 395 } else { 396 return cur; 397 } 398 } 399 400 public static <T> boolean contains(@Nullable ArraySet<T> cur, T val) { 401 return (cur != null) ? cur.contains(val) : false; 402 } 403 404 public static @NonNull <T> ArrayList<T> add(@Nullable ArrayList<T> cur, T val) { 405 if (cur == null) { 406 cur = new ArrayList<>(); 407 } 408 cur.add(val); 409 return cur; 410 } 411 412 public static @Nullable <T> ArrayList<T> remove(@Nullable ArrayList<T> cur, T val) { 413 if (cur == null) { 414 return null; 415 } 416 cur.remove(val); 417 if (cur.isEmpty()) { 418 return null; 419 } else { 420 return cur; 421 } 422 } 423 424 public static <T> boolean contains(@Nullable ArrayList<T> cur, T val) { 425 return (cur != null) ? cur.contains(val) : false; 426 } 427 428 public static @Nullable <T> T[] trimToSize(@Nullable T[] array, int size) { 429 if (array == null || size == 0) { 430 return null; 431 } else if (array.length == size) { 432 return array; 433 } else { 434 return Arrays.copyOf(array, size); 435 } 436 } 437 438 /** 439 * Returns true if the two ArrayLists are equal with respect to the objects they contain. 440 * The objects must be in the same order and be reference equal (== not .equals()). 441 */ 442 public static <T> boolean referenceEquals(ArrayList<T> a, ArrayList<T> b) { 443 if (a == b) { 444 return true; 445 } 446 447 final int sizeA = a.size(); 448 final int sizeB = b.size(); 449 if (a == null || b == null || sizeA != sizeB) { 450 return false; 451 } 452 453 boolean diff = false; 454 for (int i = 0; i < sizeA && !diff; i++) { 455 diff |= a.get(i) != b.get(i); 456 } 457 return !diff; 458 } 459} 460