/* * (c) Copyright 2003, 2004, 2005, 2006, 2007 Hewlett-Packard Development * Company, LP 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. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 net.enilink.commons.iterator; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import java.util.Set; /** * NiceIterator is the standard base class implementing ExtendedIterator. It * provides the static methods for <code>andThen</code>, <code>filterKeep</code> * and <code>filterDrop</code>; these can be reused from any other class. It * defines equivalent instance methods for descendants and to satisfy * ExtendedIterator. * */ public class NiceIterator<T> implements IExtendedIterator<T> { public NiceIterator() { super(); } /** * default close: don't need to do anything. */ public void close() { } /** * default hasNext: no elements, return false. */ public boolean hasNext() { return false; } protected void ensureHasNext() { if (hasNext() == false) throw new NoSuchElementException(); } /** * default next: throw an exception. */ public T next() { return noElements("empty NiceIterator"); } /** * Utility method for this and other (sub)classes: raise the appropriate "no * more elements" exception. I note that we raised the wrong exception in at * least one case ... * * @param message * the string to include in the exception * @return never - but we have a return type to please the compiler */ protected T noElements(String message) { throw new NoSuchElementException(message); } /** * default remove: we have no elements, so we can't remove any. */ public void remove() { throw new UnsupportedOperationException( "remove not supported for this iterator"); } /** * concatenate two iterators. */ public static <T> IExtendedIterator<T> andThen( final Iterator<? extends T> a, final Iterator<? extends T> b) { final List<Iterator<? extends T>> L = new ArrayList<Iterator<? extends T>>( 2); L.add(b); return new NiceIterator<T>() { private int index = 0; private Iterator<? extends T> current = a; public boolean hasNext() { while (current.hasNext() == false && index < L.size()) current = L.get(index++); return current.hasNext(); } public T next() { return hasNext() ? current.next() : noElements("concatenation"); } public void close() { close(current); for (int i = index; i < L.size(); i += 1) { close(L.get(i)); } } public void remove() { current.remove(); } public IExtendedIterator<T> andThen(Iterator<? extends T> other) { L.add(other); return this; } }; } /** * make a new iterator, which is us then the other chap. */ public IExtendedIterator<T> andThen(Iterator<? extends T> other) { return andThen(this, other); } /** * make a new iterator, which is our elements that pass the filter */ public IExtendedIterator<T> filterKeep(Filter<? super T> f) { return new FilterKeepIterator<T>(f, this); } /** * make a new iterator, which is our elements that do not pass the filter */ public IExtendedIterator<T> filterDrop(final Filter<? super T> f) { return new FilterDropIterator<T>(f, this); } /** * make a new iterator which is the elementwise _map1_ of the base iterator. */ public <B> IExtendedIterator<B> mapWith(IMap<? super T, ? extends B> map) { return new MappedIterator<T, B>(map, this); } /** * If <code>it</code> is a ClosableIterator, close it. Abstracts away from * tests [that were] scattered through the code. */ public static void close(Iterator<?> it) { if (it instanceof AutoCloseable) { try { ((AutoCloseable) it).close(); } catch (Exception e) { // ignore } } } static final private NiceIterator<?> emptyInstance = new NiceIterator<Object>(); /** * An iterator over no elements. * * @return A class singleton which doesn't iterate. */ @SuppressWarnings("unchecked") static public <T> IExtendedIterator<T> emptyIterator() { return (IExtendedIterator<T>) emptyInstance; } /** * Answer a list of the elements in order, consuming this iterator. */ public List<T> toList() { return asList(this); } /** * Answer a list of the elements in order, consuming this iterator. */ public Set<T> toSet() { return asSet(this); } /** * Answer a list of the elements of <code>it</code> in order, consuming this * iterator. Canonical implementation of toSet(). */ public static <T> Set<T> asSet(IExtendedIterator<? extends T> it) { Set<T> result = new HashSet<T>(); while (it.hasNext()) { result.add(it.next()); } return result; } /** * Answer a list of the elements from <code>it</code>, in order, consuming * that iterator. Canonical implementation of toList(). */ public static <T> List<T> asList(Iterator<? extends T> it) { List<T> result = new ArrayList<T>(); while (it.hasNext()) { result.add(it.next()); } return result; } public Iterator<T> iterator() { return this; } }