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