Iterables.java
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2019 Arno Unkrig. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.commons.compiler.util.iterator;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import org.codehaus.commons.compiler.util.Predicate;
import org.codehaus.commons.nullanalysis.Nullable;
/**
* Utility method around {@link Iterable}s and {@link Iterator}s.
*/
public final
class Iterables {
private Iterables() {}
/**
* @return An {@link Iterable} that filters the <var>delegate</var>'s elements by base class
*/
public static <T> Iterable<T>
filterByClass(Object[] delegate, final Class<T> qualifyingClass) {
return Iterables.filterByClass(Arrays.asList(delegate), qualifyingClass);
}
/**
* @return An {@link Iterable} that filters the <var>delegate</var>'s elements by base class
*/
public static <T> Iterable<T>
filterByClass(final Iterable<?> delegate, final Class<T> qualifyingClass) {
return new Iterable<T>() {
@Override public Iterator<T>
iterator() { return Iterables.filterByClass(delegate.iterator(), qualifyingClass); }
};
}
/**
* @return An {@link Iterator} that filters the <var>delegate</var>'s products by base class
*/
public static <T> Iterator<T>
filterByClass(Iterator<?> delegate, final Class<T> qualifyingClass) {
@SuppressWarnings("unchecked") Iterator<T>
result = (Iterator<T>) Iterables.<Object>filter(
delegate,
new Predicate<Object>() {
@Override public boolean
evaluate(@Nullable Object o) { return o != null && qualifyingClass.isAssignableFrom(o.getClass()); }
}
);
return result;
}
/**
* @return An {@link Iterable} that discriminates the <var>delegate</var>'s elements with the <var>predicate</var>
*/
public static <T> Iterable<T>
filter(T[] delegate, final Predicate<? super T> predicate) {
return Iterables.filter(Arrays.asList(delegate), predicate);
}
/**
* @return An {@link Iterable} that discriminates the <var>delegate</var>'s elements with the <var>predicate</var>
*/
public static <T> Iterable<T>
filter(final Iterable<? extends T> delegate, final Predicate<? super T> predicate) {
return new Iterable<T>() {
@Override public Iterator<T>
iterator() { return Iterables.filter(delegate.iterator(), predicate); }
};
}
/**
* @return An {@link Iterator} that discriminates the <var>delegate</var>'s products with the <var>predicate</var>
*/
public static <T> Iterator<T>
filter(final Iterator<? extends T> delegate, final Predicate<? super T> predicate) {
return new Iterator<T>() {
State state = State.DEFAULT;
@Nullable T nextElement; // Valid iff state==READ_AHEAD;
@Override public boolean
hasNext() {
switch (this.state) {
case DEFAULT:
while (delegate.hasNext()) {
T ne = delegate.next();
if (predicate.evaluate(ne)) {
this.nextElement = ne;
this.state = State.READ_AHEAD;
return true;
}
}
this.state = State.AT_END;
return false;
case READ_AHEAD:
return true;
case AT_END:
return false;
default:
throw new AssertionError(this.state);
}
}
@Override @Nullable public T
next() {
if (!this.hasNext()) throw new NoSuchElementException();
this.state = State.DEFAULT;
T result = this.nextElement;
this.nextElement = null;
return result;
}
@Override public void
remove() { delegate.remove(); }
};
}
private
enum State {
/**
* No element has been read ahead.
*/
DEFAULT,
/**
* The next element has been read ahead.
*/
READ_AHEAD,
/**
* The delegate Iterator is at its end.
*/
AT_END,
}
/**
* @return All elements of the <var>delegate</var>
*/
public static <T> T[]
toArray(Iterable<T> delegate, Class<T> elementType) {
return Iterables.toArray(delegate.iterator(), elementType);
}
/**
* @return All products of the <var>delegate</var>
*/
public static <T> T[]
toArray(Iterator<T> delegate, Class<T> componentType) {
List<T> l = new ArrayList<>();
while (delegate.hasNext()) l.add(delegate.next());
@SuppressWarnings("unchecked") T[] array = (T[]) Array.newInstance(componentType, l.size());
return l.toArray(array);
}
}