/*license*\
XBN-Java: Copyright (C) 2014, Jeff Epstein (aliteralmind __DASH__ github __AT__ yahoo __DOT__ com)
This software is dual-licensed under the:
- Lesser General Public License (LGPL) version 3.0 or, at your option, any later version;
- Apache Software License (ASL) version 2.0.
Either license may be applied at your discretion. More information may be found at
- http://en.wikipedia.org/wiki/Multi-licensing.
The text of both licenses is available in the root directory of this project, under the names "LICENSE_lgpl-3.0.txt" and "LICENSE_asl-2.0.txt". The latest copies may be downloaded at:
- LGPL 3.0: https://www.gnu.org/licenses/lgpl-3.0.txt
- ASL 2.0: http://www.apache.org/licenses/LICENSE-2.0.txt
\*license*/
package com.github.xbn.util.itr;
import com.github.xbn.lang.CrashIfObject;
import com.github.xbn.array.CrashIfIndex;
import java.util.Iterator;
/**
<p>Assists in building iterators over objects of a <i>known quantity</i> of indexable elements, such as arrays and collections--where the start and end indexes can be provided to the constructor, and do not change.</p>
* @since 0.1.0
* @author Copyright (C) 2014, Jeff Epstein ({@code aliteralmind __DASH__ github __AT__ yahoo __DOT__ com}), dual-licensed under the LGPL (version 3.0 or later) or the ASL (version 2.0). See source code for details. <a href="http://xbnjava.aliteralmind.com">{@code http://xbnjava.aliteralmind.com}</a>, <a href="https://github.com/aliteralmind/xbnjava">{@code https://github.com/aliteralmind/xbnjava}</a>
**/
public abstract class UnchangingIndexesIterator<E> extends AbstractIterator<E> implements Iterator<E> {
//state
protected static final String CNTR_NAME = "[the object being iterated...length is getTotalElementCount()]";
private IncDecIndexFunctor incDecFnctr;
private final boolean isLowToHigh;
public UnchangingIndexesIterator() {
this(IteratorDirection.LOW_TO_HIGH);
}
public UnchangingIndexesIterator(IteratorDirection direction) {
try {
isLowToHigh = direction.isLowToHigh();
} catch(RuntimeException rx) {
throw CrashIfObject.nullOrReturnCause(direction, "direction", null, rx);
}
}
public boolean isLowToHigh() {
return isLowToHigh;
}
protected void declareIndexRange(int idx_start, int idx_endX) {
if(idx_endX == -1) {
idx_endX = getTotalElementCount();
}
CrashIfIndex.rangeBadForLength(idx_start, idx_endX, getTotalElementCount(), "idx_start", "idx_endX", CNTR_NAME);
incDecFnctr = (isLowToHigh()
? new IncrementIndex(idx_start, idx_endX)
: new DecrementIndex(idx_start, idx_endX));
}
protected void setIndex(int index) {
incDecFnctr.setIndex(index);
}
public int getIndex() {
return incDecFnctr.getIndex();
}
public final boolean hasNext() {
return incDecFnctr.hasNext();
}
public int getStartIndex() {
return incDecFnctr.startIdx;
}
public int getEndIndexExcl() {
return incDecFnctr.endIdxExcl;
}
protected void moveIndexToNext() {
incDecFnctr.moveIndexToNext();
}
protected void resetIndex() {
incDecFnctr.resetIndex();
}
/**
<p>Must be abstract, because setIndexes optionally uses this.</p>
*/
public abstract int getTotalElementCount();
/*stub functions for implements compile...START
public int getTotalElementCount() {
return -1;
}
stub functions for implements compile...END*/
}
abstract class IncDecIndexFunctor {
public final int startIdx;
public final int endIdxExcl;
protected int currIdx;
public IncDecIndexFunctor(int start_idx, int end_idxX) {
startIdx = start_idx;
endIdxExcl = end_idxX;
}
public int getIndex() {
return currIdx;
}
public void setIndex(int index) {
crashIfBadIndex(index);
currIdx = index;
}
protected abstract void crashIfBadIndex(int index);
public abstract void moveIndexToNext();
public abstract void resetIndex();
public abstract boolean hasNext();
}
class DecrementIndex extends IncDecIndexFunctor {
public DecrementIndex(int start_idx, int end_idxX) {
super(start_idx, end_idxX);
resetIndex();
}
public void moveIndexToNext() {
currIdx--;
}
public void resetIndex() {
currIdx = (endIdxExcl - 1);
}
public boolean hasNext() {
return (getIndex() <= 0);
}
protected void crashIfBadIndex(int index) {
if(index < 0 || index >= getIndex()) {
throw new IllegalArgumentException("index (" + index + ") must be between zero-inclusive and getIndex() (" + getIndex() + ")-exclusive.");
}
}
}
class IncrementIndex extends IncDecIndexFunctor {
public IncrementIndex(int start_idx, int end_idxX) {
super(start_idx, end_idxX);
currIdx = start_idx;
resetIndex();
}
public void moveIndexToNext() {
currIdx++;
}
public void resetIndex() {
currIdx = startIdx;
}
public boolean hasNext() {
return (getIndex() < endIdxExcl);
}
protected void crashIfBadIndex(int index) {
if(index < getIndex() || index >= endIdxExcl) {
throw new IllegalArgumentException("index (" + index + ") must be between getIndex() (" + getIndex() + "), inclusive, and getEndIndexExcl() (" + endIdxExcl + "), exclusive.");
}
}
}