/*
* Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package org.visage.runtime.sequence;
/**
* Represents a portion of another sequence. Subsequences should be created with the Sequences.subsequence() factory
* method, rather than with the SubSequence constructor. O(1) space and time construction costs.
*
* @author Brian Goetz
* @author Per Bothner
*/
class SubSequence<T> extends AbstractSequence<T> {
protected final Sequence<? extends T> sequence;
protected final int size;
private final int startPos;
private final int step;
/** Create a slice of a sequence.
* Uses a default step-size of 1.
* @param sequence The sequence that we create a subsequence from.
* @param startPos The startPos index. Caller needs to validate that {@code 0 <= startPos <= sequence.size()}.
* @param endPos The end index, exclusive. Caller needs to validate that {@code startPos <= endPos <= sequence.size()}.
*/
public SubSequence(Sequence<T> sequence, int startPos, int endPos) {
this(sequence, endPos-startPos, startPos, 1);
}
private SubSequence(Sequence<T> sequence, int size, int startPos, int step) {
super(sequence.getElementType());
this.startPos = startPos;
this.step = step;
this.sequence = sequence;
this.size = size;
}
/** Create a slice of a sequence.
* Unlike the constructor, this will "collapse" the cases of creating
* a slice from a SubSequence, or when the size is zero.
* WARNING The generalization to step!=1, except as used by the Sequence.reverse
* method, is UNTESTED. That is why this method is PACKAGE-PRIVATE for now.
* @param sequence The sequence that we create a subsequence from.
* @param startPos The startPos index.
* Caller needs to validate that {@code 0 <= startPos <= sequence.size()}.
* @param size Number of elements in the slice.
* Caller needs to validate that this is correct: I.e. {@code size >= 0} and
* and {@code startPos >= 0 && startPos + step*(size-1) < sequence.size()} when {@code step >= 0 && size > 0},
* or {@code startPos < sequence.size() && startPos + step*(size-1) >= 0} when {@code step < 0 && size > 0},
* or {@code 0 <= startPos <= sequence.size()} when {@code size == 0}.
* @param step The step size (stride) between selected elements in the base {@code sequence}.
*
*/
static <T> Sequence make(Sequence<T> sequence, int size, int start, int step) {
if (size <= 0)
return sequence.getElementType().emptySequence;
if (sequence instanceof SubSequence) {
SubSequence sseq = (SubSequence) sequence;
start = sseq.startPos + sseq.step * start;
step = sseq.step * step;
sequence = sseq.sequence;
}
sequence.incrementSharing();
return new SubSequence(sequence, size, start, step);
}
@Override
public T get(int position) {
if (position < 0 || position >= size)
return getDefaultValue();
else
return sequence.get(startPos + step * position);
}
@Override
public boolean getAsBoolean(int position) {
if (position < 0 || position >= size)
return false;
else
return sequence.getAsBoolean(startPos + step * position);
}
@Override
public char getAsChar(int position) {
if (position < 0 || position >= size)
return '\0';
else
return sequence.getAsChar(startPos + step * position);
}
@Override
public byte getAsByte(int position) {
if (position < 0 || position >= size)
return 0;
else
return sequence.getAsByte(startPos + step * position);
}
@Override
public short getAsShort(int position) {
if (position < 0 || position >= size)
return 0;
else
return sequence.getAsShort(startPos + step * position);
}
@Override
public int getAsInt(int position) {
if (position < 0 || position >= size)
return 0;
else
return sequence.getAsInt(startPos + step * position);
}
@Override
public long getAsLong(int position) {
if (position < 0 || position >= size)
return 0;
else
return sequence.getAsLong(startPos + step * position);
}
@Override
public float getAsFloat(int position) {
if (position < 0 || position >= size)
return 0;
else
return sequence.getAsFloat(startPos + step * position);
}
@Override
public double getAsDouble(int position) {
if (position < 0 || position >= size)
return 0;
else
return sequence.getAsDouble(startPos + step * position);
}
public int size() {
return size;
}
@Override
public void toArray(int sourceOffset, int length, Object[] dest, int destOffset) {
if (sourceOffset < 0 || (length > 0 && sourceOffset + length > size()))
throw new ArrayIndexOutOfBoundsException();
if (step == 1)
sequence.toArray(startPos+sourceOffset, length, dest, destOffset);
else {
int j = startPos + step * sourceOffset;
for (int i = 0; i < length; i++, j += step)
dest[i + destOffset] = sequence.get(j);
}
}
}