/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package com.github.geophile.erdo.map;
import com.github.geophile.erdo.AbstractKey;
import com.github.geophile.erdo.map.emptymap.EmptyMapCursor;
import java.io.IOException;
public abstract class MapCursor
{
public abstract LazyRecord next() throws IOException, InterruptedException;
public abstract LazyRecord previous() throws IOException, InterruptedException;
public void close()
{
state = State.DONE;
}
public void goToFirst() throws IOException, InterruptedException
{
startKey = null;
state = State.NEVER_USED;
unboundStartAtFirstKey = true;
}
public void goToLast() throws IOException, InterruptedException
{
startKey = null;
state = State.NEVER_USED;
unboundStartAtFirstKey = false;
}
public void goTo(AbstractKey key) throws IOException, InterruptedException
{
assert key != null;
startKey = key;
state = State.NEVER_USED;
}
protected boolean isOpen(AbstractKey key)
{
if (key == null) {
// cursor is closed because we've run off the end
return false;
}
if (fullScan) {
// scanning the entire map, regardless of erdoId, so any non-null key is part of the cursor
return true;
}
if (key.erdoId() == startKey.erdoId()) {
// In the same OrderedMap as startKey
return !singleKey || key.equals(startKey);
} else {
return false;
}
}
protected MapCursor(AbstractKey startKey, boolean singleKey)
{
assert startKey != null || !singleKey;
this.startKey = startKey;
this.singleKey = singleKey;
this.state = State.NEVER_USED;
this.fullScan = startKey == null;
}
// Object state
// Kinds of scans:
// - Complete scan of map, across all erdoIds: startKey == null, singleKey == false. Used in consolidation.
// - Exact match: startKey != null, singleKey = true
// - Start at key, limited to one erdoId: startKey != null, singleKey = false
// - Other: canCheckIsOpen is false, meaning the subclass will check loop termination.
protected AbstractKey startKey;
protected State state;
private final boolean singleKey;
// unboundStartAtFirstKey is used to indicate where to position the cursor while in the NEVER_USED state,
// with startKey = null. true means start at the first key, false means start at the last key.
protected boolean unboundStartAtFirstKey;
private final boolean fullScan;
// Inner classes
public static final MapCursor EMPTY = new EmptyMapCursor();
protected enum State
{
// The cursor has been created, but has never been used to retrieve a record. If the key used to create
// the cursor is present, then both next() and previous() will retrieve the associated record. This state
// is also used when a cursor is repositioned using goTo().
NEVER_USED,
// The cursor has been created and used to retrieve at least one record. next() and previous() move the
// cursor before retrieving a record.
IN_USE,
// The cursor has run off one end. A call to next() or previous() will return null.
DONE
}
public interface Expression
{
MapCursor evaluate() throws IOException, InterruptedException;
}
}