package org.apache.cassandra.utils.btree;
import java.util.Comparator;
import java.util.Iterator;
import java.util.NoSuchElementException;
import org.apache.cassandra.utils.IndexedSearchIterator;
import static org.apache.cassandra.utils.btree.BTree.size;
public class BTreeSearchIterator<K, V> extends TreeCursor<K> implements IndexedSearchIterator<K, V>, Iterator<V>
{
private final boolean forwards;
private int index;
private byte state;
private final int lowerBound, upperBound;
private static final int MIDDLE = 0;
private static final int ON_ITEM = 1;
private static final int BEFORE_FIRST = 2;
private static final int LAST = 4;
private static final int END = 5;
public BTreeSearchIterator(Object[] btree, Comparator<? super K> comparator, BTree.Dir dir)
{
this(btree, comparator, dir, 0, size(btree)-1);
}
BTreeSearchIterator(Object[] btree, Comparator<? super K> comparator, BTree.Dir dir, int lowerBound, int upperBound)
{
super(comparator, btree);
this.forwards = dir == BTree.Dir.ASC;
this.lowerBound = lowerBound;
this.upperBound = upperBound;
rewind();
}
private int compareToLast(int idx)
{
return forwards ? idx - upperBound : lowerBound - idx;
}
private int compareToFirst(int idx)
{
return forwards ? idx - lowerBound : upperBound - idx;
}
public boolean hasNext()
{
return state != END;
}
public V next()
{
switch (state)
{
case ON_ITEM:
if (compareToLast(index = moveOne(forwards)) >= 0)
state = END;
break;
case BEFORE_FIRST:
seekTo(index = forwards ? lowerBound : upperBound);
state = (byte) (upperBound == lowerBound ? LAST : MIDDLE);
case LAST:
case MIDDLE:
state |= ON_ITEM;
break;
default:
throw new NoSuchElementException();
}
return current();
}
public V next(K target)
{
if (!hasNext())
return null;
int state = this.state;
boolean found = seekTo(target, forwards, (state & (ON_ITEM | BEFORE_FIRST)) != 0);
int index = cur.globalIndex();
V next = null;
if (state == BEFORE_FIRST && compareToFirst(index) < 0)
return null;
int compareToLast = compareToLast(index);
if ((compareToLast <= 0))
{
state = compareToLast < 0 ? MIDDLE : LAST;
if (found)
{
state |= ON_ITEM;
next = (V) currentValue();
}
}
else state = END;
this.state = (byte) state;
this.index = index;
return next;
}
public void rewind()
{
if (upperBound < lowerBound)
{
state = (byte) END;
}
else
{
reset(forwards);
state = (byte) BEFORE_FIRST;
}
}
private void checkOnItem()
{
if ((state & ON_ITEM) != ON_ITEM)
throw new NoSuchElementException();
}
public V current()
{
checkOnItem();
return (V) currentValue();
}
public int indexOfCurrent()
{
checkOnItem();
return compareToFirst(index);
}
}