blob: 8dbaecfc95942f2d2ad0b808f3f7571abe31a5f3 [file] [log] [blame]
// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.utils;
import com.android.tools.r8.graph.DexType;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.IntPredicate;
import java.util.function.IntUnaryOperator;
import java.util.function.Predicate;
public class ArrayUtils {
public static <T> boolean any(T[] array, Predicate<T> predicate) {
for (T element : array) {
if (predicate.test(element)) {
return true;
}
}
return false;
}
public static <T> boolean none(T[] array, Predicate<T> predicate) {
return !any(array, predicate);
}
public static boolean containsInt(int[] array, int value) {
for (int element : array) {
if (element == value) {
return true;
}
}
return false;
}
/**
* Copies the input array and then applies specified sparse changes.
*
* @param clazz target type's Class to cast
* @param original an array of original elements
* @param changedElements sparse changes to apply
* @param <T> target type
* @return a copy of original arrays while sparse changes are applied
*/
public static <T> T[] copyWithSparseChanges(
Class<T[]> clazz, T[] original, Map<Integer, T> changedElements) {
T[] results = clazz.cast(Array.newInstance(clazz.getComponentType(), original.length));
int pos = 0;
for (Map.Entry<Integer, T> entry : changedElements.entrySet()) {
int i = entry.getKey();
System.arraycopy(original, pos, results, pos, i - pos);
results[i] = entry.getValue();
pos = i + 1;
}
if (pos < original.length) {
System.arraycopy(original, pos, results, pos, original.length - pos);
}
return results;
}
public static <T> T[] filled(T[] array, T element) {
Arrays.fill(array, element);
return array;
}
public static int[] initialize(int[] array, IntUnaryOperator fn) {
for (int i = 0; i < array.length; i++) {
array[i] = fn.applyAsInt(i);
}
return array;
}
public static <T> T[] initialize(T[] array, IntFunction<T> fn) {
for (int i = 0; i < array.length; i++) {
array[i] = fn.apply(i);
}
return array;
}
public static <T> boolean isEmpty(T[] array) {
return array.length == 0;
}
public static boolean isSorted(int[] array) {
for (int i = 0; i < array.length - 1; i++) {
assert array[i] < array[i + 1];
}
return true;
}
public static int last(int[] array) {
return array[array.length - 1];
}
public static <T> T last(T[] array) {
return array[array.length - 1];
}
/**
* Rewrites the input array based on the given function.
*
* @param original an array of original elements
* @param mapper a mapper that rewrites an original element to a new one, maybe `null`
* @param emptyArray an empty array
* @return an array with written elements
*/
@SuppressWarnings("unchecked")
public static <S, T> T[] map(S[] original, Function<S, T> mapper, T[] emptyArray) {
ArrayList<T> results = null;
for (int i = 0; i < original.length; i++) {
S oldOne = original[i];
T newOne = mapper.apply(oldOne);
if (newOne == oldOne) {
if (results != null) {
results.add((T) oldOne);
}
} else {
if (results == null) {
results = new ArrayList<>(original.length);
for (int j = 0; j < i; j++) {
results.add((T) original[j]);
}
}
if (newOne != null) {
results.add(newOne);
}
}
}
return results != null ? results.toArray(emptyArray) : (T[]) original;
}
/** Rewrites the input array to the output array unconditionally. */
public static <T> String[] mapToStringArray(T[] original, Function<T, String> mapper) {
String[] returnArr = new String[original.length];
for (int i = 0; i < original.length; i++) {
returnArr[i] = mapper.apply(original[i]);
}
return returnArr;
}
public static <T> T[] filter(T[] original, Predicate<T> predicate, T[] emptyArray) {
return map(original, e -> predicate.test(e) ? e : null, emptyArray);
}
@SuppressWarnings("unchecked")
public static <T> T[] filter(T[] original, Predicate<T> predicate, T[] emptyArray, int newSize) {
T[] result = (T[]) Array.newInstance(emptyArray.getClass().getComponentType(), newSize);
int newIndex = 0;
for (int originalIndex = 0; originalIndex < original.length; originalIndex++) {
T element = original[originalIndex];
if (predicate.test(element)) {
result[newIndex] = element;
newIndex++;
}
}
assert newIndex == newSize;
return result;
}
public static int[] createIdentityArray(int size) {
int[] array = new int[size];
for (int i = 0; i < size; i++) {
array[i] = i;
}
return array;
}
public static <T> boolean all(T[] elements, T elementToLookFor) {
for (Object element : elements) {
if (!Objects.equals(element, elementToLookFor)) {
return false;
}
}
return true;
}
public static <T> boolean contains(T[] elements, T elementToLookFor) {
for (Object element : elements) {
if (Objects.equals(element, elementToLookFor)) {
return true;
}
}
return false;
}
public static <T, U> boolean contains(
T[] elements, Function<T, U> elementMap, U mappedElementToLookFor) {
for (T element : elements) {
if (elementMap.apply(element).equals(mappedElementToLookFor)) {
return true;
}
}
return false;
}
public static int[] fromPredicate(IntPredicate predicate, int size) {
int[] result = new int[size];
for (int i = 0; i < size; i++) {
result[i] = BooleanUtils.intValue(predicate.test(i));
}
return result;
}
public static void sumOfPredecessorsInclusive(int[] array) {
for (int i = 1; i < array.length; i++) {
array[i] += array[i - 1];
}
}
/**
* Copies the current array to a new array that can fit one more element and adds 'element' to
* index |ts|. Only use this if adding a single element since copying the array is expensive.
*
* @param ts the original array
* @param element the element to add
* @return a new array with element on index |ts|
*/
public static <T> T[] appendSingleElement(T[] ts, T element) {
T[] newArray = Arrays.copyOf(ts, ts.length + 1);
newArray[ts.length] = element;
return newArray;
}
public static <T> T[] appendElements(T[] ts, List<T> elements) {
if (elements.isEmpty()) {
return ts;
}
if (elements.size() == 1) {
return appendSingleElement(ts, elements.get(0));
}
int oldLength = ts.length;
T[] newArray = Arrays.copyOf(ts, oldLength + elements.size());
for (int i = 0; i < elements.size(); i++) {
newArray[oldLength + i] = elements.get(i);
}
return newArray;
}
public static <T> T first(T[] ts) {
return ts[0];
}
@SuppressWarnings("unchecked")
public static <T> Optional<T>[] withOptionalNone(T[] ts) {
Optional<T>[] optionals = new Optional[ts.length + 1];
for (int i = 0; i < ts.length; i++) {
optionals[i] = Optional.of(ts[i]);
}
optionals[ts.length] = Optional.empty();
return optionals;
}
public static boolean any(DexType[] values, Predicate<DexType> predicate) {
for (DexType value : values) {
if (predicate.test(value)) {
return true;
}
}
return false;
}
}