/* XXL: The eXtensible and fleXible Library for data processing
Copyright (C) 2000-2011 Prof. Dr. Bernhard Seeger
Head of the Database Research Group
Department of Mathematics and Computer Science
University of Marburg
Germany
This library 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; either
version 3 of the License, or (at your option) any later version.
This library 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.
You should have received a copy of the GNU Lesser General Public
License along with this library; If not, see <http://www.gnu.org/licenses/>.
http://code.google.com/p/xxl/
*/
package xxl.core.cursors.sources;
import xxl.core.cursors.AbstractCursor;
/**
* A repeater reiterates a given object <tt>n</tt> times. The argument
* <tt>times</tt> may be specified by the caller, so the given object will be
* delivered by calls to the <tt>next</tt> method <tt>times</tt> times. Otherwise
* the same object will infinitely be returned to the caller, when invoking the
* <tt>next</tt> method. In that case the <tt>hasNext</tt> method never returns
* <tt>false</tt>.
*
* <p><b>Example usage (1):</b>
* <pre>
* Repeater repeater = new Repeater(new Integer(1));
*
* repeater.open();
*
* for (int i = 0; i < 10; i++)
* System.out.print(repeater.next() + "; ");
* System.out.flush();
* System.out.println();
*
* repeater.close();
* </pre>
* This instance of a repeater returns an integer instance with value '1'
* infinitely often. With the intention to abort this operator, a for-loop is
* used returning only the first ten elements. In consequence the integer value
* is printed to the output stream for ten times.</p>
*
* <p><b>Example usage (2):</b>
* <pre>
* repeater = new Repeater(new Integer(1), 10);
*
* repeater.open();
*
* while (repeater.hasNext())
* System.out.print(repeater.next() + "; ");
* System.out.flush();
* System.out.println();
*
* repeater.close();
* </pre>
* This example shows a repeater with a given integer instance with value '1',
* which is returned for ten times, because in this case the user specified the
* parameter <tt>times</tt> in the constructor. The output is equal to that of
* example(1).</p>
*
* @param <E> the type of the elements returned by this iteration.
* @see java.util.Iterator
* @see xxl.core.cursors.Cursor
* @see xxl.core.cursors.AbstractCursor
*/
public class Repeater<E> extends AbstractCursor<E> {
/**
* The object repeatedly returned to the caller.
*/
protected E object;
/**
* A flag to signal if the object was exchanged.
*/
protected boolean replaced;
/**
* The number of times the object should be repeated.
*/
protected int times;
/**
* The number of times the object is still to be repeated.
*/
protected int left;
/**
* A flag to signal if the object should be repeated infinitely often.
*/
protected boolean unlimited;
/**
* Creates a new repeater. This repeater reiterates the input element only
* for a finite number of times.
*
* @param object the element that should repeatedly be returned to the
* caller.
* @param times the number of times the element should be repeated.
*/
public Repeater(E object, int times) {
this.object = object;
this.left = this.times = times;
this.unlimited = false;
this.replaced = true;
}
/**
* Creates a new repeater. This repeater reiterates the input element
* infinitely often.
*
* @param object the element that should repeatedly be returned to the
* caller.
*/
public Repeater(E object) {
this.object = object;
this.unlimited = true;
this.replaced = true;
}
/**
* Returns <tt>true</tt> if the iteration has more elements. (In other
* words, returns <tt>true</tt> if <tt>next</tt> or <tt>peek</tt> would
* return an element rather than throwing an exception.)
*
* @return <tt>true</tt> if the repeater has more elements.
*/
protected boolean hasNextObject() {
return unlimited ? true : left > 0;
}
/**
* Returns the next element in the iteration. This element will be
* accessible by some of the repeater's methods, e.g., <tt>update</tt> or
* <tt>remove</tt>, until a call to <tt>next</tt> or <tt>peek</tt> occurs.
* This is calling <tt>next</tt> or <tt>peek</tt> proceeds the iteration and
* therefore its previous element will not be accessible any more.
*
* @return the next element in the iteration.
*/
protected E nextObject() {
if (!unlimited)
left--;
if (replaced)
replaced = false;
return object;
}
/**
* Replaces the last element returned by the repeater in the underlying data
* structure (optional operation). This method can be called only once per
* call to <tt>next</tt> or <tt>peek</tt> and updates the element returned
* by this method. Note, that between a call to <tt>next</tt> and
* <tt>update</tt> the invocation of <tt>peek</tt> or <tt>hasNext</tt> is
* forbidden. The behaviour of a cursor is unspecified if the underlying
* data structure is modified while the iteration is in progress in any way
* other than by calling this method.
*
* <p>Note, that this operation is optional and might not work for all
* cursors.</p>
*
* @param object the object that replaces the last element returned by the
* repeater.
* @throws IllegalStateException if the <tt>next</tt> or <tt>peek</tt> method
* has not yet been called, or the <tt>update</tt> method has already
* been called after the last call to the <tt>next</tt> or
* <tt>peek</tt> method.
* @throws UnsupportedOperationException if the <tt>update</tt> operation is
* not supported by the repeater.
*/
public void update(E object) throws IllegalStateException, UnsupportedOperationException {
super.update(object);
this.object = object;
replaced = true;
}
/**
* Returns <tt>true</tt> if the <tt>update</tt> operation is supported by
* the repeater. Otherwise it returns <tt>false</tt>.
*
* @return <tt>true</tt> if the <tt>update</tt> operation is supported by
* the repeater, otherwise <tt>false</tt>.
*/
public boolean supportsUpdate() {
return true;
}
/**
* Resets the repeater to its initial state such that the caller is able to
* traverse the underlying data structure again without constructing a new
* repeater (optional operation). The modifications, removes and updates
* concerning the underlying data structure, are still persistent.
*
* <p>Note, that this operation is optional and might not work for all
* cursors.</p>
*
* @throws UnsupportedOperationException if the <tt>reset</tt> operation is
* not supported by the repeater.
*/
public void reset() throws UnsupportedOperationException {
super.reset();
if (!unlimited)
left = times;
}
/**
* Returns <tt>true</tt> if the <tt>reset</tt> operation is supported by
* the repeater. Otherwise it returns <tt>false</tt>.
*
* @return <tt>true</tt> if the <tt>reset</tt> operation is supported by
* the repeater, otherwise <tt>false</tt>.
*/
public boolean supportsReset() {
return true;
}
}