/*
* 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.*;
import org.visage.runtime.AssignToBoundException;
import org.visage.runtime.TypeInfo;
import org.visage.runtime.Util;
import org.visage.runtime.VisageObject;
import org.visage.runtime.NumericTypeInfo;
/**
* SequencesBase
*
* @author Brian Goetz
*/
public class SequencesBase {
// Must match VisageDefs.UNDEFINED_MARKER_INT
public static final int UNDEFINED_MARKER_INT = -1000;
/*******************************************/
/* Converting between sequences and arrays */
/*******************************************/
/** Convert a T[] to a Sequence<T> */
public static<T> Sequence<T> fromArray(TypeInfo<T> ti, T[] values) {
if (values == null)
return ti.emptySequence;
return new ObjectArraySequence<T>(ti, values);
}
/** Convert a long[] to a Sequence<Long> */
public static Sequence<Long> fromArray(long[] values) {
if (values == null)
return TypeInfo.Long.emptySequence;
return new LongArraySequence(values, 0, values.length);
}
/** Convert an int[] to a Sequence<Integer> */
public static Sequence<Integer> fromArray(int[] values) {
if (values == null)
return TypeInfo.Integer.emptySequence;
return new IntArraySequence(values, 0, values.length);
}
/** Convert a short[] to a Sequence<Short> */
public static Sequence<Short> fromArray(short[] values) {
if (values == null)
return TypeInfo.Short.emptySequence;
return new ShortArraySequence(values, 0, values.length);
}
/** Convert a char[] to a Sequence<Character> */
public static Sequence<Character> fromArray(char[] values) {
if (values == null)
return TypeInfo.Character.emptySequence;
return new CharArraySequence(values, 0, values.length);
}
/** Convert a byte[] to a Sequence<Byte> */
public static Sequence<Byte> fromArray(byte[] values) {
if (values == null)
return TypeInfo.Byte.emptySequence;
return new ByteArraySequence(values, 0, values.length);
}
/** Convert a double[] to a Sequence<Double> */
public static Sequence<Double> fromArray(double[] values) {
if (values == null)
return TypeInfo.Double.emptySequence;
return new DoubleArraySequence(values, 0, values.length);
}
/** Convert a float[] to a Sequence<Float> */
public static Sequence<Float> fromArray(float[] values) {
if (values == null)
return TypeInfo.Float.emptySequence;
return new FloatArraySequence(values, 0, values.length);
}
/** Convert a boolean[] to a Sequence<Boolean> */
public static Sequence<Boolean> fromArray(boolean[] values) {
if (values == null)
return TypeInfo.Boolean.emptySequence;
return new BooleanArraySequence(values, 0, values.length);
}
/** Convert a Sequence<T> to an array */
public static<T> T[] toArray(Sequence<? extends T> seq) {
T[] unboxed = Util.<T>newObjectArray(seq.size());
int i=0;
for (T val : seq) {
unboxed[i++] = val;
}
return unboxed;
}
/** Convert a Sequence<Long> to an array */
public static long[] toLongArray(Sequence<? extends Number> seq) {
int size = seq.size();
long[] unboxed = new long[size];
for (int i = size; --i >= 0; )
unboxed[i] = seq.getAsLong(i);
return unboxed;
}
/** Convert a Sequence<Integer> to an array */
public static int[] toIntArray(Sequence<? extends Number> seq) {
int size = seq.size();
int[] unboxed = new int[size];
for (int i = size; --i >= 0; )
unboxed[i] = seq.getAsInt(i);
return unboxed;
}
/** Convert a Sequence<Short> to an array */
public static short[] toShortArray(Sequence<? extends Number> seq) {
int size = seq.size();
short[] unboxed = new short[size];
for (int i = size; --i >= 0; )
unboxed[i] = seq.getAsShort(i);
return unboxed;
}
/** Convert a Sequence<Byte> to an array */
public static byte[] toByteArray(Sequence<? extends Number> seq) {
int size = seq.size();
byte[] unboxed = new byte[size];
for (int i = size; --i >= 0; )
unboxed[i] = seq.getAsByte(i);
return unboxed;
}
/** Convert a Sequence<Double> to a double array */
public static double[] toDoubleArray(Sequence<? extends Number> seq) {
int size = seq.size();
double[] unboxed = new double[size];
for (int i = size; --i >= 0; )
unboxed[i] = seq.getAsDouble(i);
return unboxed;
}
/** Convert a Sequence<Double> to a float array */
public static float[] toFloatArray(Sequence<? extends Number> seq) {
int size = seq.size();
float[] unboxed = new float[size];
for (int i = size; --i >= 0; )
unboxed[i] = seq.getAsFloat(i);
return unboxed;
}
/** Convert a Sequence<Boolean> to an array */
public static boolean[] toBooleanArray(Sequence<? extends Boolean> seq) {
int size = seq.size();
boolean[] unboxed = new boolean[size];
for (int i = size; --i >= 0; )
unboxed[i] = seq.getAsBoolean(i);
return unboxed;
}
@SuppressWarnings("unchecked")
public static<T> ObjectArraySequence<T> forceNonSharedObjectArraySequence(TypeInfo<T> typeInfo, Sequence<? extends T> value) {
ObjectArraySequence<T> arr;
block: {
if (value instanceof ObjectArraySequence) {
arr = (ObjectArraySequence) value;
if (! arr.isShared()) {
// FIXME: arr.setElementType(typeInfo);
return arr;
}
// Special case - we might as well re-use an empty array.
if (arr.array.length == 0) {
arr = new ObjectArraySequence(typeInfo, arr.array, true);
break block;
}
}
arr = new ObjectArraySequence(typeInfo, value);
}
arr.incrementSharing();
return arr;
}
public static<T> ArraySequence<T> forceNonSharedArraySequence(TypeInfo<T> typeInfo, Sequence<? extends T> value) {
ArraySequence<T> arr;
block: {
if (value instanceof ArraySequence) {
arr = (ArraySequence) value;
if (! arr.isShared()) {
// FIXME: arr.setElementType(typeInfo);
return arr;
}
}
arr = typeInfo.emptySequence.makeNew(0);
arr.add(value);
}
arr.incrementSharing();
return arr;
}
public static<T> T incrementSharing(T value) {
if (value instanceof ArraySequence)
((ArraySequence) value).incrementSharing();
return value;
}
/***************************************************/
/* Methods for constructing sequences from scratch */
/***************************************************/
/** Factory for simple sequence generation */
public static<T> Sequence<T> make(TypeInfo<T> ti, T... values) {
if (values == null || values.length == 0)
return ti.emptySequence;
else
return new ObjectArraySequence<T>(ti, values);
}
/** Factory for simple sequence generation */
public static<T> Sequence<T> make(TypeInfo<T> ti, T[] values, int size) {
if (values == null || size <= 0)
return ti.emptySequence;
else
return new ObjectArraySequence<T>(ti, values, 0, size);
}
public static<T> Sequence<T> makeViaHandoff(TypeInfo<T> ti, T[] values) {
return new ObjectArraySequence<T>(ti, values, true);
}
/** Factory for simple sequence generation */
public static<T> Sequence<T> make(TypeInfo<T> ti, List<? extends T> values) {
if (values == null || values.size() == 0)
return ti.emptySequence;
else
return new ObjectArraySequence<T>(ti, values);
}
/** Create an Integer range sequence ranging from lower to upper inclusive. */
public static Sequence<Integer> range(int lower, int upper) {
return new IntRangeSequence(lower, upper);
}
/** Create an Integer range sequence ranging from lower to upper inclusive, incrementing by the specified step. */
public static Sequence<Integer> range(int lower, int upper, int step) {
return new IntRangeSequence(lower, upper, step);
}
/** Create an Integer range sequence ranging from lower to upper exclusive. */
public static Sequence<Integer> rangeExclusive(int lower, int upper) {
return new IntRangeSequence(lower, upper, true);
}
/** Create an Integer range sequence ranging from lower to upper exnclusive, incrementing by the specified step. */
public static Sequence<Integer> rangeExclusive(int lower, int upper, int step) {
return new IntRangeSequence(lower, upper, step, true);
}
/** Create a double range sequence ranging from lower to upper inclusive, incrementing by 1.0 */
public static Sequence<Float> range(float lower, float upper) {
return new NumberRangeSequence(lower, upper, 1.0f);
}
/** Create a double range sequence ranging from lower to upper inclusive, incrementing by the specified step. */
public static Sequence<Float> range(float lower, float upper, float step) {
return new NumberRangeSequence(lower, upper, step);
}
/** Create a double range sequence ranging from lower to upper exnclusive */
public static Sequence<Float> rangeExclusive(float lower, float upper) {
return new NumberRangeSequence(lower, upper, 1.0f, true);
}
/** Create a double range sequence ranging from lower to upper exnclusive, incrementing by the specified step. */
public static Sequence<Float> rangeExclusive(float lower, float upper, float step) {
return new NumberRangeSequence(lower, upper, step, true);
}
/** Create a filtered sequence. A filtered sequence contains some, but not necessarily all, of the elements
* of another sequence, in the same order as that sequence. If bit n is set in the BitSet, then the element
* at position n of the original sequence appears in the filtered sequence. */
public static<T> Sequence<T> filter(Sequence<T> seq, BitSet bits) {
int cardinality = bits.cardinality();
if (cardinality == 0)
return seq.getEmptySequence();
else if (cardinality == seq.size() && bits.nextClearBit(0) == seq.size())
return seq;
else {
ObjectArraySequence<T> result = new ObjectArraySequence(cardinality, seq.getElementType());
for (int i = bits.nextSetBit(0), next = 0; i >= 0; i = bits.nextSetBit(i + 1))
result.add(seq.get(i));
return result;
}
}
/** Extract a subsequence from the specified sequence, starting as the specified start position, and up to but
* not including the specified end position. If the start position is negative it is assumed to be zero; if the
* end position is greater than seq.size() it is assumed to be seq.size(). */
public static<T> Sequence<T> subsequence(Sequence<T> seq, int start, int end) {
// OPT: for small sequences, just copy the elements
if (start >= end)
return seq.getEmptySequence();
else if (start <= 0 && end >= seq.size())
return seq;
else {
start = Math.max(start, 0);
end = Math.min(end, seq.size());
return SubSequence.make(seq, end-start, start, 1);
}
}
public static int calculateIntRangeSize(int lower, int upper, int step, boolean exclusive) {
if (step == 0) {
// Undo VSGC-3735 - because of forward reference binds, zero happens frequently.
return 0;
}
if (Math.abs((long) lower - (long) upper) + ((long) (exclusive ? 0 : 1)) > Integer.MAX_VALUE)
throw new IllegalArgumentException("Range sequence too big");
if (upper == lower) {
return exclusive ? 0 : 1;
}
else {
int size = Math.max(0, ((upper - lower) / step) + 1);
if (exclusive) {
boolean tooBig = (step > 0)
? (lower + (size-1)*step >= upper)
: (lower + (size-1)*step <= upper);
if (tooBig && size > 0)
--size;
}
return (int) size;
}
}
public static int calculateFloatRangeSize(float lower, float upper, float step, boolean exclusive) {
if (step == 0.0f) {
// Undo VSGC-3735 - because of forward reference binds, zero happens frequently.
return 0;
}
if (upper == lower) {
return exclusive ? 0 : 1;
} else {
long sz = ((upper < lower && step > 0.0f) ||
(upper > lower && step < 0.0f)) ? 0
: Math.max(0, (((long) ((upper - lower) / step)) + 1));
if (exclusive) {
boolean tooBig = (step > 0.0f)
? (lower + (sz - 1) * step >= upper)
: (lower + (sz - 1) * step <= upper);
if (tooBig && sz > 0) {
--sz;
}
}
if (sz > Integer.MAX_VALUE || sz < 0) {
throw new IllegalArgumentException("Range sequence too big");
} else {
return (int) sz;
}
}
}
/* NOTE Possible future functionality, to allow a step in a slice expression.
* This is a sketch, which needs some tweaking to handle corner cases,
* plus some compiler work.
* NOTE The generalization to step!=1, except as used by the reverse
* function, is UNTESTED.
public static<T> Sequence<T> subsequence(Sequence<T> seq, int start, int bound, int step, boolean exclusive) {
// FIXME canonicalize start (if out of range)
int size = calculateSize(start, bound, step, exclusive);
return SubSequence.make(seq, start, size, step);
}
*/
/** Create a sequence containing a single element, the specified value */
public static<T> Sequence<T> singleton(TypeInfo<T> ti, T t) {
if (t == null)
return ti.emptySequence;
else
return new SingletonSequence<T>(ti, t);
}
/** Create an empty sequence */
public static<T> Sequence<T> emptySequence(Class<T> clazz) {
return TypeInfo.getTypeInfo(clazz).emptySequence;
}
/** Reverse an existing sequence */
public static<T> Sequence<T> reverse(Sequence<T> sequence) {
int ssize = sequence.size();
return SubSequence.make(sequence, ssize, ssize-1, -1);
}
/** Convert a Collection<T> to a Sequence<T> */
@SuppressWarnings("unchecked")
public static<T> Sequence<T> fromCollection(TypeInfo<T> ti, Collection<T> values) {
if (values == null)
return ti.emptySequence;
// OPT: Use handoff, pre-size array
return new ObjectArraySequence<T>(ti, (T[]) values.toArray());
}
/**********************************************/
/* Utility methods for dealing with sequences */
/**********************************************/
/** Upcast a sequence of T to a sequence of superclass-of-T */
@SuppressWarnings("unchecked")
public static<T> Sequence<T> upcast(Sequence<? extends T> sequence) {
return (Sequence<T>) sequence;
}
/** Convert any numeric sequence to any other numeric sequence */
@SuppressWarnings("unchecked")
public static Sequence<? extends Object> convertObjectToSequence(Object obj) {
if (obj instanceof Sequence) {
return (Sequence<? extends Object>)obj;
}
else
return singleton(TypeInfo.Object, obj);
}
/** Convert any numeric sequence to any other numeric sequence */
public static<T extends Number, V extends Number>
Sequence<T> convertNumberSequence(NumericTypeInfo<T> toType, NumericTypeInfo<V> fromType, Sequence<? extends V> seq) {
if (Sequences.size(seq) == 0)
return toType.emptySequence;
int length = seq.size();
T[] toArray = toType.makeArray(length);
int i=0;
for (V val : seq) {
toArray[i++] = toType.asPreferred(fromType, val);
}
return new ObjectArraySequence<T>(toType, toArray, 0, length);
}
/** Convert any numeric sequence to a char sequence */
public static<V extends Number>
Sequence<Character> convertNumberToCharSequence(NumericTypeInfo<V> fromType, Sequence<? extends V> seq) {
if (Sequences.size(seq) == 0)
return TypeInfo.Character.emptySequence;
int length = seq.size();
Character[] toArray = new Character[length];
int i=0;
for (V val : seq) {
toArray[i++] = (char)val.intValue();
}
return new ObjectArraySequence<Character>(TypeInfo.Character, toArray, 0, length);
}
/** Convert a char sequence to any numeric sequence */
public static<V extends Number>
Sequence<V> convertCharToNumberSequence(NumericTypeInfo<V> targetType, Sequence<? extends Character> seq) {
if (Sequences.size(seq) == 0)
return targetType.emptySequence;
int length = seq.size();
V[] toArray = targetType.makeArray(length);
int i=0;
for (Character val : seq) {
toArray[i++] = targetType.asPreferred(TypeInfo.Integer, (int)val.charValue());
}
return new ObjectArraySequence<V>(targetType, toArray, 0, length);
}
/** How large is this sequence? Can be applied to any object. */
public static int size(Object seq) {
if (seq instanceof Sequence)
return ((Sequence) seq).size();
else
return seq == null ? 0 : 1;
}
/** How large is this sequence? */
public static int size(Sequence seq) {
return (seq == null) ? 0 : seq.size();
}
@SuppressWarnings("unchecked")
public static<T> Iterator<T> iterator(Sequence<T> seq) {
return (seq == null)? (Iterator<T>) TypeInfo.Object.emptySequence.iterator() : seq.iterator();
}
@SuppressWarnings("unchecked")
public static<T> Iterator<T> iterator(Sequence<T> seq, int startPos, int endPos) {
return (seq == null)? (Iterator<T>) TypeInfo.Object.emptySequence.iterator() : seq.iterator(startPos, endPos);
}
public static<T> boolean isEqual(Sequence<?> one, Sequence<?> other) {
int oneSize = size(one);
int otherSize = size(other);
if (oneSize == 0)
return (otherSize == 0);
else if (oneSize != otherSize)
return false;
else {
Iterator<?> it1 = one.iterator();
Iterator<?> it2 = other.iterator();
while (it1.hasNext()) {
if (! it1.next().equals(it2.next()))
return false;
}
return true;
}
}
public static<T> boolean isEqualByContentIdentity(Sequence<? extends T> one, Sequence<? extends T> other) {
int oneSize = size(one);
if (oneSize == 0)
return size(other) == 0;
else if (oneSize != size(other))
return false;
else {
Iterator<? extends T> it1 = one.iterator();
Iterator<? extends T> it2 = other.iterator();
while (it1.hasNext()) {
if (it1.next() != it2.next())
return false;
}
return true;
}
}
public static<T> boolean sliceEqual(Sequence<? extends T> seq, int startPos, int endPos/*exclusive*/, Sequence<? extends T> slice) {
int size = size(slice);
if (endPos - startPos != size)
return false;
/* For most (but not all) Sequences types, indexing is faster.
Iterator<? extends T> seqIterator = iterator(seq, startPos, endPos-1);
for (Iterator<? extends T> sliceIterator = iterator(slice); sliceIterator.hasNext(); ) {
if (!seqIterator.next().equals(sliceIterator.next())) {
return false;
}
}
*/
for (int i = 0; i < size; i++) {
if (!seq.get(startPos+i).equals(slice.get(i)))
return false;
}
return true;
}
public static<T> Sequence<? extends T> forceNonNull(TypeInfo<T> typeInfo, Sequence<? extends T> seq) {
return seq == null ? typeInfo.emptySequence : seq;
}
/**
* Return the single value of a sequence.
* Return null if the sequence zero zero or more than 1 elements.
* Thid is used to implement 'seq instanceof T'.
*/
public static <T> T getSingleValue (Sequence<T> seq) {
if (seq == null || seq.size() != 1)
return null;
return seq.get(0);
}
/*************************/
/* Sorting and searching */
/*************************/
/**
* Searches the specified sequence for the specified object using the
* binary search algorithm. The sequence must be sorted into ascending
* order according to the natural ordering of its elements (as by
* the sort(Sequence<T>) method) prior to making this call.
*
* If it is not sorted, the results are undefined. If the array contains
* multiple elements equal to the specified object, there is no guarantee
* which one will be found.
*
* @param seq The sequence to be searched.
* @param key The value to be searched for.
* @return Index of the search key, if it is contained in the array;
* otherwise, (-(insertion point) - 1). The insertion point is
* defined as the point at which the key would be inserted into the
* array: the index of the first element greater than the key, or
* a.length if all elements in the array are less than the specified
* key. Note that this guarantees that the return value will be >= 0
* if and only if the key is found.
*/
public static <T extends Comparable> int binarySearch (Sequence<? extends T> seq, T key) {
if (seq.isEmpty())
return -1;
final int length = seq.size();
T[] array = Util.<T>newComparableArray(length);
seq.toArray(0, length, array, 0);
return Arrays.binarySearch(array, key);
}
/**
* Searches the specified array for the specified object using the
* binary search algorithm. The array must be sorted into ascending
* order according to the specified comparator (as by the
* sort(Sequence<T>, Comparator<? super T>) method) prior to making
* this call.
*
* If it is not sorted, the results are undefined. If the array contains
* multiple elements equal to the specified object, there is no guarantee
* which one will be found.
*
* @param seq The sequence to be searched.
* @param key The value to be searched for.
* @param c The comparator by which the array is ordered. A null value
* indicates that the elements' natural ordering should be used.
* @return Index of the search key, if it is contained in the array;
* otherwise, (-(insertion point) - 1). The insertion point is
* defined as the point at which the key would be inserted into the
* array: the index of the first element greater than the key, or
* a.length if all elements in the array are less than the specified
* key. Note that this guarantees that the return value will be >= 0
* if and only if the key is found.
*/
public static <T> int binarySearch(Sequence<? extends T> seq, T key, Comparator<? super T> c) {
if (seq.isEmpty())
return -1;
final int length = seq.size();
T[] array = Util.<T>newObjectArray(length);
seq.toArray(0, length, array, 0);
return Arrays.binarySearch(array, (T)key, c);
}
/**
* Searches the specified sequence for the specified object.
*
* If the sequence contains multiple elements equal to the specified object,
* the first occurence in the sequence will be returned.
*
* The method nextIndexOf can be used in consecutive calls to iterate
* through all occurences of a specified object.
*
* @param seq The sequence to be searched.
* @param key The value to be searched for.
* @return Index of the search key, if it is contained in the array;
* otherwise -1.
*/
public static<T> int indexByIdentity(Sequence<? extends T> seq, T key) {
return nextIndexByIdentity(seq, key, 0);
}
/**
* Searches the specified sequence for an object with the same value. The
* objects are compared using the method equals(). If the sequence is sorted,
* binarySearch should be used instead.
*
* If the sequence contains multiple elements equal to the specified object,
* the first occurence in the sequence will be returned.
*
* The method nextIndexOf can be used in consecutive calls to iterate
* through all occurences of a specified object.
*
* @param seq The sequence to be searched.
* @param key The value to be searched for.
* @return Index of the search key, if it is contained in the array;
* otherwise -1.
*/
public static<T> int indexOf(Sequence<? extends T> seq, T key) {
return nextIndexOf(seq, key, 0);
}
/**
* Returns the element with the maximum value in the specified sequence,
* according to the natural ordering of its elements. All elements in the
* sequence must implement the Comparable interface. Furthermore, all
* elements in the sequence must be mutually comparable (that is,
* e1.compareTo(e2) must not throw a ClassCastException for any elements
* e1 and e2 in the sequence).
*
* If the sequence contains multiple elements with the maximum value,
* there is no guarantee which one will be found.
*
* @param seq The sequence to be searched.
* @return The element with the maximum value.
*/
@SuppressWarnings("unchecked")
public static <T extends Comparable> T max (Sequence<T> seq) {
if (seq == null || seq.isEmpty())
throw new IllegalArgumentException("empty sequence passed to Sequences.max");
T result = seq.get(0);
for (T val : seq) {
if (result.compareTo(val) < 0) {
result = val;
}
}
return result;
}
/**
* Returns the element with the maximum value in the specified sequence,
* according to the specified comparator. All elements in the sequence must
* be mutually comparable by the specified comparator (that is,
* c.compare(e1, e2) must not throw a ClassCastException for any elements
* e1 and e2 in the sequence).
*
* If the sequence contains multiple elements with the maximum value,
* there is no guarantee which one will be found.
*
* @param seq The sequence to be searched.
* @param c The comparator to determine the order of the sequence.
* A null value indicates that the elements' natural ordering
* should be used.
* @return The element with the maximum value.
*/
@SuppressWarnings("unchecked")
public static <T> T max (Sequence<T> seq, Comparator<? super T> c) {
if (seq == null || seq.isEmpty())
throw new IllegalArgumentException("empty sequence passed to Sequences.max");
if (c == null)
return (T)max((Sequence<Comparable>)seq);
T result = seq.get(0);
for (T val : seq) {
if (c.compare(result, val) < 0) {
result = val;
}
}
return result;
}
/**
* Returns the element with the minimum value in the specified sequence,
* according to the natural ordering of its elements. All elements in the
* sequence must implement the Comparable interface. Furthermore, all
* elements in the sequence must be mutually comparable (that is,
* e1.compareTo(e2) must not throw a ClassCastException for any elements
* e1 and e2 in the sequence).
*
* If the sequence contains multiple elements with the minimum value,
* there is no guarantee which one will be found.
*
* @param seq The sequence to be searched.
* @return The element with the maximum value.
*/
@SuppressWarnings("unchecked")
public static <T extends Comparable> T min (Sequence<T> seq) {
if (seq == null || seq.isEmpty())
throw new IllegalArgumentException("empty sequence passed to Sequences.min");
T result = seq.get(0);
for (T val : seq) {
if (result.compareTo(val) > 0) {
result = val;
}
}
return result;
}
/**
* Returns the element with the minimum value in the specified sequence,
* according to the specified comparator. All elements in the sequence must
* be mutually comparable by the specified comparator (that is,
* c.compare(e1, e2) must not throw a ClassCastException for any elements
* e1 and e2 in the sequence).
*
* If the sequence contains multiple elements with the minimum value,
* there is no guarantee which one will be found.
*
* @param seq The sequence to be searched.
* @param c The comparator to determine the order of the sequence.
* A null value indicates that the elements' natural ordering
* should be used.
* @return The element with the minimum value.
*/
@SuppressWarnings("unchecked")
public static <T> T min (Sequence<T> seq, Comparator<? super T> c) {
if (seq == null || seq.isEmpty())
throw new IllegalArgumentException("empty sequence passed to Sequences.min");
if (c == null)
return (T)min((Sequence<Comparable>)seq);
T result = seq.get(0);
for (T val : seq) {
if (c.compare(result, val) > 0)
result = val;
}
return result;
}
/**
* Searches the specified sequence for an object with the same value,
* starting the search at the specified position. The objects are compared
* using the method equals().
*
* If the sequence contains multiple elements equal to the specified object,
* the first occurence in the subsequence will be returned.
*
* @param seq The sequence to be searched.
* @param key The value to be searched for.
* @param pos The position in the sequence to start the search. If pos is
* negative or 0 the whole sequence will be searched.
* @return Index of the search key, if it is contained in the array;
* otherwise -1.
*/
public static<T> int nextIndexByIdentity(Sequence<? extends T> seq, T key, int pos) {
if (seq == null)
return -1;
if (key == null)
throw new NullPointerException();
Iterator<? extends T> it = seq.iterator();
int i;
for (i=0; i<pos && it.hasNext(); ++i)
it.next();
for (; it.hasNext(); ++i)
if (it.next() == key)
return i;
return -1;
}
/**
* Searches the specified sequence for the specified object, starting the
* search at the specified position.
*
* If the sequence contains multiple elements equal to the specified object,
* the first occurence in the subsequence will be returned.
*
* @param seq The sequence to be searched.
* @param key The value to be searched for.
* @param pos The position in the sequence to start the search. If pos is
* negative or 0 the whole sequence will be searched.
* @return Index of the search key, if it is contained in the array;
* otherwise -1.
*/
public static<T> int nextIndexOf(Sequence<? extends T> seq, T key, int pos) {
if (seq == null)
return -1;
if (key == null)
throw new NullPointerException();
Iterator<? extends T> it = seq.iterator();
int i;
for (i=0; i<pos && it.hasNext(); ++i)
it.next();
for (; it.hasNext(); ++i)
if (it.next().equals(key))
return i;
return -1;
}
/**
* Sorts the specified sequence of objects into ascending order, according
* to the natural ordering of its elements. All elements in the sequence
* must implement the Comparable interface. Furthermore, all elements in
* the sequence must be mutually comparable (that is, e1.compareTo(e2)
* must not throw a ClassCastException for any elements e1 and e2 in the
* sequence).
*
* This method is immutative, the result is returned in a new sequence,
* while the original sequence is left untouched.
*
* This sort is guaranteed to be stable: equal elements will not be
* reordered as a result of the sort.
*
* The sorting algorithm is a modified mergesort (in which the merge is
* omitted if the highest element in the low sublist is less than the
* lowest element in the high sublist). This algorithm offers guaranteed
* n*log(n) performance.
*
* @param seq The sequence to be sorted.
* @return The sorted sequence.
*/
public static <T extends Comparable> Sequence<? extends T> sort (Sequence<T> seq) {
if (seq.isEmpty())
return seq.getEmptySequence();
final int length = seq.size();
T[] array = Util.<T>newComparableArray(length);
seq.toArray(0, length, array, 0);
Arrays.sort(array);
return Sequences.<T>make(seq.getElementType(), array);
}
/**
* Sorts the specified sequence of objects according to the order induced
* by the specified comparator. All elements in the sequence must be
* mutually comparable by the specified comparator (that is,
* c.compare(e1, e2) must not throw a ClassCastException for any elements
* e1 and e2 in the sequence).
*
* This method is immutative, the result is returned in a new sequence,
* while the original sequence is left untouched.
*
* This sort is guaranteed to be stable: equal elements will not be
* reordered as a result of the sort.
*
* The sorting algorithm is a modified mergesort (in which the merge is
* omitted if the highest element in the low sublist is less than the
* lowest element in the high sublist). This algorithm offers guaranteed
* n*log(n) performance.
*
* @param seq The sequence to be sorted.
* @param c The comparator to determine the order of the sequence.
* A null value indicates that the elements' natural ordering
* should be used.
* @return The sorted sequence.
*/
public static <T> Sequence<? extends T> sort (Sequence<T> seq, Comparator<? super T> c) {
if (seq.isEmpty())
return seq.getEmptySequence();
final int length = seq.size();
T[] array = Util.<T>newObjectArray(length);
seq.toArray(0, length, array, 0);
Arrays.sort(array, c);
return Sequences.<T>make(seq.getElementType(), array);
}
/** Returns a new sequence containing the randomly shuffled
* contents of the existing sequence
* */
public static <T> Sequence<T> shuffle (Sequence<T> seq) {
T[] array = toArray(seq);
List<? extends T> list = Arrays.asList(array);
Collections.shuffle(list);
return Sequences.make(seq.getElementType(), list);
}
public static <T> T getFromNewElements(VisageObject instance, int varNum, int loIndex, int inserted, int k) {
if (k >= inserted)
k = -1;
else if (k >= 0)
k += loIndex;
return (T) instance.elem$(varNum, k);
}
public static <T> Sequence<? extends T> getNewElements(Sequence<? extends T> current, int startPos, int inserted) {
return Sequences.subsequence(current, startPos, startPos+inserted);
}
public static <T> Sequence<? extends T> replaceSlice(Sequence<? extends T> oldValue, T newValue, int startPos, int endPos/*exclusive*/) {
if (preReplaceSlice(oldValue, newValue, startPos, endPos)) {
return replaceSliceInternal(oldValue, newValue, startPos, endPos, false);
}
else
return oldValue;
}
//where
private static <T> boolean preReplaceSlice(Sequence<? extends T> oldValue, T newValue, int startPos, int endPos/*exclusive*/) {
if (newValue == null)
return preReplaceSlice(oldValue, (Sequence<? extends T>) null, startPos, endPos);
int oldSize = oldValue.size();
if (startPos < 0)
startPos = 0;
else if (startPos > oldSize)
startPos = oldSize;
if (endPos > oldSize)
endPos = oldSize;
else if (endPos < startPos)
endPos = startPos;
if (endPos == startPos+1 && newValue.equals(oldValue.get(startPos))) {
// FIXME set valid??
return false;
}
else {
return true;
}
}
//where
private static <T> Sequence<? extends T> replaceSliceInternal(Sequence<? extends T> oldValue, T newValue, int startPos, int endPos/*exclusive*/, boolean hasTrigger) {
if (newValue == null)
return replaceSliceInternal(oldValue, (Sequence<? extends T>) null, startPos, endPos, hasTrigger);
int oldSize = oldValue.size();
if (startPos < 0)
startPos = 0;
else if (startPos > oldSize)
startPos = oldSize;
if (endPos > oldSize)
endPos = oldSize;
else if (endPos < startPos)
endPos = startPos;
ObjectArraySequence<T> arr = forceNonSharedObjectArraySequence((TypeInfo<T>) oldValue.getElementType(), oldValue);
arr.replace(startPos, endPos, (T) newValue, hasTrigger);
if (hasTrigger)
arr.clearOldValues(endPos-startPos);
return arr;
}
public static <T> void replaceSlice(VisageObject instance, int varNum, T newValue, int startPos, int endPos/*exclusive*/) {
boolean wasUninitialized =
instance.varTestBits$(varNum, VisageObject.VFLGS$INITIALIZED_STATE_BIT, 0);
instance.varChangeBits$(varNum, VisageObject.VFLGS$INIT$MASK, VisageObject.VFLGS$INIT$INITIALIZED_DEFAULT);
if (instance.varTestBits$(varNum, VisageObject.VFLGS$IS_BOUND_READONLY, VisageObject.VFLGS$IS_BOUND_READONLY)) {
throw new AssignToBoundException("Cannot mutate bound sequence");
}
Sequence<? extends T> oldValue = (Sequence<? extends T>) instance.get$(varNum);
while (oldValue instanceof SequenceProxy) {
SequenceProxy sp = (SequenceProxy) oldValue;
instance = sp.instance();
varNum = sp.varNum();
instance.varChangeBits$(varNum, VisageObject.VFLGS$INIT$MASK, VisageObject.VFLGS$INIT$INITIALIZED_DEFAULT);
oldValue = (Sequence<? extends T>) instance.get$(varNum);
}
if (preReplaceSlice(oldValue, newValue, startPos, endPos) ||
wasUninitialized) {
int newLength = newValue==null?0:1;
instance.invalidate$(varNum, startPos, endPos, newLength, VisageObject.PHASE_TRANS$CASCADE_INVALIDATE);
Sequence<? extends T> arr = replaceSliceInternal(oldValue, newValue, startPos, endPos, true);
instance.seq$(varNum, arr);
instance.invalidate$(varNum, startPos, endPos, newLength, VisageObject.PHASE_TRANS$CASCADE_TRIGGER);
}
}
public static <T> Sequence<? extends T> replaceSlice(Sequence<? extends T> oldValue, Sequence<? extends T> newValues, int startPos, int endPos/*exclusive*/) {
int oldSize = oldValue.size();
if (startPos < 0)
startPos = 0;
else if (startPos > oldSize)
startPos = oldSize;
if (endPos > oldSize)
endPos = oldSize;
else if (endPos < startPos)
endPos = startPos;
/*
// Calling sliceEqual is probably not worth it,
// at least if oldValue is non-shared, and we can just copy.
// sliceEqual is especially bad if it needs to do boxing.
if (newValues == null ? startPos == endPos
: sliceEqual(oldValue, startPos, endPos, newValues)) {
// FIXME set valid??
return oldValue;
}
*/
int inserted = newValues==null? 0 : newValues.size();
// If we are replacing it all, and, since we don't want copies of SequenceRef, if it isn't a SequenceRef
if (startPos == 0 && endPos == oldSize && !(newValues instanceof SequenceRef) && !(newValues instanceof SequenceProxy)) {
if (newValues == null)
newValues = oldValue.getEmptySequence();
newValues.incrementSharing();
return newValues;
}
ArraySequence<T> arr = forceNonSharedArraySequence((TypeInfo<T>) oldValue.getElementType(), oldValue);
arr.replace(startPos, endPos, newValues, 0, inserted, false);
return arr;
}
//where
private static <T> boolean preReplaceSlice(Sequence<? extends T> oldValue, Sequence<? extends T> newValues, int startPos, int endPos/*exclusive*/) {
int oldSize = oldValue.size();
if (startPos < 0)
startPos = 0;
else if (startPos > oldSize)
startPos = oldSize;
if (endPos > oldSize)
endPos = oldSize;
else if (endPos < startPos)
endPos = startPos;
if (newValues == null ? startPos == endPos
: sliceEqual(oldValue, startPos, endPos, newValues)) {
// FIXME set valid??
return false;
}
else {
return true;
}
}
//where
private static <T> Sequence<? extends T> replaceSliceInternal(Sequence<? extends T> oldValue, Sequence<? extends T> newValues, int startPos, int endPos/*exclusive*/, boolean hasTrigger) {
int oldSize = oldValue.size();
if (startPos < 0)
startPos = 0;
else if (startPos > oldSize)
startPos = oldSize;
if (endPos > oldSize)
endPos = oldSize;
else if (endPos < startPos)
endPos = startPos;
int inserted = newValues==null? 0 : newValues.size();
// If we are replacing it all, and, since we don't want copies of SequenceRef, if it isn't a SequenceRef
if (startPos == 0 && endPos == oldSize && !(newValues instanceof SequenceRef) && !(newValues instanceof SequenceProxy)) {
if (newValues == null)
newValues = oldValue.getEmptySequence();
newValues.incrementSharing();
return newValues;
}
ArraySequence<T> arr = forceNonSharedArraySequence((TypeInfo<T>) oldValue.getElementType(), oldValue);
arr.replace(startPos, endPos, newValues, 0, inserted, hasTrigger);
if (hasTrigger)
arr.clearOldValues(endPos-startPos);
return arr;
}
public static <T> void replaceSlice(VisageObject instance, int varNum, Sequence<? extends T> newValues, int startPos, int endPos/*exclusive*/) {
boolean wasUninitialized =
instance.varTestBits$(varNum, VisageObject.VFLGS$INITIALIZED_STATE_BIT, 0);
instance.varChangeBits$(varNum, VisageObject.VFLGS$INIT$MASK, VisageObject.VFLGS$INIT$INITIALIZED_DEFAULT);
if (instance.varTestBits$(varNum, VisageObject.VFLGS$IS_BOUND_READONLY, VisageObject.VFLGS$IS_BOUND_READONLY)) {
throw new AssignToBoundException("Cannot mutate bound sequence");
}
Sequence<? extends T> oldValue = (Sequence<? extends T>) instance.get$(varNum);
while (oldValue instanceof SequenceProxy) {
SequenceProxy sp = (SequenceProxy) oldValue;
instance = sp.instance();
varNum = sp.varNum();
instance.varChangeBits$(varNum, VisageObject.VFLGS$INIT$MASK, VisageObject.VFLGS$INIT$INITIALIZED_DEFAULT);
oldValue = (Sequence<? extends T>) instance.get$(varNum);
}
if (preReplaceSlice(oldValue, newValues, startPos, endPos) ||
wasUninitialized) {
int newLength = newValues == null ? 0 : newValues.size();
instance.invalidate$(varNum, startPos, endPos, newLength, VisageObject.PHASE_TRANS$CASCADE_INVALIDATE);
Sequence<? extends T> arr = replaceSliceInternal(oldValue, newValues, startPos, endPos, true);
instance.seq$(varNum, arr);
instance.invalidate$(varNum, startPos, endPos, newLength, VisageObject.PHASE_TRANS$CASCADE_TRIGGER);
}
}
public static <T> Sequence<? extends T> set(Sequence<? extends T> oldValue, Sequence<? extends T> newValue) {
if (newValue instanceof SequenceRef || newValue instanceof SequenceProxy) {
// Can't have any copies of a SequenceRef
return replaceSlice(oldValue, newValue, 0, oldValue.size());
}
newValue.incrementSharing();
return newValue;
}
public static <T> Sequence<? extends T> set(VisageObject instance, int varNum, Sequence<? extends T> newValue) {
//TODO: should give slice invalidations, as if below, but should actually set to the new sequence
replaceSlice(instance, varNum, newValue, 0, instance.size$(varNum));
return newValue;
}
public static <T> Sequence<? extends T> set(Sequence<? extends T> oldValue, T newValue, int index) {
return replaceSlice(oldValue, newValue, index, index + 1);
}
public static <T> T set(VisageObject instance, int varNum, T newValue, int index) {
replaceSlice(instance, varNum, newValue, index, index + 1);
return newValue;
}
public static <T> ArraySequence<? extends T> copy(Sequence<? extends T> oldValue) {
ArraySequence<T> arr = ((TypeInfo<T>) oldValue.getElementType()).emptySequence.makeNew(0);
arr.add(oldValue);
arr.incrementSharing();
return arr;
}
public static <T> Sequence<? extends T> insert(Sequence<? extends T> oldValue, T newValue) {
if (newValue == null)
return oldValue;
int oldSize = oldValue.size();
ObjectArraySequence<T> arr = forceNonSharedObjectArraySequence((TypeInfo<T>) oldValue.getElementType(), oldValue);
arr.replace(oldSize, oldSize, (T) newValue, true);
return arr;
}
public static <T> void insert(VisageObject instance, int varNum, T newValue) {
if (newValue == null)
return;
instance.varChangeBits$(varNum, VisageObject.VFLGS$INIT$MASK, VisageObject.VFLGS$INIT$INITIALIZED_DEFAULT);
Sequence<? extends T> oldValue = (Sequence<? extends T>) instance.get$(varNum);
while (oldValue instanceof SequenceProxy) {
SequenceProxy sp = (SequenceProxy) oldValue;
instance = sp.instance();
varNum = sp.varNum();
instance.varChangeBits$(varNum, VisageObject.VFLGS$INIT$MASK, VisageObject.VFLGS$INIT$INITIALIZED_DEFAULT);
oldValue = (Sequence<? extends T>) instance.get$(varNum);
}
int oldSize = oldValue.size();
int newLength = newValue==null?0:1;
Sequence<? extends T> arr = insert(oldValue, newValue);
instance.invalidate$(varNum, oldSize, oldSize, newLength, VisageObject.PHASE_TRANS$CASCADE_INVALIDATE);
instance.seq$(varNum, arr);
instance.invalidate$(varNum, oldSize, oldSize, newLength, VisageObject.PHASE_TRANS$CASCADE_TRIGGER);
}
public static <T> Sequence<? extends T> insert(Sequence<? extends T> oldValue, Sequence<? extends T> values) {
int inserted = values.size();
if (inserted == 0)
return oldValue;
int oldSize = oldValue.size();
ArraySequence<T> arr = forceNonSharedArraySequence((TypeInfo<T>) oldValue.getElementType(), oldValue);
arr.replace(oldSize, oldSize, values, 0, inserted, true);
return arr;
}
public static <T> void insert(VisageObject instance, int varNum, Sequence<? extends T> values) {
int inserted = values.size();
if (inserted == 0)
return;
instance.varChangeBits$(varNum, VisageObject.VFLGS$INIT$MASK, VisageObject.VFLGS$INIT$INITIALIZED_DEFAULT);
Sequence<? extends T> oldValue = (Sequence<? extends T>) instance.get$(varNum);
while (oldValue instanceof SequenceProxy) {
SequenceProxy sp = (SequenceProxy) oldValue;
instance = sp.instance();
varNum = sp.varNum();
instance.varChangeBits$(varNum, VisageObject.VFLGS$INIT$MASK, VisageObject.VFLGS$INIT$INITIALIZED_DEFAULT);
oldValue = (Sequence<? extends T>) instance.get$(varNum);
}
int oldSize = oldValue.size();
int newLength = values == null ? 0 : values.size();
Sequence<? extends T> arr = insert(oldValue, values);
instance.invalidate$(varNum, oldSize, oldSize, newLength, VisageObject.PHASE_TRANS$CASCADE_INVALIDATE);
instance.seq$(varNum, arr);
instance.invalidate$(varNum, oldSize, oldSize, newLength, VisageObject.PHASE_TRANS$CASCADE_TRIGGER);
}
public static <T> void insertBefore(VisageObject instance, int varNum, T value, int position) {
replaceSlice(instance, varNum, value, position, position);
}
public static <T> void insertBefore(VisageObject instance, int varNum, Sequence<? extends T> values, int position) {
replaceSlice(instance, varNum, values, position, position);
}
public static <T> Sequence<? extends T> insertBefore(Sequence<? extends T> oldValue, T value, int position) {
return replaceSlice(oldValue, value, position, position);
}
public static <T> Sequence<? extends T> insertBefore(Sequence<? extends T> oldValue, Sequence<? extends T> values, int position) {
return replaceSlice(oldValue, values, position, position);
}
public static <T> void deleteIndexed(VisageObject instance, int varNum, int position) {
replaceSlice(instance, varNum, (Sequence<? extends T>)null, position, position+1);
}
public static <T> Sequence<? extends T> deleteIndexed(Sequence<? extends T> oldValue, int position) {
return replaceSlice(oldValue, (Sequence<? extends T>)null, position, position+1);
}
public static <T> void deleteSlice(VisageObject instance, int varNum, int begin, int end) {
replaceSlice(instance, varNum, (Sequence<? extends T>)null, begin, end);
}
public static <T> Sequence<? extends T> deleteSlice(Sequence<? extends T> oldValue, int begin, int end) {
return replaceSlice(oldValue, (Sequence<? extends T>)null, begin, end);
}
public static <T> void deleteValue(VisageObject instance, int varNum, T value) {
if (instance.varTestBits$(varNum, VisageObject.VFLGS$IS_BOUND_READONLY, VisageObject.VFLGS$IS_BOUND_READONLY)) {
throw new AssignToBoundException("Cannot mutate bound sequence");
}
Sequence<? extends T> oldValue = (Sequence<? extends T>) instance.get$(varNum);
while (oldValue instanceof SequenceProxy) {
SequenceProxy sp = (SequenceProxy) oldValue;
instance = sp.instance();
varNum = sp.varNum();
oldValue = (Sequence<? extends T>) instance.get$(varNum);
}
// It's tempting to just do:
// Sequence<? extends T> arr = deleteValue(oldValue, value);
// instance.seq$(varNum, arr);
// However, in that case triggers won't run properly.
int hi = -1;
for (int i = oldValue.size(); ; ) {
boolean matches = --i < 0 ? false : oldValue.get(i).equals(value);
if (matches) {
if (hi < 0)
hi = i;
}
else if (hi >= 0) {
deleteSlice(instance, varNum, i+1, hi+1);
// The following may be redundant - but just in case:
oldValue = (Sequence<? extends T>) instance.get$(varNum);
hi = -1;
}
if (i < 0) break;
}
}
public static <T> Sequence<? extends T> deleteValue(Sequence<? extends T> oldValue, T value) {
int hi = -1;
for (int i = oldValue.size(); ; ) {
boolean matches = --i < 0 ? false : oldValue.get(i).equals(value);
if (matches) {
if (hi < 0)
hi = i;
}
else if (hi >= 0) {
oldValue = deleteSlice(oldValue, i+1, hi+1);
hi = -1;
}
if (i < 0) break;
}
return oldValue;
}
public static <T> Sequence<? extends T> deleteAll(Sequence<? extends T> oldValue) {
return oldValue.getEmptySequence();
}
public static <T> void deleteAll(VisageObject instance, int varNum) {
int oldSize = instance.size$(varNum);
replaceSlice(instance, varNum, (Sequence<? extends T>)null, 0, oldSize);
}
public static boolean withinBounds(VisageObject obj, int varNum, int position) {
return (position >= 0 && position < obj.size$(varNum));
}
}