/* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.telephony.util; import android.annotation.NonNull; import android.annotation.Nullable; import java.lang.reflect.Array; import java.util.Collection; import java.util.Map; import java.util.Objects; /** Utility methods for array operations. */ public final class ArrayUtils { private ArrayUtils() { /* cannot be instantiated */ } /** * Adds value to given array if not already present, providing set-like behavior. * * @param kind The class of the array elements. * @param array The array to append to. * @param element The array element to append. * @return The array containing the appended element. */ @SuppressWarnings("unchecked") @NonNull public static T[] appendElement(Class kind, @Nullable T[] array, T element) { return appendElement(kind, array, element, false); } /** * Adds value to given array. * * @param kind The class of the array elements. * @param array The array to append to. * @param element The array element to append. * @param allowDuplicates Whether to allow duplicated elements in array. * @return The array containing the appended element. */ @SuppressWarnings("unchecked") @NonNull public static T[] appendElement(Class kind, @Nullable T[] array, T element, boolean allowDuplicates) { final T[] result; final int end; if (array != null) { if (!allowDuplicates && contains(array, element)) return array; end = array.length; result = (T[]) Array.newInstance(kind, end + 1); System.arraycopy(array, 0, result, 0, end); } else { end = 0; result = (T[]) Array.newInstance(kind, 1); } result[end] = element; return result; } /** * Combine multiple arrays into a single array. * * @param kind The class of the array elements * @param arrays The arrays to combine * @param The class of the array elements (inferred from kind). * @return A single array containing all the elements of the parameter arrays. */ @SuppressWarnings("unchecked") @NonNull public static T[] concatElements(Class kind, @Nullable T[]... arrays) { if (arrays == null || arrays.length == 0) { return createEmptyArray(kind); } int totalLength = 0; for (T[] item : arrays) { if (item == null) { continue; } totalLength += item.length; } // Optimization for entirely empty arrays. if (totalLength == 0) { return createEmptyArray(kind); } final T[] all = (T[]) Array.newInstance(kind, totalLength); int pos = 0; for (T[] item : arrays) { if (item == null || item.length == 0) { continue; } System.arraycopy(item, 0, all, pos, item.length); pos += item.length; } return all; } private static @NonNull T[] createEmptyArray(Class kind) { if (kind == String.class) { return (T[]) EmptyArray.STRING; } else if (kind == Object.class) { return (T[]) EmptyArray.OBJECT; } return (T[]) Array.newInstance(kind, 0); } private static final class EmptyArray { private EmptyArray() {} public static final Object[] OBJECT = new Object[0]; public static final String[] STRING = new String[0]; } /** * Checks if {@code value} is in {@code array}. */ public static boolean contains(@Nullable char[] array, char value) { if (array == null) return false; for (char element : array) { if (element == value) { return true; } } return false; } /** * Checks if {@code value} is in {@code array}. */ public static boolean contains(@Nullable Collection cur, T val) { return (cur != null) ? cur.contains(val) : false; } /** * Checks if {@code value} is in {@code array}. */ public static boolean contains(@Nullable int[] array, int value) { if (array == null) return false; for (int element : array) { if (element == value) { return true; } } return false; } /** * Checks if {@code value} is in {@code array}. */ public static boolean contains(@Nullable long[] array, long value) { if (array == null) return false; for (long element : array) { if (element == value) { return true; } } return false; } /** * Checks if {@code value} is in {@code array}. */ public static boolean contains(@Nullable T[] array, T value) { return indexOf(array, value) != -1; } /** * Return first index of {@code value} in {@code array}, or {@code -1} if * not found. */ public static int indexOf(@Nullable T[] array, T value) { if (array == null) return -1; for (int i = 0; i < array.length; i++) { if (Objects.equals(array[i], value)) return i; } return -1; } /** * Checks if given array is null or has zero elements. */ public static boolean isEmpty(@Nullable Collection array) { return array == null || array.isEmpty(); } /** * Checks if given map is null or has zero elements. */ public static boolean isEmpty(@Nullable Map map) { return map == null || map.isEmpty(); } /** * Checks if given array is null or has zero elements. */ public static boolean isEmpty(@Nullable T[] array) { return array == null || array.length == 0; } /** * Checks if given array is null or has zero elements. */ public static boolean isEmpty(@Nullable int[] array) { return array == null || array.length == 0; } /** * Checks if given array is null or has zero elements. */ public static boolean isEmpty(@Nullable long[] array) { return array == null || array.length == 0; } /** * Checks if given array is null or has zero elements. */ public static boolean isEmpty(@Nullable byte[] array) { return array == null || array.length == 0; } /** * Checks if given array is null or has zero elements. */ public static boolean isEmpty(@Nullable boolean[] array) { return array == null || array.length == 0; } }