blob: a7e968a3197ae7029339ac3d6acfeeb342883f0e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2014 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Mike Kucera (IBM Corporation) - initial API and implementation
* Sergey Prigogin (Google)
* Nathan Ridge
*******************************************************************************/
package org.eclipse.cdt.core.parser.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
/**
* Useful utility methods for dealing with Collections.
*
* @noinstantiate This class is not intended to be instantiated by clients.
*/
public final class CollectionUtils {
private CollectionUtils() {
// this class has just static utility methods
}
/**
* Returns an iterator that iterates backwards over the given list.
* The remove() method is not implemented and will throw UnsupportedOperationException.
* The returned iterator does not support the remove() method.
*
* @throws NullPointerException if list is {@code null}
*/
public static <T> Iterator<T> reverseIterator(final List<T> list) {
return new Iterator<>() {
ListIterator<T> iterator = list.listIterator(list.size());
@Override
public boolean hasNext() {
return iterator.hasPrevious();
}
@Override
public T next() {
return iterator.previous();
}
@Override
public void remove() {
throw new UnsupportedOperationException("remove() not supported"); //$NON-NLS-1$
}
};
}
/**
* Allows a foreach loop to iterate backwards over a list from the end to the start.
*
* <p>
* Example use:
* <pre>
* for (Object o : reverseIterable(list)) { ... }
* </pre>
*
* @throws NullPointerException if list is null
*/
public static <T> Iterable<T> reverseIterable(final List<T> list) {
return iterable(reverseIterator(list));
}
/**
* Creates an Iterable instance that just returns the given Iterator from its iterator() method.
*
* This is useful for using an iterator in a foreach loop directly.
*
* <p>
* Example use:
* <pre>
* for (Object o : iterable(iterator)) { ... }
* </pre>
*
* @throws NullPointerException if list is {@code null}
*/
public static <T> Iterable<T> iterable(final Iterator<T> iter) {
if (iter == null)
throw new NullPointerException("iter parameter is null"); //$NON-NLS-1$
return new Iterable<>() {
@Override
public Iterator<T> iterator() {
return iter;
}
};
}
/**
* Finds the first object in the heterogeneous list that is an instance of
* the given class, removes it from the list, and returns it.
* If there is not object in the list of the given type the list is left
* unmodified and null is returned.
*
* @throws NullPointerException if list or clazz is null
* @throws UnsupportedOperationException if the list's Iterator does not support the remove()
* method
*/
@SuppressWarnings("unchecked")
public static <T> T findFirstAndRemove(List<?> list, Class<T> clazz) {
for (Iterator<?> iter = list.iterator(); iter.hasNext();) {
Object o = iter.next();
if (clazz.isInstance(o)) {
iter.remove();
return (T) o; // safe
}
}
return null;
}
/**
* Combines two collections into one.
* @param c1 The first collection. May be modified as a result of the call. May be {@code null}.
* @param c2 The second collection. May be {@code null}.
* @return A collection containing elements from both input collections,
* or {@code null} if both, {@code c1} and {@code c2} are {@code null}.
* @since 5.4
*/
public static <T, U extends Collection<T>> U merge(U c1, U c2) {
if (c1 == null)
return c2;
if (c2 == null)
return c1;
if (c1.isEmpty())
return c2;
if (c2.isEmpty())
return c1;
c1.addAll(c2);
return c1;
}
/**
* Returns a List&lt;U&gt; corresponding to a T in a Map&lt;T, List&lt;U&gt;&gt;. If the mapping doesn't exist,
* creates it with an empty list as the initial value.
* @since 5.6
*/
public static <T, U> List<U> listMapGet(Map<T, List<U>> m, T t) {
List<U> result = m.get(t);
if (result == null) {
result = new ArrayList<>();
m.put(t, result);
}
return result;
}
/**
* Filter the elements of a collection down to just the ones that match the given predicate.
* @since 5.6
*/
public static <T> Collection<T> filter(Collection<T> collection, IUnaryPredicate<T> predicate) {
if (collection.isEmpty())
return collection;
Collection<T> result = null;
int n = 0;
for (T t : collection) {
if (predicate.apply(t)) {
if (result != null) {
result.add(t);
} else {
++n;
}
} else if (result == null) {
result = new ArrayList<>(collection.size() - 1);
for (T u : collection) {
if (--n < 0)
break;
result.add(u);
}
}
}
return result == null ? collection : result;
}
}