net.sf.staccatocommons.iterators.thriter.Thriter Maven / Gradle / Ivy
/**
* Copyright (c) 2010-2012, The StaccatoCommons Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*/
package net.sf.staccatocommons.iterators.thriter;
import java.util.NoSuchElementException;
import net.sf.staccatocommons.defs.Thunk;
import net.sf.staccatocommons.restrictions.check.NonNull;
import net.sf.staccatocommons.restrictions.effect.SideEffectFree;
/**
* A {@link Thriter} - acronym for Three-messages
* Iterator - is an object that can traverse elements of type
* {@code A} from a collection-like object, much like an {@link Iterator} does,
* but using three messages instead of two, enabling new lazy features.
*
* Such messages are {@link #hasNext()}, {@link #advanceNext()} and
* {@link #current()}:
*
* -
* {@link #hasNext()} is completely equivalent to {@link Iterator#hasNext()} ,
* this message just polls if the iterator has more elements. It
* must be side-effect free, and its result must be constant as
* long as the thriter is not advanced.
* -
* {@link #advanceNext()} advances the iterator to its next element, but it does
* not return it. Like {@link Iterator#next()}, it must throw a
* no {@link NoSuchElementException} if the iterator has reached its end
* - {@link #current()} returns the element at the actual position. This
* method should return the same element as long as the thriter
* is not advanced, but the result of evaluating it if the thriter was never
* advanced is undefined. Lazy thriters should implementing the
* actual processing here
*
*
* For example,
*
*
* while (thriter.hasNext) {
* thriter.advanceNext();
* A elem = thriter.current();
* }
*
*
*
* Although normal iteration on thriters is more complex that in
* {@link Iterator}s, the power of {@link Thriter}s lays if that it allows to
* perform special lazy iterations that would be otherwise impossible with an
* plain two-messages iterator.
*
*
* For example, lets assume that a {@link Thriter} {@code thriter} can retrieve
* two elements, and that its first element is bottom
- that is, it
* will never return normally, for example, by throwing an exception or by
* falling in a infinite loop. Then, the second element of the {@code thriter}
* is an actual value - accessing it would return normally. In such scenario,
* the following successfully obtains the second element of the thriter:
*
*
*
* thriter.advance();
* thriter.advance();
* thriter.current();
*
*
* However, the same behavior is impossible to implement using a
* {@link Iterator}, as in order to access the n element, it is necessary to
* access the n-1 element.
*
*
* @author flbulgarelli
* @see Thriterator
* @see AbstractThriterator
* @param
* the type of elements retrieved by this {@link Thriter}
*/
public interface Thriter {
/**
* Answers if the thriter has more elements, that is, if sending
* {@link #advanceNext()} would not result in a {@link NoSuchElementException}
*
* @return if the {@link Thriter} has more elements
*/
@SideEffectFree
boolean hasNext();
/**
* Advances to the thriter to the position of the next element.
*
* @throws NoSuchElementException
* if there are no more elements
*/
void advanceNext() throws NoSuchElementException;
/**
* Answers element at the current position of this {@link Thriter}. Result of
* this method if {@link #advanceNext()} was never evaluated before is
* undefined.
*
* @return the current element
*/
A current();
/**
* Answers a {@link Thunk} that, when evaluated through {@link Thunk#value()},
* will return the current element of this {@link Thriter} at the time of
* being {@link #delayedCurrent()} sent.
*
* This means, that the value of the returned thunk must must
* always equals, even if this {@link Thriter} was advanced later.
*
* @return a {@link Thunk} tha provides {@link #current()} at the time of this
* message being sent.
*/
@NonNull
Thunk delayedCurrent();
/**
* Advances this thriter and the returns {@link #delayedCurrent()}
*
* @return {@link #delayedCurrent()}
*/
@NonNull
Thunk delayedNext();
}