/*
* 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;
import java.util.BitSet;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import org.visage.runtime.TypeInfo;
import org.visage.runtime.Util;
public class ObjectArraySequence<T> extends ArraySequence<T> implements Sequence<T> {
T[] array;
public ObjectArraySequence(int initialSize, TypeInfo<T> ti) {
super(ti);
this.array = Util.<T>newObjectArray(initialSize);
gapStart = 0;
gapEnd = initialSize;
}
public ObjectArraySequence(TypeInfo<T> ti) {
this(DEFAULT_SIZE, ti);
}
public ObjectArraySequence(TypeInfo<T> ti, T... values) {
this(ti, values, false);
}
public ObjectArraySequence(TypeInfo<T> ti, T[] values, boolean handoff) {
super(ti);
if (handoff) {
this.array = values;
}
else {
this.array = Util.<T>newObjectArray(values.length);
System.arraycopy(values, 0, array, 0, values.length);
}
gapStart = gapEnd = values.length;
checkForNulls();
}
public ObjectArraySequence(TypeInfo<T> ti, T[] values, int startPos, int size) {
super(ti);
this.array = Util.<T>newObjectArray(size);
System.arraycopy(values, startPos, array, 0, size);
gapStart = gapEnd = size;
checkForNulls();
}
@SuppressWarnings("unchecked")
public ObjectArraySequence(TypeInfo<T> ti, List<? extends T> values) {
super(ti);
this.array = (T[]) values.toArray();
gapStart = gapEnd = array.length;
checkForNulls();
}
/*public ObjectArraySequence(TypeInfo<T> ti, Sequence<? extends T>... sequences) {
super(ti);
int size = 0;
for (Sequence<? extends T> seq : sequences)
size += seq.size();
this.array = Util.<T>newObjectArray(size);
int next = 0;
for (Sequence<? extends T> seq : sequences) {
final int l = seq.size();
seq.toArray(0, l, array, next);
next += l;
}
gapStart = gapEnd = size;
}*/
public ObjectArraySequence(TypeInfo<T> ti, Sequence<? extends T> seq) {
super(ti);
int size = seq.size();
this.array = Util.<T>newObjectArray(size);
seq.toArray(0, size, array, 0);
gapStart = gapEnd = size;
}
private void checkForNulls() {
int limit = gapStart;
for (int i = 0; ; i++) {
// limit is either gapStart or array.length.
if (i == limit) {
if (limit != gapStart)
break;
i = gapEnd;
limit = array.length;
if (i == limit)
break;
}
if (array[i] == null)
throw new IllegalArgumentException("cannot create sequence with null values");
}
}
protected Object getRawArray() { return array; }
protected Object newRawArray(int size) { return Util.<T>newObjectArray(size); }
protected void setRawArray(Object array) { this.array = (T[]) array; }
protected int getRawArrayLength() { return array.length; }
protected T getRawArrayElementAsObject(int index) { return array[index]; }
protected ObjectArraySequence extractOldValue(int startPos, int endPos) {
int oldSize = array.length - gapEnd + endPos;
ObjectArraySequence<T> copy = new ObjectArraySequence(oldSize, getElementType());
copy.addFromArray(array, 0, startPos);
copy.addFromArray(array, gapEnd-endPos+startPos, array.length);
return copy;
}
@Override
public T get(int position) {
if (position >= gapStart)
position += gapEnd - gapStart;
if (position < 0 || position >= array.length)
return getDefaultValue();
else
return array[position];
}
// optimized versions
@Override
public BitSet getBits(SequencePredicate<? super T> predicate) {
int sz = size();
BitSet bits = new BitSet(sz);
for (int i = 0; i < sz; i++) {
int j = i;
if (j >= gapStart)
j += gapEnd - gapStart;
if (predicate.matches(this, i, array[j]))
bits.set(i);
}
return bits;
}
@Override
public void toArray(int sourceOffset, int length, Object[] dest, int destOffset) {
if (sourceOffset < 0 || length < 0 || sourceOffset + length > size())
throw new ArrayIndexOutOfBoundsException();
int beforeGap = gapStart - sourceOffset;
if (beforeGap >= 0) {
if (length <= beforeGap)
beforeGap = length;
System.arraycopy(array, sourceOffset, dest, destOffset, beforeGap);
length -= beforeGap;
destOffset += beforeGap;
sourceOffset = gapEnd;
}
else
sourceOffset += gapEnd - gapStart;
System.arraycopy(array, sourceOffset, dest, destOffset, length);
}
@Override
public Iterator<T> iterator() {
return new Iterator<T>() {
int index;
public boolean hasNext() {
if (index == gapStart)
index = gapEnd;
return index < array.length;
}
public T next() {
if (hasNext())
return array[index++];
else
throw new NoSuchElementException();
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
/** Add a single element to the sequence, modifying it.
* This must only be called when the sequence is unshared. */
public void add(T element) {
if (element != null) {
gapReserve(size(), 1);
array[gapStart++] = element;
}
}
/** Add the contents of an existing sequence to the sequence.
* This must only be called when the sequence is unshared. */
@Override
public void add(Sequence<? extends T> elements) {
final int length = Sequences.size(elements);
if (length > 0) {
int size = size();
gapReserve(size, length);
elements.toArray(0, length, array, size);
gapStart += length;
}
}
public void add(T[] data, int loIndex, int hiIndex) { // deprecated FIXME
addFromArray(data, loIndex, hiIndex);
/*
int length = hiIndex - loIndex;
int size = size();
gapReserve(size, length);
System.arraycopy(data, loIndex, array, size, length);
gapStart += length;
* */
}
/** Internal method to replace a value. */
public void replace (int position, T value) {
if (position >= gapStart)
position += gapEnd - gapStart;
if (position < 0 || position >= array.length)
return; // Sigh - we really should throw an exception.
array[position] = value;
}
/** Replace a slice of this array.
* @param startPos Starting position of the slice, inclusive, may be 0..size.
* @param endPos Ending position of the slice, exclusive, may be startPos..size.
* @param value The single replement value - must be non-null
*/
public/*FIXME*/ void replace (int startPos, int endPos, T value, boolean hasTrigger) {
if (endPos == startPos+1 && ! hasTrigger) {
replace(startPos, value);
return;
}
int size = size();
int removed = endPos-startPos;
gapReserve(startPos, removed == 0 || hasTrigger? 1 : 0);
gapEnd = startPos + array.length - size + removed;
array[startPos++] = value;
gapStart=startPos;
if (! hasTrigger)
clearOldValues(removed);
}
@Override
protected void replaceRaw(Sequence<? extends T> values, int sourceOffset, int length, int destPos) {
values.toArray(sourceOffset, length, array, destPos);
}
/** Internal method to insert values.
* Does not check shared flag, and does not do any notifications.
*/
protected <T> void insert (Sequence<? extends T> values, int vsize, int where) {
gapReserve(where, vsize);
values.toArray(array, where);
gapStart += vsize;
}
@Override
public void clearOldValues (int oldLength) {
for (int i = gapEnd-oldLength; i < gapEnd; i++)
array[i] = null;
}
}