Static utility methods, classes, and abstract classes for iteration.
/*
* LingPipe v. 3.9
* Copyright (C) 2003-2010 Alias-i
*
* This program is licensed under the Alias-i Royalty Free License
* Version 1 WITHOUT ANY WARRANTY, without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Alias-i
* Royalty Free License Version 1 for more details.
*
* You should have received a copy of the Alias-i Royalty Free License
* Version 1 along with this program; if not, visit
* http://alias-i.com/lingpipe/licenses/lingpipe-license-1.txt or contact
* Alias-i, Inc. at 181 North 11th Street, Suite 401, Brooklyn, NY 11211,
* +1 (718) 290-9170.
*/
//package com.aliasi.util;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.List;
/**
* Static utility methods, classes, and abstract classes for
* iteration.
*
* @author Bob Carpenter
* @author Mike Ross
* @version 4.0.0
* @since LingPipe2.0
*/
public class Iterators {
// do not allow instances
private Iterators() {
/* no instances */
}
static final Iterator<Object> EMPTY_ITERATOR
= new Empty<Object>();
/**
* Returns an iterator that has no elements. Thus {@code
* hasNext()} will always return {@code false} and {@code next()}
* will always throw a {@code NoSuchElementException}.
*
* @return The empty iterator.
*/
public static <E> Iterator<E> empty() {
@SuppressWarnings("unchecked")
Iterator<E> emptyIterator = (Iterator<E>) EMPTY_ITERATOR;
return emptyIterator;
}
/**
* Returns an iterator over the single specified element.
* Thus {@code next()} will return the specified element
* on the first call, with subsequent calls
* throwing a {@code NoSuchElementException} .
*
* @param e The object to return in the iterator.
* @return The iterator over the specified object.
*/
public static <E> Iterator<E> singleton(E e) {
Iterator<E> singletonIterator = new Singleton<E>(e);
return singletonIterator;
}
/**
* Returns a newly constructed iterator over the specified pair of
* elements.
*
* <p><i>Implementation Note:</i> References to the elemenets are
* removed from iterator after they are returned through {@code
* next()}.
*
* @param e1 First element returned.
* @param e2 Second element returned.
* @return The iterator over the pair of elements specified.
*/
public static <E> Iterator<E> pair(E e1, E e2) {
return new Pair<E>(e1,e2);
}
/**
* Returns an iterator constructed from the specified variable
* length argument list of objects.
*
* <p>Remove is supported, but has no effect on anything as the
* list from which elements are being deleted is only used for the
* iterator.
*
* @param es Array of objects for iteration.
* @return Iterator over list.
*/
public static <E> Iterator<E> list(E... es) {
return java.util.Arrays.<E>asList(es).iterator();
}
/**
* Returns an unmodifiable view of the specified iterator.
* Calls to {@code next()} and {@code hasNext()} are delegated
* to the specified iterator as made. Calls to {@code remove()}
* throw unsupported operation exceptions.
*
* @param it Iterator to view.
* @return Unmodifiable view of specified iterator.
*/
public static <E> Iterator<E> unmodifiable(Iterator<E> it) {
final Iterator<E> mIt = it;
return new Iterator<E>() {
public boolean hasNext() {
return mIt.hasNext();
}
public E next() {
return mIt.next();
}
public void remove() {
String msg = "Cannot remove from an unmodifiable iterator.";
throw new UnsupportedOperationException(msg);
}
};
}
/**
* Returns an iterator that runs through the first iterator's
* elements and then runs through the second iterator's elements.
*
* <p>References to the iterators are freed after it is finished
* iterating.
*
* @param it1 The first iterator in the sequence.
* @param it2 The second iterator in the sequence.
* @return The iterator over the two iterators.
*/
public static <E> Iterator<E> sequence(Iterator<? extends E> it1,
Iterator<? extends E> it2) {
Iterator<E> result = new Sequence<E>(it1,it2);
return result;
}
public static <E> Iterator<E> sequence(List<? extends Iterator<? extends E>> iterators) {
@SuppressWarnings({"unchecked","rawtypes"})
Iterator<? extends E>[] elts
= (Iterator<? extends E>[]) iterators.toArray(new Iterator[0]);
Iterator<E> it = new Sequence<E>(elts);
return it;
}
public static <E> Iterator<E>
sequence(Iterator<? extends Iterator<? extends E>> iteratorOfIterators) {
Iterator<E> it = new Sequence<E>(iteratorOfIterators);
return it;
}
/**
* Returns an iterator over the specified array of objects.
*
* <p><i>Warning:</i> The array is not copied, so any changes in
* the underlying array are reflected in the iterator.
*
* <P><I>Implementation Note:</I> this class does not
* automatically free references in the underlying array, because
* the array may be used elswhere. If reference freeing is
* critical here, a call to {@code remove()} after ever call to
* {@code next()} will free the references in the array.
*
* @param members Array of elements over which to iterate.
* @return The iterator over the array elements.
*/
public static <E> Iterator<E> array(E[] members) {
return new Array<E>(members);
}
/**
* Returns a newly constructed iterator over the specified
* object array slice.
*
* <p>The {@code remove()} method is not supported.
*
* <p><i>Warning:</i> The array is not copied, so any changes in
* the underlying array are reflected in the iterator.
*
* <P><I>Implementation Note:</I> this class does not
* automatically free references in the underlying array, because
* the array may be used elswhere.
*
* @param members Array of objects over which to iterate.
* @param start Index of first object to return.
* @param length Number of objects to iterate.
* @throws Illegal argument exception if {@code start < 0} or
* {@code start + length > objects.length()}.
*/
public static <E> Iterator<E> arraySlice(E[] members, int start, int length) {
return new ArraySlice<E>(members,start,length);
}
/**
* An <code>Iterator.Array</code> iterates over the elements of an
* array specified at construction time.
*
* <P><I>Implementation Note:</I> this class does not automatically
* free references in the underlying array, because the array
* may be used elswhere. If reference freeing is critical here,
* a call to <code>remove()</code> after ever <code>next()</code>
* will free the references in the array.
*
* @author Bob Carpenter
* @version 3.8
* @since LingPipe1.0
* @param <E> the type of objects returned by the iterator
*/
static class Array<E> implements Iterator<E> {
/**
* Array to iterate over.
*/
private final E[] mMembers;
/**
* Current position of next element to return in array.
*/
private int mPosition;
/**
* Construct an array iterator from the specified array.
*
* @param members Array basis of the constructed iterator.
*/
public Array(E[] members) {
mMembers = members;
}
/**
* Returns <code>true</code> if this iterator has more
* elements.
*
* @return <code>true</code> if this iterator has more
* elements.
*/
public boolean hasNext() {
return mPosition < mMembers.length;
}
/**
* Returns the next element in the array.
*
* @return Next element in the array.
* @throws NoSuchElementException If there are no more
* elements left in the array to return.
*/
public E next() {
if (!hasNext())
throw new NoSuchElementException();
return mMembers[mPosition++];
}
/**
* Sets position in underlying array corresponding to the most
* recently returned token to <code>null</code>.
*
* @throws IllegalStateException If the <code>next</code>
* method has not been called, or the <code>remove</code>
* method has already been called after the last call to the
* next method.
*/
public void remove() {
if (mPosition < 1)
throw new IllegalStateException("Next not yet called.");
if (mMembers[mPosition-1] == null)
throw new IllegalStateException("Remove already called.");
mMembers[mPosition-1] = null;
}
}
/**
* An <code>Iterators.ArraySlice</code> iterates over a slice of
* an array specified by start index and length.
*
* @author Bob Carpenter
* @version 3.8
* @since LingPipe1.0
* @param <E> the type of objects returned by the iterator
*/
static class ArraySlice<E> implements Iterator<E> {
/**
* The underlying objects represented in this array iterator.
*/
private final E[] mObjects;
/**
* Index of next element to return.
*/
private int mNext;
/**
* Index one past the index of the last element to return.
*/
private final int mLast;
/**
* Construct an iterator over the specified array of objects
* that begins at the object at the specified start index
* and carries through to the other objects.
*
* @param objects Array of objects over which to iterate.
* @param start Index of first object to return.
* @param length Number of objects to iterate.
* @throws Illegal argument exception if {@code start < 0} or
* {@code start + length > objects.length}.
*/
public ArraySlice(E[] objects,
int start, int length) {
if (start < 0) {
String msg = "Require start of slice to be non-negative."
+ " Found start=" + start;
throw new IllegalArgumentException(msg);
}
if (start + length > objects.length) {
String msg = "Start plus length must not exceed array length."
+ " Found objects.length=" + objects.length
+ " start=" + start
+ " length=" + length
+ " (start+length)=" + (start+length);
throw new IllegalArgumentException(msg);
}
mObjects = objects;
mNext = start;
mLast = start + length;
}
/**
* Returns <code>true</code> if there are more objects
* to return.
*
* @return <code>true</code> if this iterator has more
* elements.
*/
public boolean hasNext() {
return mNext < mLast;
}
/**
* Returns the next object for this iterator, throwing
* an exception if there are no more objects left.
*
* @return Next object from this iterator.
* @throws NoSuchElementException If there are no more
* elements to return.
*/
public E next() {
if (!hasNext()) throw new NoSuchElementException();
return mObjects[mNext++];
}
/**
* Throws an <code>UnsupportedOperationException</code>.
*
* @throws UnsupportedOperationException If called.
*/
public void remove() {
throw new UnsupportedOperationException();
}
}
/**
* An <code>Iterator.Empty</code> is an iterator with no
* objects. The method {@link #hasNext()} always returns
* <code>false</code>, while the methods {@link #next()}
* and {@link #remove()} always throw exceptions.
*
* @author Bob Carpenter
* @version 3.8
* @since LingPipe3.0
* @param <E> the type of objects returned by the iterator
*/
static class Empty<E> implements Iterator<E> {
/**
* Construct an empty iterator.
*/
public Empty() {
/* do nothing */
}
/**
* Always returns <code>false</code>.
*
* @return <code>false</code>.
*/
public boolean hasNext() {
return false;
}
/**
* Calling this method throws a no-such-element exception.
*
* @return Always throws an exception.
* @throws NoSuchElementException Always.
*/
public E next() {
String msg = "No elements in empty iterator.";
throw new NoSuchElementException(msg);
}
/**
* Calling this method throws an illegal state exception.
*
* @throws IllegalStateException Always.
*/
public void remove() {
String msg = "No elements to remove in empty iterator.";
throw new IllegalStateException(msg);
}
}
/**
* An <code>Iterator.Singleton</code> is an iterator over a
* singleton object.
*
* @author Bob Carpenter
* @version 3.8
* @since LingPipe2.0
* @param <E> the type of objects returned by the iterator
*/
static class Singleton<E> implements Iterator<E> {
/**
* The single object to return.
*/
private E mMember;
/**
* <code>true</code> if the single element has not already
* been returned.
*/
private boolean mHasNext = true;
/**
* Construct a singleton iterator that returns the specified
* object.
*
* @param member Single member over which to iterate.
*/
public Singleton(E member) {
mMember = member;
}
/**
* Returns <code>true</code> if the single member has not
* already been returned.
*
* @return <code>true</code> if the single member has not
* already been returned.
*/
public boolean hasNext() {
return mHasNext;
}
/**
* Returns the singleton member if it has not yet been
* returned, otherwise throw an exception.
*
* @return Singleton member if it has not yet been returned.
* @throws NoSuchElementException If the singleton member has
* already been returned and no elements remain.
*/
public E next() {
if (!mHasNext)
throw new NoSuchElementException();
mHasNext = false;
E result = mMember;
mMember = null;
return result;
}
/**
* Throws an unsupported operation exception.
*
* @throws UnsupportedOperationException Whenver called.
*/
public void remove() {
String msg = "This iterator does not support remove()."
+ " class=" + this.getClass();
throw new UnsupportedOperationException(msg);
}
}
/**
* An <code>Iterators.Pair</code> provides an iterator
* over a sequence of exactly two elements.
*
* @author Bob Carpenter
* @version 3.0
* @since LingPipe2.0
* @param <E> the type of objects returned by the iterator
*/
static class Pair<E> implements Iterator<E> {
/**
* Number of members returned so far.
*/
private int mMembersReturned = 0;
private E mMember1;
private E mMember2;
/**
* Construct a pair iterator based on the containing
* pair set.
*
* @param member1 First member.
* @param member2 Second member.
*/
public Pair(E member1, E member2) {
mMember1 = member1;
mMember2 = member2;
}
/**
* Returns <code>true</code> if there are more elements
* left to return.
*
* @return <code>true</code> if there are more elements
* left to return.
*/
public boolean hasNext() {
return mMembersReturned < 2;
}
/**
* Returns the next object in this pair iterator,
* or throws an exception if there aren't any more.
*
* @return Next object in this pair iterator.
*/
public E next() {
if (mMembersReturned == 0) {
++mMembersReturned;
E result1 = mMember1;
mMember1 = null;
return result1;
}
if (mMembersReturned == 1) {
++mMembersReturned;
E result2 = mMember2;
mMember2 = null;
return result2;
}
throw new NoSuchElementException();
}
/**
* Throws an unsupported operation exception.
*
* @throws UnsupportedOperationException Whenver called.
*/
public void remove() {
String msg = "This iterator does not support remove()."
+ " class=" + this.getClass();
throw new UnsupportedOperationException(msg);
}
}
/**
* An <code>Iterators.Filter</code> filters the stream of objects
* returned by another iterator by subjecting them to an acceptance
* test. Instances are constructed with a specified iterator to be
* filtered; this filter is saved in this class and should not be
* accessed by other methods. Concrete subclasses must implement
* {@link #accept(Object)}, which determines which of the elements
* produced by the containediterator are returned.
*
* @author Bob Carpenter
* @version 3.0
* @since LingPipe1.0
* @param <E> the type of objects returned by the iterator
*/
public static abstract class Filter<E> implements Iterator<E> {
private final Iterator<? extends E> mIterator;
private boolean mFoundNext = false;
private E mNext;
/**
* Construct a filtered iterator from the specified iterator.
*
* @param iterator Contained iterator to be filtered.
*/
public Filter(Iterator<? extends E> iterator) {
mIterator = iterator;
}
/**
* Returns <code>true</code> for objects returned by the contained
* iterator that should be returned by this iterator.
*
* @param x Object to test.
* @return <code>true</code> if this object should be returned by
* this iterator.
*/
abstract public boolean accept(E x);
/**
* Returns <code>true</code> if calls to <code>next()</code> will
* return a value.
*
* <P><i>Implementation note:</i> This iterator stores the next
* element in a local variable after calls to this method. Calls to
* {@link #next()} remove this reference.
*
* @return <code>true</code> if calls to <code>next()</code> will
* return a value.
*/
public boolean hasNext() {
if (mFoundNext) return true;
while (mIterator.hasNext()) {
E y = mIterator.next();
if (accept(y)) {
mFoundNext = true;
mNext = y;
return true;
}
}
return false;
}
/**
* Returns the next value from the contained iterator that is accepted.
* Acceptance is determined by the method {@link #accept(Object)}.
*
* @return Next object from the underlying iterator that passes
* the acceptance test.
* @throws NoSuchElementException If there are no more elements in
* the underlying iterator that pass the acceptance test.
*/
public E next() {
if (!hasNext())
throw new NoSuchElementException();
mFoundNext = false;
E result = mNext;
mNext = null;
return result;
}
/**
* This operation is not supported.
*
* <P><i>Implementation Note:</i> Because calls to {@link
* #hasNext()} must iterate over the contained iterator to find
* the next acceptable object to return, it is not guaranteed that
* the last element returned by this iterator is the same as the
* last element returned by the underlying iterator. Thus the
* underlying iterator can't be used to do the removal without
* tripping the fail-fast behavior of {@link Iterator}.
*
* @throws UnsupportedOperationException Always.
*/
public void remove() {
String msg = "Cannot remove from a filtered iterator.";
throw new UnsupportedOperationException(msg);
}
}
/**
* An <code>Iterator.Modifier</code> uses a single abstract method
* to operate on the elements returned by an underlying iterator
* to return modified objects. The {@link #remove()} and {@link
* #hasNext()} methods are simply passed to the underlying iterator.
* This implements the filter pattern, which is known as a map in
* functional programming.
*
* @author Bob Carpenter
* @version 3.0
* @since LingPipe2.1
* @param <E> the type of objects returned by the iterator
*/
public static abstract class Modifier<E> implements Iterator<E> {
private final Iterator<? extends E> mIt;
/**
* Construct a modifier from an underlying iterator.
*
* @param it Underlying iterator.
*/
public Modifier(Iterator<? extends E> it) {
mIt = it;
}
/**
* Remove the next element by delegating the call to the the
* underlying iterator.
*/
public void remove() {
mIt.remove();
}
/**
* Returns <code>true</code> if the underlying iterator has
* more elements. This method is simply delegated to the
* underlying iterator.
*
* @return <code>true</code> if this iterator has more
* elements.
*/
public boolean hasNext() {
return mIt.hasNext();
}
/**
* Returns the next element for this iterator, which is
* the object returned by the underlying iterator after
* undergoing modification by {@link #modify(Object)}.
*
* @return The modified next element from the underlying
* iterator.
*/
public E next() {
return modify(mIt.next());
}
/**
* This abstract method is applied to objects returned by the
* underlying iterator to create the object returned by this
* iterator. This method is called once for each call to
* {@link #next()}.
*
* @param next Object returned by underlying iterator.
* @return Object returned by this iterator.
*/
public abstract E modify(E next);
}
/**
* An <code>Iterators.Buffered</code> uses a single method to return
* objects, buffering the result and returning it as the next element
* if it is non-<code>null</code>. This class does not support
* <code>null</code> return values for {@link #next()}. The {@link
* #remove()} operation is unsupported, but may be overridden.
*
* @author Bob Carpenter
* @version 3.0
* @since LingPipe1.0
* @param <E> the type of objects returned by the iterator
*/
public static abstract class Buffered<E> implements Iterator<E> {
private E mNext;
/**
* Construct a buffered iterator. This constructor does not
* do anything.
*/
protected Buffered() {
// do nothing
}
/**
* Returns the next object for this iterator, or <code>null</code>
* if there are no more objects.
*
* @return Next object for this iterator.
*/
protected abstract E bufferNext();
/**
* Returns <code>true</code> if the next call to {@link #next()}
* will return a non-<code>null</code> value.
*
* @return <code>true</code> if the next call to {@link #next()}
* will return a non-<code>null</code> value.
*/
public boolean hasNext() {
return mNext != null
|| (mNext = bufferNext()) != null;
}
/**
* Returns the next object for this iterator.
*
* @return The next object for this iterator.
* @throws NoSuchElementException If there are no more elements.
*/
public E next() {
if (!hasNext())
throw new NoSuchElementException();
E result = mNext;
mNext = null;
return result;
}
/**
* Throws an unsupported operation exception unless overridden by
* a subclass.
*
* @throws UnsupportedOperationException Always.
*/
public void remove() {
throw new UnsupportedOperationException();
}
}
/**
* An <code>Iterators.Sequence</code> iterates over the elements of an
* ordered sequence of iterators in turn. Each iterator is exhausted
* before moving to the next. These iterators may be supplied as a
* pair of iterators, as an array of iterators, or as an iterator of
* iterators. The sequence iterator delegates calls to {@link
* #next()} and {@link #remove()} to the relevant iterator in the
* underlying sequence of iterators. For <code>next()</code>, this is
* the current underlying iterator. For <code>remove()</code>, it's
* the last iterator whose <code>next()</code> element was called, and
* it throws an illegal state exception if there isn't one.
*
* <P><I>Implementation Note:</I> Because of the requirements of
* {@link Iterator#remove()}, a reference to the last iterator is
* kept, as well as to the current iterator. Otherwise, the sequence
* iterator will release resources as soon as possible. If the
* supplied sequence is an array, the elements will not be
* automatically returned from that array; it is simply wrapped in an
* instance of {@link Iterators.Array}.
*
* @author Bob Carpenter
* @version 3.8
* @since LingPipe1.0
* @param <E> the type of objects returned by the iterator
*/
static class Sequence<E> implements Iterator<E> {
private final Iterator<? extends Iterator<? extends E>> mIterators;
private Iterator<? extends E> mCurrentIterator;
private Iterator<? extends E> mLastIteratorNextCalled;
/**
* Construct a sequenc iterator that calls the pair of
* iterators specified in turn.
*
* @param iterator1 First iterator.
* @param iterator2 Second iterator.
*/
public Sequence(Iterator<? extends E> iterator1,
Iterator<? extends E> iterator2) {
this(toIteratorIterator(iterator1,iterator2));
}
/**
* Construct a sequence iterator that calls the iterators in the
* specified array in the order they are given in the array.
*
* @param iterators Sequence of iterators.
*/
public Sequence(Iterator<? extends E>[] iterators) {
this(new Iterators.Array<Iterator<? extends E>>(iterators));
}
/**
* Construct a sequence iterator that calls the iterators returned
* by the iterator of iterators specified. If one of the elements
* is not an iterator, <code>hasNext()</code> and
* <code>next()</code> will throw a
* <code>ClassCastException</code>.
*
* @param iteratorOfIterators Iterator of iterators.
*/
public Sequence(Iterator<? extends Iterator<? extends E>> iteratorOfIterators) {
mIterators = iteratorOfIterators;
}
/**
* Returns <code>true</code> if this iterator has another element.
* This sequence of iterators has another element if it has
* another iterator that has another element.
*
* @return <code>true</code> if this sequence of iterators
* has another iterator with another element.
* @throws ClassCastException If an object is returned by
* the iterator of iterators specified at construction time
* that is not an iterator.
*/
public boolean hasNext() {
if (mCurrentIterator == null)
nextIterator(); // get started
for (; mCurrentIterator != null; nextIterator())
if (mCurrentIterator.hasNext())
return true;
return false;
}
/**
* Return the next element returned by the next iterator in the
* iterator sequence.
*
* @return The next object in the iteration.
* @throws ClassCastException If an object is returned by
* the iterator of iterators specified at construction time
* that is not an iterator.
*/
public E next() {
if (!hasNext())
throw new NoSuchElementException();
mLastIteratorNextCalled = mCurrentIterator;
return mCurrentIterator.next();
}
/**
* Removes the last element returned by this iterator from the
* collection underlying the iterator from which it was returned.
* The method can only be called once per call to
* <code>next()</code>.
* @throws IllegalStateException If <code>next()</code> has not
* yet been called, or <code>remove()</code> method has
* been called after the last call to <code>next()</code>.
*/
public void remove() {
if (mLastIteratorNextCalled == null)
throw new IllegalStateException("next() not yet called.");
mLastIteratorNextCalled.remove();
mLastIteratorNextCalled = null;
}
private void nextIterator() {
// possible cast exception
mCurrentIterator =
mIterators.hasNext()
? mIterators.next()
: null;
}
static <E> Iterator<? extends Iterator<? extends E>>
toIteratorIterator(Iterator<? extends E> it1,
Iterator<? extends E> it2) {
ArrayList<Iterator<? extends E>> list
= new ArrayList<Iterator<? extends E>>(2);
list.add(it1);
list.add(it2);
return list.iterator();
}
}
/**
* A {@code Iterators.PrimitiveInt} is an integer iterator that
* also allows objects to be accessed as primitive {@code int}
* values.
*
* <p>The method {@link #next()} returns an {@code Integer},
* whereas {@link #nextPrimitive()} returns a primitive {@code
* int} value. Using either one will advanced the iterator to the
* next element.
*
* <p><i>Implementation Note:</i> Using the standard iterator
* implementation as {@code Integer} requires boxing of the
* primitive values as objects. Therefore, use the method
* {@code nextPrimitive()} wherever possible.
*
* @author Mike Ross
* @author Bob Carpenter
* @version 3.8
* @since Lingpipe3.8
*/
public static abstract class PrimitiveInt
implements Iterator<Integer> {
/**
* Returns the next primitive integer.
*
* @return The next primitive integer.
*/
abstract public int nextPrimitive();
/**
* Returns {@code true} if there is another integer in the
* iteration.
*
* @return {@code true} if there is another integer in the
* iteration.
*/
abstract public boolean hasNext();
/**
* Throws unsupported operation exception.
*
* @throws UnsupportedOperationException Always.
*/
public void remove() {
String msg = "Iterators.PrimitiveInt does not support remove.";
throw new UnsupportedOperationException(msg);
}
/**
* Returns the next integer result.
*
* <p><i>Implementation Note:</i> Requires boxing the
* primitive {@code int} returned by {@link #nextPrimitive()}.
*
* @return The next integer.
*/
public Integer next() {
return nextPrimitive();
}
}
/**
* Construct an Integer iterator from 0 (inclusive) the specified
* end point (exclusive). The returned iterator does not support
* {@code remove()}.
*
* @param end One plus the last integer returned.
*/
public static PrimitiveInt intRange(int end) {
return new IntRange(0,end);
}
/**
* Returns a newly constructed primitive integer iterator that
* iterates from the start (inclusive) to end (exclusive).
*
* <p>The returned iterator does not support {@code remove()}.
*
* @param start The first and lowest value to return.
* @param end One plus the last integer returned.
* @throws IllegalArgumentException If {@code start > end}.
*/
public static PrimitiveInt intRange(int start, int end) {
return new IntRange(start,end);
}
/**
* Returns an iterator over the array of primitive integers
* specified.
*
* <p>There are no order restrictions on the array -- its elements
* may be in any order and may contain duplicates.
*
* <p>The returned iterator does not support {@code remove()}.
*
* @param members Array of members to iterate.
*/
public static PrimitiveInt intArray(int[] members) {
return new IntArray(members);
}
/**
* See {@link #intRange(int,int)} for usage.
*
* @author Mike Ross
* @version 3.8
* @since Lingpipe3.8
*/
static class IntRange extends PrimitiveInt {
private int mCur;
private final int mEnd;
public IntRange(int start, int end) {
if (end < start) {
String msg = "End point must be >= start point."
+ " Found start=" + start
+ " end=" + end;
throw new IllegalArgumentException(msg);
}
mCur = start;
mEnd = end;
}
public boolean hasNext() {
return mCur < mEnd;
}
public int nextPrimitive() {
if (!hasNext())
throw new NoSuchElementException();
return mCur++;
}
}
/**
* See {@link #intArray(int[])} for usage.
*
* @author Mike Ross
* @version 3.8
* @since Lingpipe3.8
*/
static class IntArray extends PrimitiveInt {
private final int[] mMembers;
private int mPosition;
public IntArray(int[] members) {
mMembers = members;
}
public boolean hasNext() {
return mPosition < mMembers.length;
}
public int nextPrimitive() {
if (!hasNext())
throw new NoSuchElementException();
return mMembers[mPosition++];
}
}
}
Related examples in the same category