package it.unimi.dsi.mg4j.search;
/*
* MG4J: Managing Gigabytes for Java
*
* Copyright (C) 2007-2010 Sebastiano Vigna
*
* 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 program; if not, see <http://www.gnu.org/licenses/>.
*
*/
import it.unimi.dsi.fastutil.ints.AbstractIntIterator;
import it.unimi.dsi.fastutil.ints.IntIterator;
import it.unimi.dsi.fastutil.objects.AbstractObjectIterator;
import it.unimi.dsi.util.Interval;
import java.io.IOException;
import java.util.Iterator;
import java.util.NoSuchElementException;
/** An abstract iterator on documents that implements {@link IntIterator#hasNext() hasNext()}
* and {@link IntIterator#nextInt() nextInt()} using {@link DocumentIterator#nextDocument() nextDocument()},
* and provides support for the {@link DocumentIterator#weight()}/{@link DocumentIterator#weight(double)} methods.
*
* <p>As explained elsewhere, since MG4J 1.2 the iteration logic has been made fully lazy,
* and the standard {@link IntIterator} methods are available as a commodity, but their use
* in performance-sensitive environments is strongly discouraged. The fully lazy
* implementation needs some bridging to be accessible using {@link java.util}'s semi-lazy
* {@linkplain Iterator iterators}, and this class provides the necessary code.
*
* <p>Instances of this class keep track of the {@linkplain #next} document
* to be returned, if it has been already peeked at by {@link #hasNext()}, and of the
* {@linkplain #last} document returned by {@link #nextInt()} or
* {@link DocumentIterator#nextDocument() nextDocument()}. Concrete subclasses must implement
* {@link DocumentIterator#nextDocument() nextDocument()} so that after it has been called {@link #last} is
* equal to the returned document (possibly -1) and {@link #next} is -1 (of course,
* if {@link #next} has already been set <code>nextDocument()</code> must behave exactly
* like the implementation of <code>nextInt()</code> found in this class). Methods performing
* actions depending on the last document returned should throw an {@link IllegalStateException}
* if called when {@link #last} is -1.
*
*/
public abstract class AbstractDocumentIterator extends AbstractIntIterator implements DocumentIterator {
/** The last document returned by this iterator, or -1 if the iterator has never
* be advanced or if its state has been modified since the last call to {@link #nextInt()}
* or {@link DocumentIterator#nextDocument() nextDocument()} because of a call to {@link IntIterator#hasNext() hasNext()}. */
protected int last = -1;
/** The next document to be returned, if it has already been peeked at by {@link #hasNext()},
* or -1. */
protected int next = -1;
/** The weight of this iterator. */
protected double weight = 1;
public double weight() {
return weight;
}
public DocumentIterator weight( final double weight ) {
this.weight = weight;
return this;
}
/** Invokes {@link DocumentIterator#intervalIterator()}
*
* @return {@link DocumentIterator#intervalIterator()}.
*/
public IntervalIterator iterator() {
try {
return intervalIterator();
}
catch ( IOException e ) {
throw new RuntimeException( e );
}
}
/** Checks whether {@link #next} has been already set; if not, peeks at the document returned by {@link DocumentIterator#nextDocument() nextDocument()}.
*
* @return true if {@link #next} is not -1 or if {@link DocumentIterator#nextDocument() nextDocument()} has returned a valid document pointer.
*/
public boolean hasNext() {
if ( next == -1 ) try {
next = nextDocument();
last = -1;
}
catch ( IOException e ) {
throw new RuntimeException( e );
}
return next != -1;
}
/** Checks whether there is an element to be returned, sets {@link #last} to {@link #next},
* {@link #next} to -1, and returns {@link #last}.
*
* @return the next document pointer, as cached by {@link #hasNext()}.
*/
@Deprecated
public int nextInt() {
if ( ! hasNext() ) throw new NoSuchElementException();
last = next;
next = -1;
return last;
}
/** Returns {@link #last}, if it is not -1; otherwise, throws an {@link IllegalStateException}.
*
* @return {@link #last}, if it is not -1.
* @throws IllegalStateException if {@link #last} is -1.
*/
public int document() {
if ( last == -1 ) throw new IllegalStateException();
return last;
}
protected abstract static class AbstractIntervalIterator extends AbstractObjectIterator<Interval> implements IntervalIterator {
/** The next document to be returned, if it has already been peeked at by {@link #hasNext()},
* or <code>null</code>. */
protected Interval next;
/** Checks whether {@link #next} has been already set; if not, peeks at the interval returned by {@link IntervalIterator#nextInterval() nextInterval()}.
*
* @return true if {@link #next} is not <code>null</code> or if {@link IntervalIterator#nextInterval() nextInterval()} has returned a valid interval.
*/
public boolean hasNext() {
if ( next == null ) try {
next = nextInterval();
}
catch ( IOException e ) {
throw new RuntimeException( e );
}
return next != null;
}
/** Checks whether there is an interval to be returned, sets
* {@link #next} to <code>null</code>, and returns its previous value.
*
* @return the next interval, as cached by {@link #hasNext()}.
*/
@Deprecated
public Interval next() {
if ( ! hasNext() ) throw new NoSuchElementException();
final Interval result = next;
next = null;
return result;
}
}
}