/*
* $Id: AnySequence.java,v 1.21 2002/09/16 08:05:02 jkl Exp $
*
* Copyright (c) 2002 Njet Communications Ltd. All Rights Reserved.
*
* Use is subject to license terms, as defined in
* Anvil Sofware License, Version 1.1. See LICENSE
* file, or http://njet.org/license-1.1.txt
*/
package anvil.core;
import java.io.Writer;
import java.io.IOException;
import java.io.OutputStream;
import java.io.ByteArrayOutputStream;
import java.util.Comparator;
import anvil.script.Context;
import anvil.java.util.BindingEnumeration;
import anvil.util.Conversions;
import org.apache.oro.text.regex.Pattern;
import org.apache.oro.text.regex.Perl5Compiler;
import org.apache.oro.text.regex.Perl5Matcher;
///
/// @class sequence
/// Sequence represents list of elements, that may
/// be accessed with index. Some of sequences (such
/// as string and tuple) are immutable and mutating
/// operations always return copy of original sequence
/// modified.
/// @attribute length
/// Length of this sequence
/// @synopsis int <b>this</b>.length
///
/// @operator sizeof
/// Length of this sequence
/// @synopsis int sizeof <b>this</b>
///
/// @operator boolean
/// <code>true</code> if length of this sequence is greater than 0,
/// <code>false</code> otherwise.
/// @synopsis boolean (boolean)<b>this</b>
///
/// @reference index
/// @synopsis object <b>this</b>[int index] ; Returns element at given index
/// @synopsis sequence <b>this</b>[int start..int end] ; Returns sequence from given range
/// @synopsis sequence <b>this</b>[indices...] ; Returns sequence of elements
/// @synopsis object <b>this</b>[int index] = element ; Sets the element at given index
/// @synopsis object <b>this</b>[int start .. int end] = element ; Sets the content of sub sequence
/// @synopsis object <b>this</b>[int start .. int end] = sequence ; Sets the content of sub sequence
/// @param index Index of element
/// @param start Start of range (included)
/// @param end End of range (excluded)
/// @param element Element to set
/// @param sequence Elements to set
///
/// @operator append
/// @synopsis <b>this</b>[] = element ; Appends element to end of this sequence
/// @synopsis <b>this</b>[] = sequence ; Appends elements of sequence to end of this sequence
///
/// @operator delete
/// @synopsis delete <b>this</b>[int index] ; Removes element at given index
/// @synopsis delete <b>this</b>[int start..int end] ; Removes given range
/// @synopsis delete <b>this</b>[indices...] ; Removes indicices and ranges
/// @param index Index of element
/// @param start Start of range (included)
/// @param end End of range (excluded)
/// @param index Index of element
///
/// @operator in
/// @synopsis element in <b>this</b> ; Checks if given element is in this sequence
/// @synopsis sequence in <b>this</b> ; Checks if given sequence is a sub sequence
/// in this sequence
///
/// @operator enumeration
/// Returns enumeration of elements in this sequence
/// @synopsis enumeration *<b>this</b>
/*
* class AnySequence
*
* @author: Jani Lehtim�ki
*/
public abstract class AnySequence extends Any
{
public abstract boolean isCompatible(Any type);
public abstract AnySequence clear();
public abstract int getSize();
public abstract AnySequence setSize(int size);
public abstract Any getElement(int index);
public abstract AnySequence setElement(int index, Any element);
public abstract AnySequence swap(int index1, int index2);
public abstract AnySequence crop(int start, int length);
public abstract AnySequence getSlice(int start, int length);
public abstract AnySequence setSlice(int start, int length, Any element);
public abstract AnySequence setSlice(int start, int length, AnySequence element);
public abstract AnySequence deleteSlice(int start, int length);
public abstract AnySequence append(AnySequence sequence);
public abstract AnySequence append(Any element);
public abstract AnySequence createEmptySequence();
public abstract AnySequence createSequence(Any element);
public abstract int compareAt(Any value, int start);
public abstract int compareAt(AnySequence sequence, int start, int length);
public abstract AnySequence fill(Any fill, int start, int length);
public abstract AnySequence sort(int start, int length, Comparator comparator);
public abstract int search(Any element, Comparator comparator);
public AnySequence reverse(int start, int length)
{
AnySequence seq = this;
int p = 0;
int q = p + length - 1;
while(p<q) {
seq = seq.swap(p++, q--);
}
return seq;
}
public int indexOf(Any element, int start)
{
if (start < 0) {
return -1;
}
int size = getSize();
if (isCompatible(element)) {
AnySequence needle = (AnySequence)element;
int needle_size = needle.getSize();
size -= (needle_size - 1);
if (size <= 0) {
return -1;
}
for(; start < size; start++) {
if (compareAt(needle, start, needle_size)==0) {
return start;
}
}
} else {
for(; start<size; start++) {
if (compareAt(element, start)==0) {
return start;
}
}
}
return -1;
}
public int lastIndexOf(Any element, int start)
{
if (start < 0) {
return -1;
}
int size = getSize();
if (isCompatible(element)) {
AnySequence needle = (AnySequence)element;
int needle_size = needle.getSize();
if (start + needle_size >= size) {
start = size - needle_size;
}
for(; start >= 0; start--) {
if (compareAt(needle, start, needle_size)==0) {
return start;
}
}
} else {
for(; start >= 0; start--) {
if (compareAt(element, start)==0) {
return start;
}
}
}
return -1;
}
public boolean equalsTo(AnySequence sequence)
{
int alength = getSize();
int blength = sequence.getSize();
if (alength != blength) {
return false;
}
return compareAt(sequence, 0, alength) == 0;
}
public int compareTo(AnySequence sequence)
{
int alength = getSize();
int blength = sequence.getSize();
int length = (alength < blength) ? alength : blength;
int delta = compareAt(sequence, 0, length);
if (delta == 0) {
return alength - blength;
}
return delta;
}
public anvil.script.ClassType classOf() {
return __class__;
}
public int sizeOf()
{
return getSize();
}
public boolean isMutable()
{
return true;
}
public boolean isSequence()
{
return true;
}
public boolean toBoolean()
{
return getSize() > 0;
}
public AnySequence getReference(AnySequence sequence, Any index)
{
switch(index.typeOf()) {
case IS_TUPLE:
case IS_LIST:
{
Any[] tuple = index.toTuple();
int length = index.sizeOf();
for(int i=0; i<length; i++) {
sequence = getReference(sequence, tuple[i]);
}
}
break;
case IS_RANGE:
{
AnyRange r = index.toRange();
int size = getSize();
Any a = r.getLeft();
int start = a.isDefined() ? a.toInt() : 0;
a = r.getRight();
int end = a.isDefined() ? a.toInt() : size;
long l = ArrayUtils.adjust2(start, end, size);
start = (int)(l & 0xffffffff);
int length = (int)(l >> 32);
if (length>0 && start<size) {
AnySequence slice = getSlice(start, length);
if (sequence == null) {
sequence = slice;
} else {
sequence = sequence.append(slice);
}
} else {
if (sequence == null) {
sequence = createEmptySequence();
}
}
}
break;
default:
int i = index.toInt();
if (i>=0 && i<getSize()) {
Any element = getElement(i);
sequence = ((sequence != null) ?
sequence.append(element) : createSequence(element));
}
}
return sequence;
}
public Any getReference(Context context, Any index)
{
switch(index.typeOf()) {
case IS_TUPLE:
case IS_LIST:
return getReference((AnySequence)null, index);
case IS_RANGE:
{
AnyRange r = index.toRange();
int size = getSize();
Any a = r.getLeft();
int start = a.isDefined() ? a.toInt() : 0;
a = r.getRight();
int end = a.isDefined() ? a.toInt() : size;
long l = ArrayUtils.adjust2(start, end, size);
start = (int)(l & 0xffffffff);
int length = (int)(l >> 32);
if (length>0 && start<size) {
return getSlice(start, length);
} else {
return createEmptySequence();
}
}
default:
int i = index.toInt();
return (i>=0 && i<getSize()) ? getElement(i) : UNDEFINED;
}
}
public Any checkReference(Context context, Any index)
{
return getReference(context, index);
}
public Any setReference(Context context, Any value)
{
if (isCompatible(value)) {
append((AnySequence)value);
} else {
append(value);
}
return value;
}
public boolean deleteReference(Context context, Any index)
{
switch(index.typeOf()) {
case IS_TUPLE:
case IS_LIST:
{
Any[] tuple = index.toTuple();
int length = index.sizeOf();
for(int i=0; i<length; i++) {
deleteReference(context, tuple[i]);
}
}
break;
case IS_RANGE:
{
AnyRange r = index.toRange();
int size = getSize();
Any a = r.getLeft();
int start = a.isDefined() ? a.toInt() : 0;
a = r.getRight();
int end = a.isDefined() ? a.toInt() : size;
long l = ArrayUtils.adjust2(start, end, size);
start = (int)(l & 0xffffffff);
int length = (int)(l >> 32);
if (length>0 && start<size) {
deleteSlice(start, length);
}
}
break;
default:
int i = index.toInt();
if (i>=0 && i<getSize()) {
deleteSlice(i,1);
}
}
return true;
}
public Any setReference(Context context, Any index, Any value)
{
int start;
int length;
if (index.isRange()) {
AnyRange r = index.toRange();
int size = getSize();
Any a = r.getLeft();
start = a.isDefined() ? a.toInt() : 0;
a = r.getRight();
int end = a.isDefined() ? a.toInt() : size;
long l = ArrayUtils.adjust2(start, end, size);
start = (int)(l & 0xffffffff);
length = (int)(l >> 32);
if (start>=size) {
return value;
}
if (isCompatible(value)) {
setSlice(start, length, (AnySequence)value);
} else {
setSlice(start, length, value);
}
return value;
} else {
start = index.toInt();
if (start>=0 && start<getSize()) {
setElement(start, value);
}
return value;
}
}
public Any getAttribute(Context context, String attribute)
{
if (attribute.equals("length")) {
return Any.create(getSize());
} else {
return UNDEFINED;
}
}
public boolean contains(Any value)
{
return indexOf(value, 0) != -1;
}
public Any add(Any other)
{
if (isCompatible(other)) {
AnySequence seq = createEmptySequence();
seq = seq.append(this);
seq = seq.append((AnySequence)other);
return seq;
} else {
return this;
}
}
public boolean equals(Object obj)
{
if (this == obj) {
return true;
}
if (getClass() == obj.getClass()) {
return equalsTo((AnySequence)obj);
}
return false;
}
protected int compare(Any other)
{
return compareTo((AnySequence)other);
}
public BindingEnumeration enumeration()
{
return new ArrayEnumeration();
}
///
/// @method length
/// Returns the length of this sequence.
/// @synopsis int length()
///
public Any m_length()
{
return Any.create(getSize());
}
///
/// @method setLength
/// Expands or contract sequence to given length. If length
/// is greater than current size, <code>null</code> is used as
/// a fill.
/// @synopsis sequence setLength(int length)
/// @return Modified sequence, original or copy
///
public static final Object[] p_setLength = new Object[] { "length" };
public Any m_setLength(int length)
{
int size = getSize();
if (length>=0 && length<size) {
return setSize(length);
} else if (length>size) {
AnySequence seq = this;
while(length-->size) {
seq = seq.append(NULL);
}
return seq;
}
return this;
}
///
/// @method clear
/// Clears this sequence.
/// @synopsis sequence clear()
/// @return Modified sequence, original or copy
///
public Any m_clear()
{
return clear();
}
///
/// @method fill
/// Fills sequence with given element.
/// @synopsis fill()
/// @synopsis fill(object element)
/// @synopsis fill(object element, int start)
/// @synopsis fill(object element, int start, int length)
/// @param element Element to fill with, default is <code>null</code>.
/// @param start Start of sub sequence to fill
/// @param start Length of sub sequence to fill
/// @return Modified sequence, original or copy
///
public static final Object[] p_fill = new Object[] { "*element", NULL, "*start", null, "*end", null };
public Any m_fill(Any element, Any start_, Any end_)
{
int size = getSize();
if (start_ == null) {
return fill(element, 0, size);
} else {
int start = start_.toInt();
int length = size;
if (end_ != null) {
length = end_.toInt();
}
long l = ArrayUtils.adjust(start, length, size);
start = (int)(l & 0xffffffff);
length = (int)(l >> 32);
return fill(element, start, length);
}
}
///
/// @method startsWith
/// Checks if sequence starts with given element or sequence
/// @synopsis boolean startsWith(object prefix)
/// @synopsis boolean startsWith(sequence prefix)
///
public static final Object[] p_startsWith = new Object[] { "prefix" };
public Any m_startsWith(Any element)
{
int size = getSize();
if (isCompatible(element)) {
AnySequence sequence = (AnySequence)element;
int sequence_size = sequence.getSize();
if (sequence_size == 0) {
return TRUE;
}
if (size >= sequence_size) {
return compareAt(sequence, 0, sequence_size)==0 ? TRUE : FALSE;
}
} else {
if (size > 0) {
return compareAt(element, 0)==0 ? TRUE : FALSE;
}
}
return FALSE;
}
///
/// @method endsWith
/// Checks if sequence ends with given element or sequence
/// @synopsis boolean endsWith(object suffix)
/// @synopsis boolean endsWith(sequence suffix)
///
public static final Object[] p_endsWith = new Object[] { "suffix" };
public Any m_endsWith(Any element)
{
int size = getSize();
if (isCompatible(element)) {
AnySequence sequence = (AnySequence)element;
int sequence_size = sequence.getSize();
if (sequence_size > 0) {
if (size >= sequence_size) {
return compareAt(sequence, size-sequence_size, sequence_size)==0 ? TRUE : FALSE;
}
} else {
return TRUE;
}
} else {
if (size > 0) {
return compareAt(element, size-1)==0 ? TRUE : FALSE;
}
}
return FALSE;
}
///
/// @method indexOf
/// Finds the first index of given needle.
/// @synopsis int indexOf(object needle)
/// @synopsis int indexOf(object needle, int fromIndex)
/// @param needle Element to search for
/// @param fromIndex Start index of search
/// @return Index of needle, -1 if it wasn't found.
///
public static final Object[] p_indexOf = new Object[] { "needle", "*fromIndex", new Integer(0) };
public Any m_indexOf(Any needle, int from)
{
return Any.create(indexOf(needle, from));
}
///
/// @method lastIndexOf
/// Finds the last index of given needle. Searching
/// occurs from end to beginning.
/// @synopsis int lastIndexOf(object needle)
/// @synopsis int lastIndexOf(object needle, int fromIndex)
/// @param needle Element to search for
/// @param fromIndex Start index of search
/// @return Index or needle, -1 if it wasn't found.
///
public static final Object[] p_lastIndexOf = new Object[] { "needle", "*fromIndex", null };
public Any m_lastIndexOf(Any needle, Any from)
{
int start = (from != null) ? from.toInt() : getSize();
return Any.create(lastIndexOf(needle, start));
}
///
/// @method append
/// Appends given element to this sequence.
/// @synopsis sequence append(object element)
/// @param element Element to append
/// @return Modified sequence, original or copy
///
public static final Object[] p_append = new Object[] { "element" };
public Any m_append(Any element)
{
return append(element);
}
///
/// @method concat
/// Concatenates given elements to this sequence.
/// @synopsis sequence concat(sequence elements)
/// @synopsis sequence concat(object element)
/// @param element Element to concatenate
/// @param elements Elements of compatible sequence are concatenated
/// @return Modified sequence, original or copy
///
public static final Object[] p_concat = new Object[] { "element" };
public Any m_concat(Any element)
{
if (isCompatible(element)) {
return append((AnySequence)element);
} else {
return append(element);
}
}
///
/// @method crop
/// Crops (shortens) this sequence to contain only specified range.
/// @synopsis sequence crop(int start)
/// @synopsis sequence crop(int start, int length)
/// @param start Start of sub sequence
/// @param length Length of sub sequence
/// @return Cropped sequence, original or copy
///
public static final Object[] p_crop = new Object[] { "start", "*length", null };
public Any m_crop(int start, Any length_)
{
int size = getSize();
int length = (length_ != null) ? length_.toInt() : size;
long l = ArrayUtils.adjust(start, length, size);
start = (int)(l & 0xffffffff);
length = (int)(l >> 32);
if (start < size && length > 0) {
return crop(start, length);
} else {
return clear();
}
}
///
/// @method slice
/// Takes slice from sequence.
/// @synopsis sequence slice(int start)
/// @synopsis sequence slice(int start, int length)
/// @param start Start of sub sequence
/// @param length Length of sub sequence
/// @return Sub sequence
///
public static final Object[] p_slice = new Object[] { "start", "*length", null };
public Any m_slice(int start, Any length_)
{
int size = getSize();
int length = (length_ != null) ? length_.toInt() : size;
long l = ArrayUtils.adjust(start, length, size);
start = (int)(l & 0xffffffff);
length = (int)(l >> 32);
if (start < size && length > 0) {
return getSlice(start, length);
} else {
return createEmptySequence();
}
}
///
/// @method cut
/// Remove given range from sequence.
/// @synopsis sequence cut(int start)
/// @synopsis sequence cut(int start, int length)
/// @param start Start of sub sequence to remove
/// @param length Length of sub sequence to remove
/// @return Modified sequence, original or copy
///
public static final Object[] p_cut = new Object[] { "start", "*length", null };
public Any m_cut(int start, Any length_)
{
int size = getSize();
int length = (length_ != null) ? length_.toInt() : size;
long l = ArrayUtils.adjust(start, length, size);
start = (int)(l & 0xffffffff);
length = (int)(l >> 32);
if (start < size && length > 0) {
return deleteSlice(start, length);
}
return this;
}
///
/// @method insert
/// Inserts given element (or elements) to this sequence.
/// Some elements might be replaced if length > 0.
/// @synopsis sequence insert(int start, sequence elements)
/// @synopsis sequence insert(int start, object element)
/// @synopsis sequence insert(int start, int length, sequence elements)
/// @synopsis sequence insert(int start, int length, object element)
/// @param start Insertion position
/// @param length Length of sub sequence to overwrite
/// @param element Element to insert
/// @param elements Elements of compatible sequence are inserted
/// @return Modified sequence, original or copy
///
public static final Object[] p_insert = new Object[] { "start", "lengthOrElement", "*element", null };
public Any m_insert(int start, Any p1, Any p2)
{
Any element;
int length;
if (p2 == null) {
length = 0;
element = p1;
} else {
length = p1.toInt();
element = p2;
}
int size = getSize();
long l = ArrayUtils.adjust(start, length, size);
start = (int)(l & 0xffffffff);
length = (int)(l >> 32);
if (start == size) {
if (isCompatible(element)) {
return append((AnySequence)element);
} else {
return append(element);
}
} else {
if (isCompatible(element)) {
return setSlice(start, length, (AnySequence)element);
} else {
return setSlice(start, length, element);
}
}
}
///
/// @method minmax
/// Finds and returns minimum and maximum value from this sequence.
/// @synopsis tuple minmax()
/// @return tuple containing <code>(minElement, maxElement)</code>
///
public Any m_minmax()
{
Any min = UNDEFINED;
Any max = UNDEFINED;
int size = getSize();
for(int i=0; i<size; i++) {
Any candidate = getElement(i);
if (i == 0) {
min = max = candidate;
} else {
if (candidate.compareTo(min) < 0) {
min = candidate;
} else if (candidate.compareTo(max) > 0) {
max = candidate;
}
}
}
return new AnyTuple(new Any[] { min, max });
}
/// @method swap
/// Swaps elements of given indices.
/// @synopsis sequence swap(int index1, int index2)
/// @return Modified sequence, original or copy
public static final Object[] p_swap = new Object[] { "index1", "index2" };
public Any m_swap(int index1, int index2)
{
int size = getSize();
if (index1>=0 && index1<size) {
if (index2>=0 && index2<size) {
if (index1 != index2) {
return swap(index1, index2);
}
}
}
return this;
}
///
/// @method reverse
/// Reverse elements in given range.
/// @synopsis sequence reverse()
/// @synopsis sequence reverse(int start)
/// @synopsis sequence reverse(int start, int length)
/// @param start Start index of sub sequence to reverse
/// @param length Length of sub sequence to reverse
/// @return Reversed sequence, original or copy
///
public static final Object[] p_reverse = new Object[] { "*start", new Integer(0), "*length", null };
public Any m_reverse(int start, Any length_)
{
int size = getSize();
int length = (length_ != null) ? length_.toInt() : size;
long l = ArrayUtils.adjust(start, length, size);
start = (int)(l & 0xffffffff);
length = (int)(l >> 32);
return reverse(start, length);
}
///
/// @method sort
/// Sorts this sequence.
/// @synopsis sequence sort()
/// @synopsis sequence sort(int start)
/// @synopsis sequence sort(int start, int length)
/// @synopsis sequence sort(int start, int length, Function comparator)
/// @synopsis sequence sort(int start, int length, Function comparator, object data)
/// @param start Start of sub sequence to sort
/// @param start Lenght of sub sequence to sort
/// @param comparator Comparator function
/// <code>function comparator(elem1, elem2)</code>,
/// or <code>function comparator(elem1, elem2, data)</code>. Function should
/// return less than 0 if elem1<elem2, 0 if elem1==elem2 or
/// more than 0 if elem1>elem2.
/// @param data Data passed as a third parameter to searching function
/// @return Sorted sequence, original or copy
public static final Object[] p_sort =
new Object[] { null, "*start", new Integer(0), "*length", null, "*comparator", null, "*data", UNDEFINED };
public Any m_sort(Context context, int start, Any length_, Any comparator_, Any data)
{
int size = getSize();
int length = (length_ != null) ? length_.toInt() : size;
Comparator comparator = null;
if (comparator_ != null) {
comparator = new AnyUtils.SequenceComparator(context, comparator_, data);
}
long l = ArrayUtils.adjust(start, length, size);
start = (int)(l & 0xffffffff);
length = (int)(l >> 32);
return sort(start, length, comparator);
}
///
/// @method search
/// Performs binary-search this sequence.
/// @synopsis int search(object element)
/// @synopsis int search(object element, Function comparator)
/// @synopsis iut search(object element, Function comparator, object data)
/// @param comparator Comparator function
/// <code>function comparator(elem1, elem2)</code>,
/// or <code>function comparator(elem1, elem2, data)</code>. Function should
/// return less than 0 if elem1<elem2, 0 if elem1==elem2 or
/// more than 0 if elem1>elem2.
/// @param element Element to search for
/// @param data Data passed as a third parameter to searching function
/// @return Index of element found, or less than 0 if no element could be found.
public static final Object[] p_search =
new Object[] { null, "element", "*comparator", null, "*data", UNDEFINED };
public Any m_search(Context context, Any element, Any comparator_, Any data)
{
int size = getSize();
int start = 0;
int length = size;
Comparator comparator = null;
if (comparator_ != null) {
comparator = new AnyUtils.SequenceComparator(context, comparator_, data);
}
return Any.create(search(element, comparator));
}
///
/// @method repeat
/// Repeats this sequence given times.
/// @synopsis sequence repeat(int count)
/// @param count Number of times to repeat this sequence
/// @return New sequence containing this sequence <code>count</code> times
///
public static final Object[] p_repeat = new Object[] { "count" };
public Any m_repeat(int count)
{
AnySequence seq = createEmptySequence();
for(int i=count; i>0; i--) {
seq = seq.append((AnySequence)this);
}
return seq;
}
///
/// @method count
/// Count the number of elements which equals to given element.
/// @synopsis int count(object element)
/// @param element Element to count
/// @return Number of elements mathinc given element
///
public static final Object[] p_count = new Object[] { "element" };
public Any m_count(Any element)
{
int count = 0;
for(int i=getSize()-1; i>=0; i--) {
if (compareAt(element, i) == 0) {
count++;
}
}
return Any.create(count);
}
///
/// @method push
/// Adds given elements to end this sequence. Adding occurs
/// in the same order as in parameter list, i.e. last parameter will
/// be last in sequence.
/// @synopsis sequence push(object element, ...)
/// @return Modified sequence, original or copy
///
public static final Object[] p_push = new Object[] { "element", "elements" };
public Any m_push(Any element, Any[] parameters)
{
AnySequence seq = this.append(element);
int n = parameters.length;
for(int i=0; i<n; i++) {
seq = seq.append(parameters[i]);
}
return seq;
}
///
/// @method pop
/// @synopsis object pop() ; Pops last element out of this sequence
/// @synopsis object pop(int index) ; Pops element at given index out of this sequence
/// @param index Index of element
/// @return Removed element
///
public static final Object[] p_pop = new Object[] { "*index", null };
public Any m_pop(Any index_)
{
int size = getSize();
int index = size - 1;
if (index_ != null) {
index = index_.toInt();
if (index<0 || index>=size) {
return UNDEFINED;
}
}
if (size>0) {
Any item = getElement(index);
deleteSlice(index, 1);
return item;
} else {
return UNDEFINED;
}
}
///
/// @method unshift
/// Insert given elements to this start sequence. Insertion
/// happens in the same order as they appear in parameter list,
/// i.e. last parameter will be first in sequence.
/// @synopsis sequence unshift(object element, ...)
/// @return Modified sequence, original or copy
///
public static final Object[] p_unshift = new Object[] { "element", "elements" };
public Any m_unshift(Any element, Any[] parameters)
{
AnySequence seq = this.setSlice(0, 0, element);
int n = parameters.length;
for(int i=0; i<n; i++) {
seq = seq.setSlice(0, 0, parameters[i]);
}
return seq;
}
///
/// @method shift
/// Shifts (removes and returns) the first element out this sequence.
/// @synopsis object shift()
/// @return First element of sequence, or <code>undefined</code>
/// if sequence was empty.
///
public Any m_shift()
{
int size = getSize();
if (size>0) {
Any item = getElement(0);
deleteSlice(0, 1);
return item;
} else {
return UNDEFINED;
}
}
///
/// @method first
/// Returns first element from sequence, or undefined.
/// @synopsis any first()
/// @synopsis any first(int index)
/// @param index Index to sequence, from beginning
/// @return Element from sequence
///
public static final Object[] p_first = new Object[] { "*index", null };
public Any m_first(Any index_)
{
int index = 0;
if (index_ != null) {
index = index_.toInt();
}
int n = getSize();
if (index < 0 || index >= n) {
return UNDEFINED;
}
return getElement(index);
}
///
/// @method last
/// Returns last element from sequence, or undefined.
/// @synopsis any last()
/// @synopsis any last(int index)
/// @param index Index to sequence, starting from end
/// @return Element from sequence
///
public static final Object[] p_last = new Object[] { "*index", null };
public Any m_last(Any index_)
{
int index = 0;
if (index_ != null) {
index = index_.toInt();
}
int n = getSize();
if (index < 0 || index >= n) {
return UNDEFINED;
}
return getElement(n - index - 1);
}
///
/// @method join
/// Joins the string represtation of elements of this sequence
/// together with given clue (default is <code>de", "</code>);
/// @synopsis string join()
/// @synopsis string join(clue)
/// @param clue Clue to join elements with
///
public static final Object[] p_join = new Object[] { "*clue", null };
public Any m_join(String clue)
{
if (clue == null) {
clue = ", ";
}
int size = getSize();
if (size>0) {
StringBuffer buffer = new StringBuffer();
for(int i=0; i<size; i++) {
if (i>0) {
buffer.append(clue);
}
buffer.append(getElement(i).toString());
}
return Any.create(buffer.toString());
} else {
return EMPTY_STRING;
}
}
///
/// @method get
/// Fetches value from multi dimensional sequence. (i.e. sequence
/// containing nested sequences). If missing index is encountered
/// <code>undefined</code> is returned.
/// @synopsis object get(index1, index2, ...)
public static final Object[] p_get = new Object[] { "*indices" };
public Any m_get(Any[] parameters)
{
int n = parameters.length;
AnySequence self = this;
int i=0;
while(i<n) {
int index = parameters[i++].toInt();
if (index>=0 && index<self.getSize()) {
Any a = self.getElement(index);
if (i>=n) {
return a;
}
if (a.isSequence()) {
self = (AnySequence)a;
} else {
return UNDEFINED;
}
} else {
return UNDEFINED;
}
}
return self;
}
///
/// @method set
/// Sets value at given multi-dimensional sequence (i.e. sequence
/// containing nested sequences). If missing index is encountered
/// sequences remain unchanged.
/// @synopsis object set(index1, index2, ..., value)
/// @param value Value to set
/// @return value
public static final Object[] p_set = new Object[] { null, "*indicesAndValue" };
public Any m_set(Context context, Any[] parameters)
{
int n = parameters.length;
if (n<2) {
throw parametersMissing(context, "set");
}
n--;
Any value = parameters[n];
AnySequence self = this;
int i=0;
while(i<n) {
int index = parameters[i++].toInt();
if (index>=0 && index<self.getSize()) {
if (i==n) {
self.setElement(index, value);
return value;
}
Any a = self.getElement(index);
if (a.isSequence()) {
self = (AnySequence)a;
} else {
return value;
}
} else {
return value;
}
}
return value;
}
/// @method grep
/// Returns new sequence of a same type as this, containing
/// all elements that matched given regular expression.
/// @synopsis sequence grep(pattern pattern)
/// @synopsis sequence grep(string pattern)
/// @param pattern Regular expression to match with
/// @return New sequence containing selected elements
public static final Object[] p_grep = new Object[] { null, "pattern" };
public Any m_grep(Context context, Any pattern_)
{
Pattern pattern = ObjectPool.createPattern(context, pattern_);
Perl5Matcher matcher = new Perl5Matcher();
AnySequence matched = createEmptySequence();
int size = getSize();
for(int i=0; i<size; i++) {
Any element = getElement(i);
if (matcher.contains(element.toString(), pattern)) {
matched = matched.append(element);
}
}
return matched;
}
///
/// @method select
/// Returns new sequence of same type as this, containing
/// all elements for which given function returned <code>true</code>.
/// @synopsis sequence select(Function selector)
/// @synopsis sequence select(Function selector, object data)
/// @param selector Selector function, either like
/// <code>function selector(element)</code> or
/// <code>function selector(element, data)</code>.
/// @param data Data passed as a second parameter to selector function
/// @return New sequence containing selected elements.
public static final Object[] p_select = new Object[] { null, "selector", "*data", UNDEFINED };
public Any m_select(Context context, Any selector, Any data)
{
AnySequence matched = createEmptySequence();
int size = getSize();
for(int i=0; i<size; i++) {
Any element = getElement(i);
if (selector.execute(context, element, Any.create(i), data).toBoolean()) {
matched = matched.append(element);
}
}
return matched;
}
///
/// @method walk
/// Iterates through the sequence and calls given
/// function at each element. Iteration ends when end of
/// sequence is reached or function returns <code>false</code>.
/// @synopsis object walk(Function walker)
/// @synopsis object walk(Function walker, object data)
/// @param walker Iterator function, either like
/// <code>function walker(element)</code> or
/// <code>function walker(element, data)</code>.
/// @param data Data passed as a second parameter to walker function
/// @return Returns 'data' parameter
public static final Object[] p_walk = new Object[] { null, "walker", "*data", UNDEFINED };
public Any m_walk(Context context, Any walker, Any data)
{
int size = getSize();
for(int i=0; i<size; i++) {
Any element = getElement(i);
if (!walker.execute(context, element, Any.create(i), data).toBoolean()) {
break;
}
}
return data;
}
public class ArrayEnumeration implements BindingEnumeration
{
private int _index = 0;
public ArrayEnumeration()
{
}
public boolean hasMoreElements()
{
return (_index < getSize());
}
public Object nextElement()
{
return (_index < getSize()) ? getElement(_index++) : UNDEFINED;
}
public Object nextKey()
{
return (_index < getSize()) ? Any.create(_index) : UNDEFINED;
}
}
transient public static final anvil.script.compiler.NativeClass __class__ =
new anvil.script.compiler.NativeClass("sequence", AnySequence.class,
//DOC{{
""+
"\n" +
" @class sequence\n" +
" Sequence represents list of elements, that may\n" +
" be accessed with index. Some of sequences (such\n" +
" as string and tuple) are immutable and mutating\n" +
" operations always return copy of original sequence\n" +
" modified.\n" +
" @attribute length\n" +
" Length of this sequence\n" +
" @synopsis int <b>this</b>.length\n" +
"\n" +
" @operator sizeof\n" +
" Length of this sequence\n" +
" @synopsis int sizeof <b>this</b>\n" +
"\n" +
" @operator boolean\n" +
" <code>true</code> if length of this sequence is greater than 0, \n" +
" <code>false</code> otherwise.\n" +
" @synopsis boolean (boolean)<b>this</b>\n" +
"\n" +
" @reference index\n" +
" @synopsis object <b>this</b>[int index] ; Returns element at given index\n" +
" @synopsis sequence <b>this</b>[int start..int end] ; Returns sequence from given range\n" +
" @synopsis sequence <b>this</b>[indices...] ; Returns sequence of elements \n" +
" @synopsis object <b>this</b>[int index] = element ; Sets the element at given index\n" +
" @synopsis object <b>this</b>[int start .. int end] = element ; Sets the content of sub sequence\n" +
" @synopsis object <b>this</b>[int start .. int end] = sequence ; Sets the content of sub sequence\n" +
" @param index Index of element\n" +
" @param start Start of range (included)\n" +
" @param end End of range (excluded)\n" +
" @param element Element to set\n" +
" @param sequence Elements to set\n" +
"\n" +
" @operator append\n" +
" @synopsis <b>this</b>[] = element ; Appends element to end of this sequence\n" +
" @synopsis <b>this</b>[] = sequence ; Appends elements of sequence to end of this sequence\n" +
"\n" +
" @operator delete\n" +
" @synopsis delete <b>this</b>[int index] ; Removes element at given index\n" +
" @synopsis delete <b>this</b>[int start..int end] ; Removes given range\n" +
" @synopsis delete <b>this</b>[indices...] ; Removes indicices and ranges\n" +
" @param index Index of element\n" +
" @param start Start of range (included)\n" +
" @param end End of range (excluded)\n" +
" @param index Index of element\n" +
"\n" +
" @operator in\n" +
" @synopsis element in <b>this</b> ; Checks if given element is in this sequence\n" +
" @synopsis sequence in <b>this</b> ; Checks if given sequence is a sub sequence\n" +
" in this sequence\n" +
"\n" +
" @operator enumeration\n" +
" Returns enumeration of elements in this sequence\n" +
" @synopsis enumeration *<b>this</b>\n" +
"\n" +
" @method length\n" +
" Returns the length of this sequence.\n" +
" @synopsis int length()\n" +
"\n" +
"\n" +
" @method setLength\n" +
" Expands or contract sequence to given length. If length\n" +
" is greater than current size, <code>null</code> is used as \n" +
" a fill.\n" +
" @synopsis sequence setLength(int length)\n" +
" @return Modified sequence, original or copy\n" +
"\n" +
"\n" +
" @method clear\n" +
" Clears this sequence.\n" +
" @synopsis sequence clear()\n" +
" @return Modified sequence, original or copy\n" +
"\n" +
"\n" +
" @method fill\n" +
" Fills sequence with given element.\n" +
" @synopsis fill()\n" +
" @synopsis fill(object element)\n" +
" @synopsis fill(object element, int start)\n" +
" @synopsis fill(object element, int start, int length)\n" +
" @param element Element to fill with, default is <code>null</code>.\n" +
" @param start Start of sub sequence to fill\n" +
" @param start Length of sub sequence to fill\n" +
" @return Modified sequence, original or copy\n" +
"\n" +
"\n" +
" @method startsWith\n" +
" Checks if sequence starts with given element or sequence\n" +
" @synopsis boolean startsWith(object prefix)\n" +
" @synopsis boolean startsWith(sequence prefix)\n" +
"\n" +
"\n" +
" @method endsWith\n" +
" Checks if sequence ends with given element or sequence\n" +
" @synopsis boolean endsWith(object suffix)\n" +
" @synopsis boolean endsWith(sequence suffix)\n" +
"\n" +
"\n" +
" @method indexOf\n" +
" Finds the first index of given needle.\n" +
" @synopsis int indexOf(object needle)\n" +
" @synopsis int indexOf(object needle, int fromIndex)\n" +
" @param needle Element to search for\n" +
" @param fromIndex Start index of search\n" +
" @return Index of needle, -1 if it wasn't found.\n" +
"\n" +
"\n" +
" @method lastIndexOf\n" +
" Finds the last index of given needle. Searching\n" +
" occurs from end to beginning.\n" +
" @synopsis int lastIndexOf(object needle)\n" +
" @synopsis int lastIndexOf(object needle, int fromIndex)\n" +
" @param needle Element to search for\n" +
" @param fromIndex Start index of search\n" +
" @return Index or needle, -1 if it wasn't found.\n" +
"\n" +
"\n" +
" @method append\n" +
" Appends given element to this sequence.\n" +
" @synopsis sequence append(object element)\n" +
" @param element Element to append\n" +
" @return Modified sequence, original or copy\n" +
" \n" +
"\n" +
" @method concat\n" +
" Concatenates given elements to this sequence.\n" +
" @synopsis sequence concat(sequence elements)\n" +
" @synopsis sequence concat(object element)\n" +
" @param element Element to concatenate\n" +
" @param elements Elements of compatible sequence are concatenated\n" +
" @return Modified sequence, original or copy\n" +
" \n" +
"\n" +
" @method crop\n" +
" Crops (shortens) this sequence to contain only specified range.\n" +
" @synopsis sequence crop(int start)\n" +
" @synopsis sequence crop(int start, int length)\n" +
" @param start Start of sub sequence\n" +
" @param length Length of sub sequence\n" +
" @return Cropped sequence, original or copy\n" +
" \n" +
"\n" +
" @method slice\n" +
" Takes slice from sequence.\n" +
" @synopsis sequence slice(int start)\n" +
" @synopsis sequence slice(int start, int length)\n" +
" @param start Start of sub sequence\n" +
" @param length Length of sub sequence\n" +
" @return Sub sequence\n" +
" \n" +
"\n" +
" @method cut\n" +
" Remove given range from sequence.\n" +
" @synopsis sequence cut(int start)\n" +
" @synopsis sequence cut(int start, int length)\n" +
" @param start Start of sub sequence to remove\n" +
" @param length Length of sub sequence to remove\n" +
" @return Modified sequence, original or copy\n" +
"\n" +
"\n" +
" @method insert\n" +
" Inserts given element (or elements) to this sequence.\n" +
" Some elements might be replaced if length > 0.\n" +
" @synopsis sequence insert(int start, sequence elements)\n" +
" @synopsis sequence insert(int start, object element)\n" +
" @synopsis sequence insert(int start, int length, sequence elements)\n" +
" @synopsis sequence insert(int start, int length, object element)\n" +
" @param start Insertion position\n" +
" @param length Length of sub sequence to overwrite\n" +
" @param element Element to insert\n" +
" @param elements Elements of compatible sequence are inserted\n" +
" @return Modified sequence, original or copy\n" +
" \n" +
"\n" +
" @method minmax\n" +
" Finds and returns minimum and maximum value from this sequence.\n" +
" @synopsis tuple minmax()\n" +
" @return tuple containing <code>(minElement, maxElement)</code>\n" +
" \n" +
" @method swap\n" +
" Swaps elements of given indices.\n" +
" @synopsis sequence swap(int index1, int index2)\n" +
" @return Modified sequence, original or copy\n" +
"\n" +
" @method reverse\n" +
" Reverse elements in given range.\n" +
" @synopsis sequence reverse()\n" +
" @synopsis sequence reverse(int start)\n" +
" @synopsis sequence reverse(int start, int length)\n" +
" @param start Start index of sub sequence to reverse\n" +
" @param length Length of sub sequence to reverse\n" +
" @return Reversed sequence, original or copy\n" +
" \n" +
"\n" +
" @method sort\n" +
" Sorts this sequence.\n" +
" @synopsis sequence sort()\n" +
" @synopsis sequence sort(int start)\n" +
" @synopsis sequence sort(int start, int length)\n" +
" @synopsis sequence sort(int start, int length, Function comparator)\n" +
" @synopsis sequence sort(int start, int length, Function comparator, object data)\n" +
" @param start Start of sub sequence to sort\n" +
" @param start Lenght of sub sequence to sort\n" +
" @param comparator Comparator function\n" +
" <code>function comparator(elem1, elem2)</code>,\n" +
" or <code>function comparator(elem1, elem2, data)</code>. Function should\n" +
" return less than 0 if elem1<elem2, 0 if elem1==elem2 or \n" +
" more than 0 if elem1>elem2.\n" +
" @param data Data passed as a third parameter to searching function\n" +
" @return Sorted sequence, original or copy\n" +
"\n" +
" @method search\n" +
" Performs binary-search this sequence.\n" +
" @synopsis int search(object element)\n" +
" @synopsis int search(object element, Function comparator)\n" +
" @synopsis iut search(object element, Function comparator, object data)\n" +
" @param comparator Comparator function\n" +
" <code>function comparator(elem1, elem2)</code>,\n" +
" or <code>function comparator(elem1, elem2, data)</code>. Function should\n" +
" return less than 0 if elem1<elem2, 0 if elem1==elem2 or \n" +
" more than 0 if elem1>elem2.\n" +
" @param element Element to search for\n" +
" @param data Data passed as a third parameter to searching function\n" +
" @return Index of element found, or less than 0 if no element could be found.\n" +
"\n" +
" @method repeat\n" +
" Repeats this sequence given times.\n" +
" @synopsis sequence repeat(int count)\n" +
" @param count Number of times to repeat this sequence\n" +
" @return New sequence containing this sequence <code>count</code> times\n" +
" \n" +
"\n" +
" @method count\n" +
" Count the number of elements which equals to given element.\n" +
" @synopsis int count(object element)\n" +
" @param element Element to count\n" +
" @return Number of elements mathinc given element\n" +
" \n" +
"\n" +
" @method push\n" +
" Adds given elements to end this sequence. Adding occurs\n" +
" in the same order as in parameter list, i.e. last parameter will\n" +
" be last in sequence.\n" +
" @synopsis sequence push(object element, ...)\n" +
" @return Modified sequence, original or copy\n" +
" \n" +
"\n" +
" @method pop\n" +
" @synopsis object pop() ; Pops last element out of this sequence\n" +
" @synopsis object pop(int index) ; Pops element at given index out of this sequence\n" +
" @param index Index of element\n" +
" @return Removed element\n" +
"\n" +
"\n" +
" @method unshift\n" +
" Insert given elements to this start sequence. Insertion\n" +
" happens in the same order as they appear in parameter list, \n" +
" i.e. last parameter will be first in sequence.\n" +
" @synopsis sequence unshift(object element, ...)\n" +
" @return Modified sequence, original or copy\n" +
" \n" +
"\n" +
" @method shift\n" +
" Shifts (removes and returns) the first element out this sequence.\n" +
" @synopsis object shift()\n" +
" @return First element of sequence, or <code>undefined</code>\n" +
" if sequence was empty.\n" +
" \n" +
"\n" +
" @method first\n" +
" Returns first element from sequence, or undefined.\n" +
" @synopsis any first()\n" +
" @synopsis any first(int index)\n" +
" @param index Index to sequence, from beginning\n" +
" @return Element from sequence\n" +
" \n" +
"\n" +
" @method last\n" +
" Returns last element from sequence, or undefined.\n" +
" @synopsis any last()\n" +
" @synopsis any last(int index)\n" +
" @param index Index to sequence, starting from end\n" +
" @return Element from sequence\n" +
" \n" +
"\n" +
" @method join\n" +
" Joins the string represtation of elements of this sequence \n" +
" together with given clue (default is <code>de\", \"</code>);\n" +
" @synopsis string join()\n" +
" @synopsis string join(clue)\n" +
" @param clue Clue to join elements with\n" +
" \n" +
"\n" +
" @method get\n" +
" Fetches value from multi dimensional sequence. (i.e. sequence\n" +
" containing nested sequences). If missing index is encountered\n" +
" <code>undefined</code> is returned.\n" +
" @synopsis object get(index1, index2, ...)\n" +
"\n" +
" @method set\n" +
" Sets value at given multi-dimensional sequence (i.e. sequence\n" +
" containing nested sequences). If missing index is encountered \n" +
" sequences remain unchanged.\n" +
" @synopsis object set(index1, index2, ..., value)\n" +
" @param value Value to set\n" +
" @return value\n" +
" @method grep\n" +
" Returns new sequence of a same type as this, containing\n" +
" all elements that matched given regular expression.\n" +
" @synopsis sequence grep(pattern pattern)\n" +
" @synopsis sequence grep(string pattern)\n" +
" @param pattern Regular expression to match with\n" +
" @return New sequence containing selected elements\n" +
"\n" +
" @method select\n" +
" Returns new sequence of same type as this, containing\n" +
" all elements for which given function returned <code>true</code>.\n" +
" @synopsis sequence select(Function selector)\n" +
" @synopsis sequence select(Function selector, object data)\n" +
" @param selector Selector function, either like\n" +
" <code>function selector(element)</code> or\n" +
" <code>function selector(element, data)</code>.\n" +
" @param data Data passed as a second parameter to selector function\n" +
" @return New sequence containing selected elements.\n" +
"\n" +
" @method walk\n" +
" Iterates through the sequence and calls given\n" +
" function at each element. Iteration ends when end of \n" +
" sequence is reached or function returns <code>false</code>.\n" +
" @synopsis object walk(Function walker)\n" +
" @synopsis object walk(Function walker, object data)\n" +
" @param walker Iterator function, either like\n" +
" <code>function walker(element)</code> or\n" +
" <code>function walker(element, data)</code>.\n" +
" @param data Data passed as a second parameter to walker function\n" +
" @return Returns 'data' parameter\n"
//}}DOC
);
}