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