/******************************************************************************* * * Copyright (c) 2004-2009 Oracle Corporation. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * * Kohsuke Kawaguchi * * *******************************************************************************/ 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(); } }; } }; } }