blob: b74b0e2a1e953f94ef80c390dccc4cf3bda849a9 [file] [log] [blame]
/*
* Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.util;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.Predicate;
import java.util.function.Supplier;
/**
* This class contains utility methods for commonly used functional patterns for collections.
*/
public final class CollectionsUtil {
private CollectionsUtil() {
}
/**
* Concatenates two iterables into a single iterable. The iterator exposed by the returned
* iterable does not support {@link Iterator#remove()} even if the input iterables do.
*
* @throws NullPointerException if {@code a} or {@code b} is {@code null}
*/
public static <T> Iterable<T> concat(Iterable<T> a, Iterable<T> b) {
List<Iterable<T>> l = Arrays.asList(a, b);
return concat(l);
}
/**
* Concatenates multiple iterables into a single iterable. The iterator exposed by the returned
* iterable does not support {@link Iterator#remove()} even if the input iterables do.
*
* @throws NullPointerException if {@code iterables} or any of its elements are {@code null}
*/
public static <T> Iterable<T> concat(List<Iterable<T>> iterables) {
for (Iterable<T> iterable : iterables) {
Objects.requireNonNull(iterable);
}
return new Iterable<T>() {
@Override
public Iterator<T> iterator() {
if (iterables.size() == 0) {
return Collections.emptyIterator();
}
return new Iterator<T>() {
Iterator<Iterable<T>> cursor = iterables.iterator();
Iterator<T> currentIterator = cursor.next().iterator();
private void advance() {
while (!currentIterator.hasNext() && cursor.hasNext()) {
currentIterator = cursor.next().iterator();
}
}
@Override
public boolean hasNext() {
advance();
return currentIterator.hasNext();
}
@Override
public T next() {
advance();
return currentIterator.next();
}
};
}
};
}
/**
* Returns whether all elements in {@code inputs} match {@code predicate}. May not evaluate
* {@code predicate} on all elements if not necessary for determining the result. If
* {@code inputs} is empty then {@code true} is returned and {@code predicate} is not evaluated.
*
* @return {@code true} if either all elements in {@code inputs} match {@code predicate} or
* {@code inputs} is empty, otherwise {@code false}.
*/
public static <T> boolean allMatch(T[] inputs, Predicate<T> predicate) {
return allMatch(Arrays.asList(inputs), predicate);
}
/**
* Returns whether all elements in {@code inputs} match {@code predicate}. May not evaluate
* {@code predicate} on all elements if not necessary for determining the result. If
* {@code inputs} is empty then {@code true} is returned and {@code predicate} is not evaluated.
*
* @return {@code true} if either all elements in {@code inputs} match {@code predicate} or
* {@code inputs} is empty, otherwise {@code false}.
*/
public static <T> boolean allMatch(Iterable<T> inputs, Predicate<T> predicate) {
for (T t : inputs) {
if (!predicate.test(t)) {
return false;
}
}
return true;
}
/**
* Returns whether any elements in {@code inputs} match {@code predicate}. May not evaluate
* {@code predicate} on all elements if not necessary for determining the result. If
* {@code inputs} is empty then {@code false} is returned and {@code predicate} is not
* evaluated.
*
* @return {@code true} if any elements in {@code inputs} match {@code predicate}, otherwise
* {@code false}.
*/
public static <T> boolean anyMatch(T[] inputs, Predicate<T> predicate) {
return anyMatch(Arrays.asList(inputs), predicate);
}
/**
* Returns whether any elements in {@code inputs} match {@code predicate}. May not evaluate
* {@code predicate} on all elements if not necessary for determining the result. If
* {@code inputs} is empty then {@code false} is returned and {@code predicate} is not
* evaluated.
*
* @return {@code true} if any elements in {@code inputs} match {@code predicate}, otherwise
* {@code false}.
*/
public static <T> boolean anyMatch(Iterable<T> inputs, Predicate<T> predicate) {
for (T t : inputs) {
if (predicate.test(t)) {
return true;
}
}
return false;
}
/**
* Returns a new list consisting of the elements in {@code inputs} that match {@code predicate}.
*
* @return the new list.
*/
public static <T> List<T> filterToList(List<T> inputs, Predicate<? super T> predicate) {
return filterToList(inputs, predicate, ArrayList::new);
}
/**
* Appends elements of {@code inputs} that match {@code predicate} to the list generated by
* {@code listGenerator}.
*
* @return the list generated by {@code listGenerator}.
*/
public static <T> List<T> filterToList(List<T> inputs, Predicate<? super T> predicate, Supplier<List<T>> listGenerator) {
List<T> resultList = listGenerator.get();
for (T t : inputs) {
if (predicate.test(t)) {
resultList.add(t);
}
}
return resultList;
}
/**
* Filters {@code inputs} with {@code predicate}, applies {@code mapper} and adds them in the
* array provided by {@code arrayGenerator}.
*
* @return the array provided by {@code arrayGenerator}.
*/
public static <T, R> R[] filterAndMapToArray(T[] inputs, Predicate<? super T> predicate, Function<? super T, ? extends R> mapper, IntFunction<R[]> arrayGenerator) {
List<R> resultList = new ArrayList<>();
for (T t : inputs) {
if (predicate.test(t)) {
resultList.add(mapper.apply(t));
}
}
return resultList.toArray(arrayGenerator.apply(resultList.size()));
}
/**
* Applies {@code mapper} on the elements in {@code inputs} and adds them in the array provided
* by {@code arrayGenerator}.
*
* @return the array provided by {@code arrayGenerator}.
*/
public static <T, R> R[] mapToArray(T[] inputs, Function<? super T, ? extends R> mapper, IntFunction<R[]> arrayGenerator) {
return mapToArray(Arrays.asList(inputs), mapper, arrayGenerator);
}
/**
* Applies {@code mapper} on the elements in {@code inputs} and adds them in the array provided
* by {@code arrayGenerator}.
*
* @return the array provided by {@code arrayGenerator}.
*/
public static <T, R> R[] mapToArray(Collection<T> inputs, Function<? super T, ? extends R> mapper, IntFunction<R[]> arrayGenerator) {
R[] result = arrayGenerator.apply(inputs.size());
int idx = 0;
for (T t : inputs) {
result[idx++] = mapper.apply(t);
}
return result;
}
/**
* Applies {@code mapper} on the elements in {@code inputs}, and joins them together separated
* by {@code delimiter}.
*
* @return a new String that is composed from {@code inputs}.
*/
public static <T, R> String mapAndJoin(T[] inputs, Function<? super T, ? extends R> mapper, String delimiter) {
return mapAndJoin(Arrays.asList(inputs), mapper, delimiter, "", "");
}
/**
* Applies {@code mapper} on the elements in {@code inputs}, and joins them together separated
* by {@code delimiter} and starting with {@code prefix}.
*
* @return a new String that is composed from {@code inputs}.
*/
public static <T, R> String mapAndJoin(T[] inputs, Function<? super T, ? extends R> mapper, String delimiter, String prefix) {
return mapAndJoin(Arrays.asList(inputs), mapper, delimiter, prefix, "");
}
/**
* Applies {@code mapper} on the elements in {@code inputs}, and joins them together separated
* by {@code delimiter} and starting with {@code prefix} and ending with {@code suffix}.
*
* @return a new String that is composed from {@code inputs}.
*/
public static <T, R> String mapAndJoin(T[] inputs, Function<? super T, ? extends R> mapper, String delimiter, String prefix, String suffix) {
return mapAndJoin(Arrays.asList(inputs), mapper, delimiter, prefix, suffix);
}
/**
* Applies {@code mapper} on the elements in {@code inputs}, and joins them together separated
* by {@code delimiter}.
*
* @return a new String that is composed from {@code inputs}.
*/
public static <T, R> String mapAndJoin(Iterable<T> inputs, Function<? super T, ? extends R> mapper, String delimiter) {
return mapAndJoin(inputs, mapper, delimiter, "", "");
}
/**
* Applies {@code mapper} on the elements in {@code inputs}, and joins them together separated
* by {@code delimiter} and starting with {@code prefix}.
*
* @return a new String that is composed from {@code inputs}.
*/
public static <T, R> String mapAndJoin(Iterable<T> inputs, Function<? super T, ? extends R> mapper, String delimiter, String prefix) {
return mapAndJoin(inputs, mapper, delimiter, prefix, "");
}
/**
* Applies {@code mapper} on the elements in {@code inputs}, and joins them together separated
* by {@code delimiter} and starting with {@code prefix} and ending with {@code suffix}.
*
* @return a new String that is composed from {@code inputs}.
*/
public static <T, R> String mapAndJoin(Iterable<T> inputs, Function<? super T, ? extends R> mapper, String delimiter, String prefix, String suffix) {
StringBuilder strb = new StringBuilder();
String sep = "";
for (T t : inputs) {
strb.append(sep).append(prefix).append(mapper.apply(t)).append(suffix);
sep = delimiter;
}
return strb.toString();
}
}