1 /* 2 * Copyright (C) 2020 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 package com.android.internal.telephony.util; 17 18 import android.annotation.NonNull; 19 import android.annotation.Nullable; 20 21 import java.lang.reflect.Array; 22 import java.util.Collection; 23 import java.util.Map; 24 import java.util.Objects; 25 26 /** Utility methods for array operations. */ 27 public final class ArrayUtils { ArrayUtils()28 private ArrayUtils() { /* cannot be instantiated */ } 29 30 /** 31 * Adds value to given array if not already present, providing set-like behavior. 32 * 33 * @param kind The class of the array elements. 34 * @param array The array to append to. 35 * @param element The array element to append. 36 * @return The array containing the appended element. 37 */ 38 @SuppressWarnings("unchecked") 39 @NonNull appendElement(Class<T> kind, @Nullable T[] array, T element)40 public static <T> T[] appendElement(Class<T> kind, @Nullable T[] array, T element) { 41 return appendElement(kind, array, element, false); 42 } 43 44 /** 45 * Adds value to given array. 46 * 47 * @param kind The class of the array elements. 48 * @param array The array to append to. 49 * @param element The array element to append. 50 * @param allowDuplicates Whether to allow duplicated elements in array. 51 * @return The array containing the appended element. 52 */ 53 @SuppressWarnings("unchecked") 54 @NonNull appendElement(Class<T> kind, @Nullable T[] array, T element, boolean allowDuplicates)55 public static <T> T[] appendElement(Class<T> kind, @Nullable T[] array, T element, 56 boolean allowDuplicates) { 57 final T[] result; 58 final int end; 59 if (array != null) { 60 if (!allowDuplicates && contains(array, element)) return array; 61 end = array.length; 62 result = (T[]) Array.newInstance(kind, end + 1); 63 System.arraycopy(array, 0, result, 0, end); 64 } else { 65 end = 0; 66 result = (T[]) Array.newInstance(kind, 1); 67 } 68 result[end] = element; 69 return result; 70 } 71 72 /** 73 * Combine multiple arrays into a single array. 74 * 75 * @param kind The class of the array elements 76 * @param arrays The arrays to combine 77 * @param <T> The class of the array elements (inferred from kind). 78 * @return A single array containing all the elements of the parameter arrays. 79 */ 80 @SuppressWarnings("unchecked") 81 @NonNull concatElements(Class<T> kind, @Nullable T[]... arrays)82 public static <T> T[] concatElements(Class<T> kind, @Nullable T[]... arrays) { 83 if (arrays == null || arrays.length == 0) { 84 return createEmptyArray(kind); 85 } 86 87 int totalLength = 0; 88 for (T[] item : arrays) { 89 if (item == null) { 90 continue; 91 } 92 93 totalLength += item.length; 94 } 95 96 // Optimization for entirely empty arrays. 97 if (totalLength == 0) { 98 return createEmptyArray(kind); 99 } 100 101 final T[] all = (T[]) Array.newInstance(kind, totalLength); 102 int pos = 0; 103 for (T[] item : arrays) { 104 if (item == null || item.length == 0) { 105 continue; 106 } 107 System.arraycopy(item, 0, all, pos, item.length); 108 pos += item.length; 109 } 110 return all; 111 } 112 createEmptyArray(Class<T> kind)113 private static @NonNull <T> T[] createEmptyArray(Class<T> kind) { 114 if (kind == String.class) { 115 return (T[]) EmptyArray.STRING; 116 } else if (kind == Object.class) { 117 return (T[]) EmptyArray.OBJECT; 118 } 119 120 return (T[]) Array.newInstance(kind, 0); 121 } 122 123 private static final class EmptyArray { EmptyArray()124 private EmptyArray() {} 125 126 public static final Object[] OBJECT = new Object[0]; 127 public static final String[] STRING = new String[0]; 128 } 129 130 /** 131 * Checks if {@code value} is in {@code array}. 132 */ contains(@ullable char[] array, char value)133 public static boolean contains(@Nullable char[] array, char value) { 134 if (array == null) return false; 135 for (char element : array) { 136 if (element == value) { 137 return true; 138 } 139 } 140 return false; 141 } 142 143 /** 144 * Checks if {@code value} is in {@code array}. 145 */ contains(@ullable Collection<T> cur, T val)146 public static <T> boolean contains(@Nullable Collection<T> cur, T val) { 147 return (cur != null) ? cur.contains(val) : false; 148 } 149 150 /** 151 * Checks if {@code value} is in {@code array}. 152 */ contains(@ullable int[] array, int value)153 public static boolean contains(@Nullable int[] array, int value) { 154 if (array == null) return false; 155 for (int element : array) { 156 if (element == value) { 157 return true; 158 } 159 } 160 return false; 161 } 162 163 /** 164 * Checks if {@code value} is in {@code array}. 165 */ contains(@ullable long[] array, long value)166 public static boolean contains(@Nullable long[] array, long value) { 167 if (array == null) return false; 168 for (long element : array) { 169 if (element == value) { 170 return true; 171 } 172 } 173 return false; 174 } 175 176 /** 177 * Checks if {@code value} is in {@code array}. 178 */ contains(@ullable T[] array, T value)179 public static <T> boolean contains(@Nullable T[] array, T value) { 180 return indexOf(array, value) != -1; 181 } 182 183 /** 184 * Return first index of {@code value} in {@code array}, or {@code -1} if 185 * not found. 186 */ indexOf(@ullable T[] array, T value)187 public static <T> int indexOf(@Nullable T[] array, T value) { 188 if (array == null) return -1; 189 for (int i = 0; i < array.length; i++) { 190 if (Objects.equals(array[i], value)) return i; 191 } 192 return -1; 193 } 194 195 /** 196 * Checks if given array is null or has zero elements. 197 */ isEmpty(@ullable Collection<?> array)198 public static boolean isEmpty(@Nullable Collection<?> array) { 199 return array == null || array.isEmpty(); 200 } 201 202 /** 203 * Checks if given map is null or has zero elements. 204 */ isEmpty(@ullable Map<?, ?> map)205 public static boolean isEmpty(@Nullable Map<?, ?> map) { 206 return map == null || map.isEmpty(); 207 } 208 209 /** 210 * Checks if given array is null or has zero elements. 211 */ isEmpty(@ullable T[] array)212 public static <T> boolean isEmpty(@Nullable T[] array) { 213 return array == null || array.length == 0; 214 } 215 216 /** 217 * Checks if given array is null or has zero elements. 218 */ isEmpty(@ullable int[] array)219 public static boolean isEmpty(@Nullable int[] array) { 220 return array == null || array.length == 0; 221 } 222 223 /** 224 * Checks if given array is null or has zero elements. 225 */ isEmpty(@ullable long[] array)226 public static boolean isEmpty(@Nullable long[] array) { 227 return array == null || array.length == 0; 228 } 229 230 /** 231 * Checks if given array is null or has zero elements. 232 */ isEmpty(@ullable byte[] array)233 public static boolean isEmpty(@Nullable byte[] array) { 234 return array == null || array.length == 0; 235 } 236 237 /** 238 * Checks if given array is null or has zero elements. 239 */ isEmpty(@ullable boolean[] array)240 public static boolean isEmpty(@Nullable boolean[] array) { 241 return array == null || array.length == 0; 242 } 243 } 244