/*
* The MIT License
*
* Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package hudson.util;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.ListIterator;
import java.util.AbstractList;
import java.util.Arrays;
import java.util.Set;
import java.util.HashSet;
/**
* Varios {@link Iterator} implementations.
*
* @author Kohsuke Kawaguchi
* @see AdaptedIterator
*/
public class Iterators {
/**
* Returns the empty iterator.
*/
public static <T> Iterator<T> empty() {
return Collections.<T>emptyList().iterator();
}
/**
* Produces {A,B,C,D,E,F} from {{A,B},{C},{},{D,E,F}}.
*/
public static abstract class FlattenIterator<U,T> implements Iterator<U> {
private final Iterator<? extends T> core;
private Iterator<U> cur;
protected FlattenIterator(Iterator<? extends T> core) {
this.core = core;
cur = Collections.<U>emptyList().iterator();
}
protected FlattenIterator(Iterable<? extends T> core) {
this(core.iterator());
}
protected abstract Iterator<U> expand(T t);
public boolean hasNext() {
while(!cur.hasNext()) {
if(!core.hasNext())
return false;
cur = expand(core.next());
}
return true;
}
public U next() {
if(!hasNext()) throw new NoSuchElementException();
return cur.next();
}
public void remove() {
throw new UnsupportedOperationException();
}
}
/**
* Creates a filtered view of another iterator.
*
* @since 1.150
*/
public static abstract class FilterIterator<T> implements Iterator<T> {
private final Iterator<? extends T> core;
private T next;
private boolean fetched;
protected FilterIterator(Iterator<? extends T> core) {
this.core = core;
}
protected FilterIterator(Iterable<? extends T> core) {
this(core.iterator());
}
private void fetch() {
while(!fetched && core.hasNext()) {
T n = core.next();
if(filter(n)) {
next = n;
fetched = true;
}
}
}
/**
* Filter out items in the original collection.
*
* @return
* true to leave this item and return this item from this iterator.
* false to hide this item.
*/
protected abstract boolean filter(T t);
public boolean hasNext() {
fetch();
return fetched;
}
public T next() {
fetch();
if(!fetched) throw new NoSuchElementException();
fetched = false;
return next;
}
public void remove() {
core.remove();
}
}
/**
* Remove duplicates from another iterator.
*/
public static final class DuplicateFilterIterator<T> extends FilterIterator<T> {
private final Set<T> seen = new HashSet<T>();
public DuplicateFilterIterator(Iterator<? extends T> core) {
super(core);
}
public DuplicateFilterIterator(Iterable<? extends T> core) {
super(core);
}
protected boolean filter(T t) {
return seen.add(t);
}
}
/**
* Returns the {@link Iterable} that lists items in the reverse order.
*
* @since 1.150
*/
public static <T> Iterable<T> reverse(final List<T> lst) {
return new Iterable<T>() {
public Iterator<T> iterator() {
final ListIterator<T> itr = lst.listIterator(lst.size());
return new Iterator<T>() {
public boolean hasNext() {
return itr.hasPrevious();
}
public T next() {
return itr.previous();
}
public void remove() {
itr.remove();
}
};
}
};
}
/**
* Returns a list that represents [start,end).
*
* For example sequence(1,5,1)={1,2,3,4}, and sequence(7,1,-2)={7.5,3}
*
* @since 1.150
*/
public static List<Integer> sequence(final int start, int end, final int step) {
final int size = (end-start)/step;
if(size<0) throw new IllegalArgumentException("List size is negative");
return new AbstractList<Integer>() {
public Integer get(int index) {
if(index<0 || index>=size)
throw new IndexOutOfBoundsException();
return start+index*step;
}
public int size() {
return size;
}
};
}
public static List<Integer> sequence(int start, int end) {
return sequence(start,end,1);
}
/**
* The short cut for {@code reverse(sequence(start,end,step))}.
*
* @since 1.150
*/
public static List<Integer> reverseSequence(int start, int end, int step) {
return sequence(end-1,start-1,-step);
}
public static List<Integer> reverseSequence(int start, int end) {
return reverseSequence(start,end,1);
}
/**
* Casts {@link Iterator} by taking advantage of its covariant-ness.
*/
@SuppressWarnings({"unchecked"})
public static <T> Iterator<T> cast(Iterator<? extends T> itr) {
return (Iterator)itr;
}
/**
* Casts {@link Iterable} by taking advantage of its covariant-ness.
*/
@SuppressWarnings({"unchecked"})
public static <T> Iterable<T> cast(Iterable<? extends T> itr) {
return (Iterable)itr;
}
/**
* Returns an {@link Iterator} that only returns items of the given subtype.
*/
@SuppressWarnings({"unchecked"})
public static <U,T extends U> Iterator<T> subType(Iterator<U> itr, final Class<T> type) {
return (Iterator)new FilterIterator<U>(itr) {
protected boolean filter(U u) {
return type.isInstance(u);
}
};
}
/**
* Creates a read-only mutator that disallows {@link Iterator#remove()}.
*/
public static <T> Iterator<T> readOnly(final Iterator<T> itr) {
return new Iterator<T>() {
public boolean hasNext() {
return itr.hasNext();
}
public T next() {
return itr.next();
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
/**
* Wraps another iterator and throws away nulls.
*/
public static <T> Iterator<T> removeNull(final Iterator<T> itr) {
return new FilterIterator<T>(itr) {
@Override
protected boolean filter(T t) {
return t!=null;
}
};
}
/**
* Returns an {@link Iterable} that iterates over all the given {@link Iterable}s.
*
* <p>
* That is, this creates {A,B,C,D} from {A,B},{C,D}.
*/
public static <T> Iterable<T> sequence( final Iterable<? extends T>... iterables ) {
return new Iterable<T>() {
public Iterator<T> iterator() {
return new FlattenIterator<T,Iterable<? extends T>>(Arrays.asList(iterables)) {
protected Iterator<T> expand(Iterable<? extends T> iterable) {
return cast(iterable).iterator();
}
};
}
};
}
}