// This file is part of OpenTSDB.
// Copyright (C) 2010-2012 The OpenTSDB Authors.
//
// 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, either version 2.1 of the License, or (at your
// option) any later version. 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. 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/>.
package net.opentsdb.core;
import java.util.NoSuchElementException;
/** Default iterator for simple implementations of {@link DataPoints}. */
final class DataPointsIterator implements SeekableView, DataPoint {
/** Instance to iterate on. */
private final DataPoints dp;
/** Where are we in the iteration. */
private short index = -1;
/**
* Ctor.
* @param dp The data points to iterate on.
*/
DataPointsIterator(final DataPoints dp) {
this.dp = dp;
}
// ------------------ //
// Iterator interface //
// ------------------ //
public boolean hasNext() {
return index < dp.size() - 1;
}
public DataPoint next() {
if (hasNext()) {
index++;
return this;
}
throw new NoSuchElementException("no more elements in " + this);
}
public void remove() {
throw new UnsupportedOperationException();
}
// ---------------------- //
// SeekableView interface //
// ---------------------- //
public void seek(final long timestamp) {
if ((timestamp & 0xFFFFFFFF00000000L) != 0) { // negative or not 32 bits
throw new IllegalArgumentException("invalid timestamp: " + timestamp);
}
// Do a binary search to find the timestamp given or the one right before.
short lo = 0;
short hi = (short) dp.size();
while (lo <= hi) {
index = (short) ((lo + hi) >>> 1);
long cmp = dp.timestamp(index) - timestamp;
if (cmp < 0) {
lo = (short) (index + 1);
} else if (cmp > 0) {
hi = (short) (index - 1);
} else {
index--; // 'index' is exactly on the timestamp wanted.
return; // So let's go right before that for next().
}
}
// We found the timestamp right before as there was no exact match.
// We take that position - 1 so the next call to next() returns it.
index = (short) (lo - 1);
// If the index we found was not the first or the last point, let's
// do a small extra sanity check to ensure the position we found makes
// sense: the timestamp we're at must not be >= what we're looking for.
if (0 < index && index < dp.size() && dp.timestamp(index) >= timestamp) {
throw new AssertionError("seeked after the time wanted!"
+ " timestamp=" + timestamp
+ ", index=" + index
+ ", dp.timestamp(index)=" + dp.timestamp(index)
+ ", this=" + this);
}
}
/** Package-private helper to find the current index of this iterator. */
int index() {
return index;
}
// ------------------- //
// DataPoint interface //
// ------------------- //
public long timestamp() {
return dp.timestamp(index);
}
public boolean isInteger() {
return dp.isInteger(index);
}
public long longValue() {
return dp.longValue(index);
}
public double doubleValue() {
return dp.doubleValue(index);
}
public double toDouble() {
return isInteger() ? longValue() : doubleValue();
}
public String toString() {
return "DataPointsIterator(index=" + index
+ (index >= 0
? ", current type: " + (isInteger() ? "long" : "float")
+ ", current value=" + (isInteger() ? longValue() : doubleValue())
: " (iteration not started)")
+ ", dp=" + dp + ')';
}
}