/*
* $Id: Array.java,v 1.53 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 anvil.script.Context;
import anvil.script.Function;
import anvil.java.util.BindingEnumeration;
import anvil.java.util.HashlistIterator;
import anvil.java.util.Holder;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Writer;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import org.apache.oro.text.regex.Pattern;
import org.apache.oro.text.regex.Perl5Matcher;
/// @class array
/// Array is collections of keys mapped to values. Array
/// has capabilities of list as it also retains doubly linked
/// list of its elements.
///
/// @operator sizeOf
/// Returns the number of elements in this array.
/// @synopsis int sizeof self
///
/// @operator toBoolean
/// <code>true</code> if number of mappings in this array is greater than 0,
/// <code>false</code> otherwise.
/// @synopsis boolean (boolean)self
/// @operator "array[key]"
/// @synopsis object <b>this</b>[object key] ; Returns element at given key
/// @synopsis array <b>this</b>[object start..object end] ; Returns array from given range
/// @synopsis array <b>this</b>[indices...] ; Returns array of elements
/// at given keys and ranges
/// @param key key to array
/// @param start start key of range (included)
/// @param end end key of range (included)
///
/// @operator "array[key] = value"
/// @synopsis <b>this</b>[object key] = object ; Sets the element at given index
/// @synopsis <b>this</b>[object start..object end] = object ; Sets the content of range
/// @synopsis <b>this</b>[object start..object end] = array ; Sets the content of range
/// @param key key to array
/// @param start start key of range (included)
/// @param end end key of range (included)
///
/// @operator "array[] = value"
/// @synopsis <b>this</b>[] = object ; Appends element to end of this sequence
/// @synopsis <b>this</b>[] = map ; Appends mapping to end of this sequence
///
/// @operator "delete array[key]"
/// @synopsis delete <b>this</b>[object key] ; Removes element at given key
/// @synopsis delete <b>this</b>[object start..object end] ; Removes given range
/// @synopsis delete <b>this</b>[indices...] ; Removes keys and ranges
/// @param key key to array
/// @param start start key of range (included)
/// @param end end key of range (included)
///
/// @operator in
/// @synopsis object in <b>this</b> ; Checks if given element is in this array
/// @synopsis map in <b>this</b> ; Checks if given mapping is in this array
///
/// @operator enumeration
/// Returns enumeration of keys and elements in this array
///
public class Array extends Any
{
/// @constructor array
/// Constructs array. Same as builtin <code>[elements, ...]</code> constructor.
/// @synopsis array(object element, ...)
/// @param element If parameter is map, corresponding key and value are
/// added instead of map.
public static final Object[] newInstance = new Object[] { null, "elements" };
public static final Any newInstance(Context context, Any[] list)
{
int n = list.length;
Array array = new Array(n+1);
for(int i=0; i<n; i++) {
array.setReference(context, list[i]);
}
return array;
}
/**
* Array collision list.
*/
class Entry implements Holder
{
int hash;
Any key;
Any value;
Entry next;
Entry prevEntry;
Entry nextEntry;
public Object getKey()
{
return key;
}
public Object getValue()
{
return value;
}
public Object setValue(Object value)
{
Object oldvalue = this.value;
this.value = (Any)value;
return oldvalue;
}
public Object remove()
{
return Array.this.remove(key);
}
}
/**
* A hashlist enumerator class. This class should remain opaque
* to the client. It will use the Enumeration interface.
*/
class ArrayEnumerator implements BindingEnumeration
{
Entry current = null;
boolean keys = false;
ArrayEnumerator(boolean keys)
{
this.keys = keys;
}
public boolean hasMoreElements()
{
Entry e = current;
if (e != null) {
return (e.nextEntry != null);
} else {
return (Array.this.head != null);
}
}
public Object nextElement() {
Entry e = current;
if (e == null) {
current = (e = Array.this.head);
} else {
current = (e = current.nextEntry);
}
if (e == null) {
throw new NoSuchElementException("ArrayEnumerator");
}
return keys ? e.key : e.value;
}
public Object nextKey()
{
Entry e = current;
if (e == null) {
e = Array.this.head;
} else {
e = e.nextEntry;
}
if (e == null) {
throw new NoSuchElementException("ArrayEnumerator");
}
return e.key;
}
}
/**
* A hashlist iterator class.
*/
class Iterator implements HashlistIterator
{
int index;
Entry current;
Entry prev;
Entry next;
protected Iterator()
{
start();
}
public void start()
{
index = -1;
current = null;
prev = null;
next = Array.this.head;
}
public void end()
{
index = Array.this.count;
current = null;
prev = Array.this.tail;
next = null;
}
public boolean hasPrevious()
{
return (prev != null);
}
public boolean hasCurrent()
{
return (current != null);
}
public boolean hasNext()
{
return (next != null);
}
public Object previous()
{
current = prev;
if (current != null) {
index--;
prev = current.prevEntry;
next = current.nextEntry;
return current.value;
} else {
index = -1;
prev = null;
next = Array.this.head;
return null;
}
}
public int previousIndex()
{
if (index > -1) {
return index - 1;
} else {
return -1;
}
}
public Object next()
{
current = next;
if (current != null) {
index++;
prev = current.prevEntry;
next = current.nextEntry;
return current.value;
} else {
index = Array.this.count;
prev = Array.this.tail;
next = null;
return null;
}
}
public int nextIndex()
{
int max = Array.this.count;
if (index < max) {
return index + 1;
} else {
return max;
}
}
public int index()
{
return index;
}
public Object key()
{
return (current != null) ? current.key : null;
}
public Object value()
{
return (current != null) ? current.value : null;
}
public void add(Object value)
{
}
public void remove()
{
/*if (current != null) {
Array.this.remove(current.key);
}*/
}
public void set(Object value)
{
if (current != null) {
current.setValue(value);
}
}
}
/**
* The hash table data.
*/
private transient Entry table[];
/**
* First item in the list
*/
private transient Entry head = null;
/**
* Last item in the list
*/
private transient Entry tail = null;
/**
* The total number of entries in the hash table.
*/
private transient int count;
/**
* Next available integer index.
*/
private int nextSequence = 0;
/**
* Rehashes the table when count exceeds this threshold.
* @serial Integer
*/
private int threshold;
/**
* The load factor for the hashlist.
* @serial Float
*/
private float loadFactor;
/**
* Constructs a new, empty hashlist with the specified initial
* capacity and the specified load factor.
*
* @param initialCapacity the initial capacity of the hashlist.
* @param loadFactor a number between 0.0 and 1.0.
* @exception IllegalArgumentException if the initial capacity is less
* than or equal to zero, or if the load factor is less than
* or equal to zero.
*/
public Array(int initialCapacity, float loadFactor)
{
if (loadFactor <= 0.0) {
loadFactor = 0.75f;
}
if (initialCapacity <= 0) {
initialCapacity = 37;
} else {
initialCapacity = (int)((float)initialCapacity / loadFactor) + 1;
}
this.loadFactor = loadFactor;
table = new Entry[initialCapacity];
threshold = (int)(initialCapacity * loadFactor);
}
/**
* Constructs a new, empty hashlist with the specified initial capacity
* and default load factor.
*
* @param initialCapacity the initial capacity of the hashlist.
*/
public Array(int initialCapacity)
{
this(initialCapacity, 0.75f);
}
/**
* Constructs a new, empty hashlist with a default capacity and load
* factor.
*
*/
public Array()
{
this(37, 0.75f);
}
/**
* Rehashes the contents of the hashlist into a hashlist with a
* larger capacity. This method is called automatically when the
* number of keys in the hashlist exceeds this hashlist's capacity
* and load factor.
*
*/
protected void rehash() {
int oldCapacity = table.length;
Entry oldTable[] = table;
int newCapacity = oldCapacity * 2 + 1;
Entry newTable[] = new Entry[newCapacity];
threshold = (int)(newCapacity * loadFactor);
table = newTable;
for (int i = oldCapacity ; i-- > 0 ;) {
for (Entry old = oldTable[i] ; old != null ; ) {
Entry e = old;
old = old.next;
int index = (e.hash & 0x7FFFFFFF) % newCapacity;
e.next = newTable[index];
newTable[index] = e;
}
}
}
protected void updateSequence(Any key)
{
if (key.typeOf() == IS_INT) {
int i = key.toInt();
if (i >= nextSequence) {
nextSequence = i+1;
}
}
/*case IS_STRING:
AnyString s = (AnyString)key;
key = s.coerce();
if (key.isInt()) {
i = key.toInt();
if (i >= nextSequence) {
nextSequence = i+1;
}
}
}*/
}
/**
* Returns the number of keys in this hashlist.
*
* @return the number of keys in this hashlist.
*/
public int size()
{
return count;
}
/**
* Tests if this hashlist maps no keys to values.
*
* @return <code>true</code> if this hashlist maps no keys to values;
* <code>false</code> otherwise.
*/
public boolean isEmpty()
{
return count == 0;
}
/**
* Returns an enumeration of the keys in this hashlist.
*
* @return an enumeration of the keys in this hashlist.
* @see anvil.core.Array#elements()
*/
public synchronized Enumeration keys()
{
return new ArrayEnumerator(true);
}
/**
* Returns an enumeration of the values in this hashlist.
* Use the Enumeration methods on the returned object to fetch the elements
* sequentially.
*
* @return an enumeration of the values in this hashlist.
* @see anvil.core.Array#keys()
*/
public synchronized Enumeration elements()
{
return new ArrayEnumerator(false);
}
/**
* Returns an enumeration of the values in this hashlist.
* Use the Enumeration methods on the returned object to fetch the elements
* sequentially.
*
* @return an enumeration of the values in this hashlist.
* @see anvil.core.Array#keys()
*/
public synchronized BindingEnumeration keysAndElements()
{
return new ArrayEnumerator(false);
}
/**
* Returns an iterator for hashlist.
* User iterator to browse through the keys and values in the
* insertion order.
*
* @return an iterator for this hashlist.
*/
public synchronized HashlistIterator hashlistIterator()
{
return new Iterator();
}
public synchronized ListIterator listIterator()
{
return new Iterator();
}
public synchronized Iterator iterator()
{
return new Iterator();
}
public boolean containsValue(Any value)
{
return contains(value);
}
/**
* Tests if some key maps into the specified value in this hashlist.
* This operation is more expensive than the <code>containsKey</code>
* method.
*
* @param value a value to search for.
* @return <code>true</code> if some key maps to the
* <code>value</code> argument in this hashlist;
* <code>false</code> otherwise.
* @exception NullPointerException if the value is <code>null</code>.
* @see anvil.core.Array#containsKey(anvil.core.Any)
*/
public synchronized boolean contains(Any value)
{
if (value == null) {
throw new NullPointerException();
}
if (value.isMap()) {
AnyMap range = value.toMap();
Any key = range.getLeft();
value = range.getRight();
Any cand = get(key);
return (cand != null && cand.equals(value));
} else {
Entry tab[] = table;
for (int i = tab.length ; i-- > 0 ;) {
for (Entry e = tab[i] ; e != null ; e = e.next) {
if (e.value.equals(value)) {
return true;
}
}
}
}
return false;
}
/**
* Tests if the specified object is a key in this hashlist.
*
* @param key possible key.
* @return <code>true</code> if the specified object is a key in this
* hashlist; <code>false</code> otherwise.
* @see anvil.core.Array#contains(anvil.core.Any)
*/
public synchronized boolean containsKey(Any key)
{
Entry tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
return true;
}
}
return false;
}
/**
* Returns the entry to which the specified key is mapped in this hashlist.
*
* @param key a key in the hashlist.
* @return the entry to which the key is mapped in this hashlist;
* <code>null</code> if the key is not mapped to any entry in
* this hashlist.
* @see anvil.core.Array#put(anvil.core.Any, anvil.core.Any)
*/
protected synchronized Entry getEntry(Any key) {
Entry tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
return e;
}
}
return null;
}
/**
* Returns the holder to which the specified key is mapped in this hashlist.
*
* @param key a key in the hashlist.
* @return the <code>Holder</code> to which the key is mapped in this hashlist;
* <code>null</code> if the key is not mapped to any entry in
* this hashlist.
* @see anvil.core.Array#put(anvil.core.Any, anvil.core.Any)
*/
public Holder getHolder(Any key)
{
return getEntry(key);
}
/**
* Returns the <code>Holder</code> to which the specified index (Integer)
* is mapped in this hashlist.
*
* @param key an index in the hashlist.
* @return the <code>Holder</code> to which the index is mapped in this hashlist;
* <code>null</code> if the index is not mapped to any <code>Holder</code> in
* this hashlist.
* @see anvil.core.Array#put(anvil.core.Any, anvil.core.Any)
*/
public Holder getHolder(int index)
{
return getEntry(ObjectPool.createInt(index));
}
/**
* Returns the value to which the specified key is mapped in this hashlist.
*
* @param key a key in the hashlist.
* @return the value to which the key is mapped in this hashlist;
* <code>null</code> if the key is not mapped to any value in
* this hashlist.
* @see anvil.core.Array#put(anvil.core.Any, anvil.core.Any)
*/
public synchronized Any get(Any key)
{
Entry tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
return e.value;
}
}
return null;
}
/**
* Returns the Any to which the specified index (Integer) is mapped in this hashlist.
*
* @param key an index in the hashlist.
* @return the <code>Holder</code> to which the index is mapped in this hashlist;
* <code>null</code> if the index is not mapped to any entry in
* this hashlist.
* @see anvil.core.Array#put(anvil.core.Any, anvil.core.Any)
*/
public Any get(int index)
{
return get(ObjectPool.createInt(index));
}
/**
* Maps the specified <code>key</code> to the specified
* <code>value</code> in this hashlist. Neither the key nor the
* value can be <code>null</code>.
* <p>
* The value can be retrieved by calling the <code>get</code> method
* with a key that is equal to the original key.
*
* @param key the hashlist key.
* @param value the value.
* @return the previous value of the specified key in this hashlist,
* or <code>null</code> if it did not have one.
* @exception NullPointerException if the key or value is
* <code>null</code>.
* @see anvil.core.Array#get(anvil.core.Any)
*/
public synchronized Any put(Any key, Any value)
{
// Make sure the value is not null
if (key == null || value == null) {
throw new NullPointerException();
}
// Makes sure the key is not already in the hashlist.
Entry tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
Any old = e.value;
e.value = value;
return old;
}
}
if (count >= threshold) {
// Rehash the table if the threshold is exceeded
rehash();
return put(key, value);
}
updateSequence(key);
// Creates the new entry.
Entry e = new Entry();
e.hash = hash;
e.key = key;
e.value = value;
e.next = tab[index];
e.prevEntry = tail;
e.nextEntry = null;
tab[index] = e;
count++;
if (head == null) {
head = e;
}
if (tail != null) {
tail.nextEntry = e;
}
tail = e;
return null;
}
protected synchronized Any putBefore(Any key, Any value, Entry before)
{
// Make sure the value is not null
if (key == null || value == null) {
throw new NullPointerException();
}
// Makes sure the key is not already in the hashlist.
Entry tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
Any old = e.value;
e.value = value;
return old;
}
}
if (count >= threshold) {
// Rehash the table if the threshold is exceeded
rehash();
return putBefore(key, value, before);
}
updateSequence(key);
// Creates the new entry.
Entry e = new Entry();
e.hash = hash;
e.key = key;
e.value = value;
e.next = tab[index];
tab[index] = e;
count++;
if (before == null) {
before = head;
}
if (before == null) {
e.prevEntry = null;
e.nextEntry = null;
head = tail = e;
} else if (before == head) {
e.prevEntry = null;
e.nextEntry = before;
before.prevEntry = e;
head = e;
} else {
Entry prev = before.prevEntry;
e.prevEntry = prev;
// previous if guarantees that (prev != null)
prev.nextEntry = e;
e.nextEntry = before;
before.prevEntry = e;
}
return null;
}
protected Any putBefore(int index, Any value, Entry entry)
{
return putBefore(ObjectPool.createInt(index), value, entry);
}
protected Any putBefore(Any value, Entry entry)
{
return putBefore(ObjectPool.createInt(nextSequence), value, entry);
}
/**
* Maps the specified <code>key</code> to the specified
* <code>value</code> in this hashlist. Neither the key nor the
* value can be <code>null</code>.
* <p>
* The value can be retrieved by calling the <code>get</code> method
* with a key that is equal to the original key.
*
* @param key the hashlist key.
* @param value the value.
* @return Holder where the key and value were stored
* @exception NullPointerException if the key or value is
* <code>null</code>.
* @see anvil.core.Array#getHolder(anvil.core.Any)
*/
protected synchronized Holder putHolder(Any key, Any value)
{
// Make sure the value is not null
if (key == null || value == null) {
throw new NullPointerException();
}
// Makes sure the key is not already in the hashlist.
Entry tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
e.value = value;
return e;
}
}
if (count >= threshold) {
// Rehash the table if the threshold is exceeded
rehash();
return putHolder(key, value);
}
updateSequence(key);
// Creates the new entry.
Entry e = new Entry();
e.hash = hash;
e.key = key;
e.value = value;
e.next = tab[index];
e.prevEntry = tail;
e.nextEntry = null;
tab[index] = e;
count++;
if (head == null) {
head = e;
}
if (tail != null) {
tail.nextEntry = e;
}
tail = e;
return e;
}
/**
* Maps the specified <code>index</code> to the specified
* <code>value</code> in this hashlist. Neither the index nor the
* value can be <code>null</code>.
* <p>
* The value can be retrieved by calling the <code>get</code> method
* with a key that is equal to the original key.
*
* @param index the hashlist index.
* @param value the value.
* @return the previous value of the specified key in this hashlist,
* or <code>null</code> if it did not have one.
* @exception NullPointerException if the index or value is
* <code>null</code>.
* @see anvil.core.Array#get(int)
*/
public Any put(int index, Any value)
{
return put(ObjectPool.createInt(index), value);
}
/**
* Maps the specified <code>index</code> to the specified
* <code>value</code> in this hashlist. Neither the index nor the
* value can be <code>null</code>.
* <p>
* The value can be retrieved by calling the <code>get</code> method
* with a key that is equal to the original key.
*
* @param index the hashlist index.
* @param value the value.
* @return Holder where key and value were stored
* @exception NullPointerException if the index or value is
* <code>null</code>.
* @see anvil.core.Array#get(java.lang.Integer)
*/
public Holder putHolder(int index, Any value)
{
return putHolder(ObjectPool.createInt(index), value);
}
/**
* Removes the key (and its corresponding value) from this
* hashlist. This method does nothing if the key is not in the hashlist.
*
* @param key the key that needs to be removed.
* @return the value to which the key had been mapped in this hashlist,
* or <code>null</code> if the key did not have a mapping.
*/
public synchronized Any remove(Any key) {
Entry tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry e = tab[index], prev = null ; e != null ; prev = e, e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
if (prev != null) {
prev.next = e.next;
} else {
tab[index] = e.next;
}
if (head == e) {
head = e.nextEntry;
}
if (tail == e) {
tail = e.prevEntry;
}
if (e.nextEntry != null) {
e.nextEntry.prevEntry = e.prevEntry;
}
if (e.prevEntry != null) {
e.prevEntry.nextEntry = e.nextEntry;
}
count--;
return e.value;
}
}
return null;
}
/**
* Clears this hashlist so that it contains no keys.
*
*/
public synchronized void clear()
{
Entry tab[] = table;
for (int index = tab.length; --index >= 0; ) {
tab[index] = null;
}
head = null;
tail = null;
count = 0;
nextSequence = 0;
}
/**
* Creates a shallow copy of this hashlist. The keys and values
* themselves are not cloned.
* This is a rather expensive operation.
*
* @return a clone of the hashlist.
*/
public synchronized Object clone()
{
Entry p = head;
Array a = new Array(table.length, loadFactor);
while(p != null) {
a.put(p.key, p.value);
p = p.nextEntry;
}
return a;
}
/**
* Creates a copy of this array.
*
* @param deep Deep copy
*
* @return a copy of the array.
*/
public synchronized Any copy()
{
Entry p = head;
Array a = new Array(table.length, loadFactor);
while(p != null) {
a.put(p.key, p.value.copy());
p = p.nextEntry;
}
return a;
}
/**
* Returns a rather long string representation of this hashlist.
*
* @return a string representation of this hashlist.
*/
public synchronized String toString()
{
StringBuffer buf = new StringBuffer();
Entry e = head;
boolean first = true;
int max = size() - 1;
buf.append('[');
while(e != null) {
if (first) {
first = false;
} else {
buf.append(',');
buf.append(' ');
}
buf.append(e.key.toString());
buf.append('=');
buf.append(e.value.toString());
e = e.nextEntry;
}
buf.append(']');
return buf.toString();
}
public synchronized Writer toAnvil(Writer writer) throws IOException
{
Entry e = head;
writer.write('[');
while(e != null) {
e.key.toAnvil(writer);
writer.write('=');
writer.write('>');
e.value.toAnvil(writer);
e = e.nextEntry;
if (e != null) {
writer.write(',');
writer.write(' ');
}
}
writer.write(']');
return writer;
}
public synchronized Writer toJava(Writer writer) throws IOException
{
Entry e = head;
writer.write("new anvil.core.Array(");
writer.write(Integer.toString(size()));
writer.write(')');
while(e != null) {
writer.write(".append(");
e.key.toJava(writer);
writer.write(',');
writer.write(' ');
e.value.toJava(writer);
writer.write(')');
e = e.nextEntry;
}
return writer;
}
public anvil.codec.Code toCode(anvil.codec.Code code)
{
anvil.codec.ConstantPool pool = code.getPool();
int clazz = pool.addClass("anvil/core/Array");
code.anew(clazz);
code.dup();
code.iconst(size());
code.invokespecial(pool.addMethodRef(clazz, "<init>", "(I)V"));
Entry e = head;
while(e != null) {
e.key.toCode(code);
e.value.toCode(code);
code.invokevirtual(pool.addMethodRef(clazz, "append", "(Lanvil/core/Any;Lanvil/core/Any;)Lanvil/core/Array;"));
e = e.nextEntry;
}
return code;
}
/**
* Gets the next available integer slot.
*
* @return Sequence
*/
public int getNextSequence()
{
return nextSequence;
}
/**
* List operations
*/
public synchronized Array reverse()
{
Entry entry = head;
Entry next;
Entry tmp;
while(entry != null) {
next = entry.nextEntry;
tmp = entry.nextEntry;
entry.nextEntry = entry.prevEntry;
entry.prevEntry = tmp;
entry = next;
}
tmp = head;
head = tail;
tail = tmp;
return this;
}
public synchronized Array crop(int start, int length)
{
if (length == 0) {
clear();
} else {
int i = start + length;
cut(i, count - i);
if (start > 0) {
cut(0, start);
}
}
return this;
}
protected Entry entryAt(int index)
{
if ((index < 0) || (index >= count)) {
return null;
} else if (index < count/2) {
Entry e = head;
while(e != null) {
if ((index--) <= 0) {
return e;
}
e = e.nextEntry;
}
} else {
index = count - index;
Entry e = tail;
while(e != null) {
if ((--index) <= 0) {
return e;
}
e = e.prevEntry;
}
}
return null;
}
public synchronized int indexOf(Any key)
{
Entry start = getEntry(key);
if (start != null) {
Entry end = start;
int pos = 0;
for(;;) {
pos ++;
start = start.prevEntry;
end = end.prevEntry;
if (start == null) {
return pos - 1;
} else if (end == null) {
return count - pos;
}
}
} else {
return -1;
}
}
public synchronized Holder holderAt(int index)
{
return entryAt(index);
}
public synchronized Any keyAt(int index)
{
Entry e = entryAt(index);
return (e != null) ? e.key : null;
}
public synchronized Any elementAt(int index)
{
Entry e = entryAt(index);
return (e != null) ? e.value : null;
}
public synchronized Array append(Any value)
{
put(nextSequence, value);
return this;
}
public Array append(int index, Any value)
{
put(ObjectPool.createInt(index), value);
return this;
}
public Array append(String index, Any value)
{
put(new AnyString(index), value);
return this;
}
public Array append(Any key, Any value)
{
put(key, value);
return this;
}
public synchronized Array insert(Any value)
{
putBefore(ObjectPool.createInt(nextSequence), value, this.head);
return this;
}
public synchronized Array insert(Any key, Any value)
{
putBefore(key, value, this.head);
return this;
}
public synchronized Array insertAt(int index, Any key, Any value)
{
if (index >= count) {
append(key, value);
} else {
putBefore(key, value, entryAt(index));
}
return this;
}
public synchronized Array insertAt(int index, Any value)
{
if (index >= count) {
append(value);
} else {
putBefore(ObjectPool.createInt(nextSequence), value, entryAt(index));
}
return this;
}
public synchronized Any setAt(int index, Any value)
{
Entry e = entryAt(index);
if (e != null) {
Any old = e.value;
e.value = value;
return old;
} else {
return null;
}
}
public synchronized Any removeAt(int index)
{
Entry e = entryAt(index);
if (e != null) {
return remove(e.key);
} else {
return null;
}
}
public synchronized Holder previousOf(Any index)
{
Entry e = getEntry(index);
if (e != null) {
e = e.prevEntry;
}
return e;
}
public synchronized Holder nextOf(Any index)
{
Entry e = getEntry(index);
if (e != null) {
e = e.nextEntry;
}
return e;
}
public synchronized Any[] toArray(boolean values)
{
Any[] array = new Any[count];
Entry p = head;
int i = 0;
while(p != null) {
array[i++] = values ? p.value : p.key;
p = p.nextEntry;
}
return array;
}
public Array slice(Any start, Any end)
{
return slice(new Array(), start, end);
}
protected boolean isReverseOrder(Entry p, Entry q)
{
if (p != q) {
Entry p0 = p;
Entry q0 = q;
for(;;) {
p0 = p0.nextEntry;
if (p0 == null) {
return true;
}
if (p0 == q) {
return false;
}
q0 = q0.nextEntry;
if (q0 == null) {
return false;
}
if (q0 == p) {
return true;
}
}
}
return false;
}
public synchronized Array slice(Array slice, Any start, Any end)
{
Entry p = (start == null) ? head : getEntry(start);
if (p == null) {
return slice;
}
Entry q = (end == null) ? tail : getEntry(end);
if (q == null) {
return slice;
}
if (isReverseOrder(p, q)) {
for(;;) {
slice.append(p.key, p.value);
if (p==q) {
break;
}
p = p.prevEntry;
}
} else {
for(;;) {
slice.append(p.key, p.value);
if (p==q) {
break;
}
p = p.nextEntry;
}
}
return slice;
}
public Array slice(int start, int length)
{
return slice(new Array(), start, length);
}
public synchronized Array slice(Array array, int start, int length)
{
long l = ArrayUtils.adjust(start, length, count);
start = (int)(l & 0xffffffff);
length = (int)(l >> 32);
if (length > 0) {
if (array == null) {
array = new Array(4 * length / 3);
}
Entry p = entryAt(start);
while(length-- > 0) {
array.put(p.key, p.value);
p = p.nextEntry;
}
return array;
} else {
return array;
}
}
public synchronized boolean cut(int start, int length)
{
long l = ArrayUtils.adjust(start, length, count);
start = (int)(l & 0xffffffff);
length = (int)(l >> 32);
Entry p = entryAt(start);
Entry q;
if (length > 0) {
while(length-- > 0) {
q = p.nextEntry;
remove(p.key);
p = q;
}
return true;
} else {
return false;
}
}
public synchronized boolean cut(Any start, Any end)
{
Entry p = (start == null) ? head : getEntry(start);
if (p == null) {
return false;
}
Entry q = (end == null) ? tail : getEntry(end);
if (q == null) {
return false;
}
if (isReverseOrder(p, q)) {
for(;;) {
Entry prev = p.prevEntry;
remove(p.key);
if (p==q) {
break;
}
p = prev;
}
} else {
for(;;) {
Entry next = p.nextEntry;
remove(p.key);
if (p==q) {
break;
}
p = next;
}
}
return true;
}
public synchronized Array insert(int start, int length, Array array)
{
long l = ArrayUtils.adjust(start, length, count);
start = (int)(l & 0xffffffff);
length = (int)(l >> 32);
Entry p = entryAt(start);
Entry q;
while(length-- > 0) {
q = p.nextEntry;
remove(p.key);
p = q;
}
if (p == null) {
q = array.head;
while(q != null) {
append(q.value);
q = q.nextEntry;
}
} else {
q = array.tail;
while(q != null) {
putBefore(q.value, p);
q = q.prevEntry;
}
}
return this;
}
public synchronized Array insert(Any start, Any end, Any slice)
{
Entry p = (start == null) ? head : getEntry(start);
if (p == null) {
return this;
}
Entry q = (end == null) ? tail : getEntry(end);
if (q == null) {
return this;
}
if (isReverseOrder(p, q)) {
Entry before = p.nextEntry;
for(;;) {
Entry prev = p.prevEntry;
remove(p.key);
if (p==q) {
break;
}
p = prev;
}
if (before != null) {
if (slice.isArray()) {
q = slice.toArray().tail;
while(q != null) {
putBefore(q.key, q.value, before);
q = q.prevEntry;
}
} else {
putBefore(Any.create(getNextSequence()), slice, before);
}
} else {
if (slice.isArray()) {
q = slice.toArray().tail;
while(q != null) {
append(q.key, q.value);
q = q.prevEntry;
}
} else {
append(slice);
}
}
} else {
Entry before = q.nextEntry;
for(;;) {
Entry next = p.nextEntry;
remove(p.key);
if (p==q) {
break;
}
p = next;
}
if (before != null) {
if (slice.isArray()) {
q = slice.toArray().head;
while(q != null) {
putBefore(q.key, q.value, before);
q = q.nextEntry;
}
} else {
putBefore(Any.create(getNextSequence()), slice, before);
}
} else {
if (slice.isArray()) {
q = slice.toArray().head;
while(q != null) {
append(q.key, q.value);
q = q.nextEntry;
}
} else {
append(slice);
}
}
}
return this;
}
public synchronized Array union(Array set)
{
Entry p = set.head;
while(p != null) {
if (!containsKey(p.key)) {
put(p.key, p.value);
}
p = p.nextEntry;
}
return this;
}
public synchronized Array intersect(Array set)
{
Entry p = head;
while(p != null) {
Entry next = p.nextEntry;
if (!set.containsKey(p.key)) {
remove(p.key);
}
p = next;
}
return this;
}
public synchronized Array subtract(Array set)
{
Entry p = set.head;
while(p != null) {
Entry next = p.nextEntry;
if (containsKey(p.key)) {
remove(p.key);
}
p = next;
}
return this;
}
public synchronized Array sort(Comparator comparator, boolean ascending)
{
if (count < 2) {
return this;
}
int i = 0;
int n = count;
Entry[] array = new Entry[n];
Entry p = head;
while(p != null) {
array[i++] = p;
p = p.nextEntry;
}
java.util.Arrays.sort(array, comparator);
n--;
if (ascending) {
for(i=0; i<=n; i++) {
p = array[i];
p.prevEntry = (i>0) ? array[i-1] : null;
p.nextEntry = (i<n) ? array[i+1] : null;
}
head = array[0];
tail = array[n];
} else {
for(i=0; i<=n; i++) {
p = array[i];
p.nextEntry = (i>0) ? array[i-1] : null;
p.prevEntry = (i<n) ? array[i+1] : null;
}
head = array[n];
tail = array[0];
}
return this;
}
/**
* WriteObject is called to save the state of the hashlist to a stream.
* Only the keys and values are serialized since the hash values may be
* different when the contents are restored.
* iterate over the contents and write out the keys and values.
*/
private synchronized void writeObject(java.io.ObjectOutputStream s)
throws IOException
{
// Write out the length, threshold, loadfactor
s.defaultWriteObject();
// Write out length, count of elements and then the key/value objects
s.writeInt(table.length);
s.writeInt(count);
Entry entry = head;
while (entry != null) {
s.writeObject(entry.key);
s.writeObject(entry.value);
entry = entry.nextEntry;
}
}
/**
* readObject is called to restore the state of the hashlist from
* a stream. Only the keys and values are serialized since the
* hash values may be different when the contents are restored.
* Read count elements and insert into the hashlist.
*/
private synchronized void readObject(java.io.ObjectInputStream s)
throws IOException, ClassNotFoundException
{
// Read in the length, threshold, and loadfactor
s.defaultReadObject();
// Read the original length of the array and number of elements
int origlength = s.readInt();
int elements = s.readInt();
// Compute new size with a bit of room 5% to grow but
// No larger than the original size. Make the length
// odd if it's large enough, this helps distribute the entries.
// Guard against the length ending up zero, that's not valid.
int length = (int)(elements * loadFactor) + (elements / 20) + 3;
if (length > elements && (length & 1) == 0)
length--;
if (origlength > 0 && length > origlength)
length = origlength;
table = new Entry[length];
count = 0;
// Read the number of elements and then all the key/value objects
for (; elements > 0; elements--) {
put((Any)s.readObject(), (Any)s.readObject());
}
}
/**
* Serializes this Array to OutputStream.
*
* @return Serialized structure as String
* @throws IOException if something goes wrong
*/
public synchronized void serialize(Serializer serializer) throws IOException
{
if (serializer.register(this)) {
return;
}
Entry p = head;
serializer.write('a');
serializer.write(size());
serializer.write(':');
while (p != null) {
p.key.serialize(serializer);
p.value.serialize(serializer);
p = p.nextEntry;
}
}
public static final Array unserialize(Unserializer unserializer)
throws UnserializationException
{
int size = (int)unserializer.getLong();
Array array = new Array(size);
unserializer.register(array);
for(int i=0; i<size; i++) {
array.put(unserializer.unserialize(), unserializer.unserialize());
}
return array;
}
/******************************************************************/
protected Any _default = null;
public anvil.script.ClassType classOf()
{
return __class__;
}
public int typeOf()
{
return IS_ARRAY;
}
public int sizeOf()
{
return count;
}
public boolean isMutable()
{
return true;
}
public boolean isArray()
{
return true;
}
public boolean toBoolean()
{
return count > 0;
}
public Array toArray()
{
return this;
}
public Object toObject()
{
return this;
}
public int hashCode()
{
Entry e = head;
int h = 0;
int i = 1;
while(e != null) {
h ^= (i++) * (e.key.hashCode() + e.value.hashCode());
e = e.nextEntry;
}
return h;
}
private synchronized boolean equalsTo(Array b)
{
Array a = this;
if (a.count == b.count) {
Entry ae = a.head;
Entry be = b.head;
while(ae != null && be != null) {
if (!ae.key.equals(be.key)) {
return false;
}
if (!ae.value.equals(be.value)) {
return false;
}
ae = ae.nextEntry;
be = be.nextEntry;
}
return true;
} else {
return false;
}
}
public synchronized int compareTo(Array b)
{
Array a = this;
int an = a.count;
int bn = b.count;
int delta;
Entry ae = a.head;
Entry be = b.head;
while(ae != null && be != null) {
delta = ae.key.compareTo(be.key);
if (delta != 0) {
return (delta < 0) ? -1 : 1;
}
delta = ae.value.compareTo(be.value);
if (delta != 0) {
return (delta < 0) ? -1 : 1;
}
ae = ae.nextEntry;
be = be.nextEntry;
}
if (an == bn) {
return 0;
} else if (an < bn) {
return -1;
} else {
return 1;
}
}
public boolean equals(Object obj)
{
if (this == obj) {
return true;
}
if (obj instanceof Array) {
return equalsTo((Array)obj);
}
return false;
}
protected int compare(Any other)
{
return compareTo(other.toArray());
}
public Any getAttribute(Context context, String attribute)
{
Any value = (Any)get(Any.create(attribute));
if (value != null) {
return value;
} else {
if (_default != null) {
return _default;
} else {
return Any.UNDEFINED;
}
}
}
public Any setAttribute(Context context, String attribute, Any value)
{
put(Any.create(attribute), value);
return value;
}
public Any checkAttribute(Context context, String attribute)
{
Any value = (Any)get(Any.create(attribute));
return (value != null) ? value :
((_default != null) ? _default : Any.UNDEFINED);
}
public boolean deleteAttribute(Context context, String attribute)
{
Holder holder = getHolder(Any.create(attribute));
if (holder != null) {
holder.remove();
return true;
} else {
return false;
}
}
private int positionOf(Any index, boolean left)
{
if (!index.isDefined()) {
return left ? 0 : this.count;
}
return indexOf(index);
}
private Array getRef(Array array, Any index)
{
switch(index.typeOf()) {
case IS_RANGE:
AnyRange range = index.toRange();
Any l = range.getLeft();
Any r = range.getRight();
return slice(array, l.isDefined() ? l : null, r.isDefined() ? r : null);
case IS_TUPLE:
case IS_LIST:
Any[] list = index.toTuple();
int n = index.sizeOf();
for(int i=0; i<n; i++) {
getRef(array, list[i]);
}
return array;
default:
Entry e = getEntry(index);
if (e != null) {
array.put(e.key, e.value);
}
return array;
}
}
public Any getReference(Context context, Any index)
{
if (index.isRange() || index.isTuple()) {
return getRef(new Array(), index);
}
Any value = get(index);
if (value != null) {
return value;
} else {
if (_default != null) {
return _default;
} else {
return UNDEFINED;
}
}
}
public Any checkReference(Context context, Any index)
{
return getReference(context, index);
}
public Any setReference(Context context, Any index, Any value)
{
if (index.isRange()) {
AnyRange range = index.toRange();
Any left = range.getLeft();
Any right = range.getRight();
insert(left.isDefined() ? left : null,
right.isDefined() ? right : null, value);
} else {
put(index, value);
}
return value;
}
public Any setReference(Context context, Any value)
{
if (value.isMap()) {
AnyMap map = value.toMap();
append(map.getLeft(), map.getRight());
} else {
append(value);
}
return value;
}
private void deleteRef(Any index)
{
switch(index.typeOf()) {
case IS_RANGE:
AnyRange range = index.toRange();
Any l = range.getLeft();
Any r = range.getRight();
cut(l.isDefined() ? l : null, r.isDefined() ? r : null);
break;
case IS_TUPLE:
case IS_LIST:
Any[] list = index.toTuple();
final int n = index.sizeOf();
for(int i=0; i<n; i++) {
deleteRef(list[i]);
}
return;
default:
remove(index);
return;
}
}
public boolean deleteReference(Context context, Any index)
{
if (index.isRange() || index.isTuple()) {
deleteRef(index);
}
Holder holder = getHolder(index);
if (holder != null) {
holder.remove();
return true;
} else {
return false;
}
}
public BindingEnumeration enumeration()
{
return keysAndElements();
}
public Any execute(Context context, Any[] parameters)
{
Any rv = Any.UNDEFINED;
Entry e = head;
while(e != null) {
rv = e.value.execute(context, parameters);
e = e.nextEntry;
}
return rv;
}
public Any execute(Context context)
{
Any rv = Any.UNDEFINED;
Entry e = head;
while(e != null) {
rv = e.value.execute(context);
e = e.nextEntry;
}
return rv;
}
public Any execute(Context context, Any param1)
{
Any rv = Any.UNDEFINED;
Entry e = head;
while(e != null) {
rv = e.value.execute(context, param1);
e = e.nextEntry;
}
return rv;
}
public Any execute(Context context, Any param1, Any param2)
{
Any rv = Any.UNDEFINED;
Entry e = head;
while(e != null) {
rv = e.value.execute(context, param1, param2);
e = e.nextEntry;
}
return rv;
}
public Any execute(Context context, Any param1, Any param2, Any param3)
{
Any rv = Any.UNDEFINED;
Entry e = head;
while(e != null) {
rv = e.value.execute(context, param1, param2, param3);
e = e.nextEntry;
}
return rv;
}
public Any execute(Context context, Any param1, Any param2, Any param3, Any param4)
{
Any rv = Any.UNDEFINED;
Entry e = head;
while(e != null) {
rv = e.value.execute(context, param1, param2, param3, param4);
e = e.nextEntry;
}
return rv;
}
/********* Exposed methods ************/
/// @method size
/// Returns the number of elements in array
/// @synopsis int size()
/// @return Number of elements
public Any m_size()
{
return Any.create(size());
}
/// @method sizeOf
/// Returns the number of elements in array
/// @synopsis int sizeOf()
/// @return Number of elements
public Any m_sizeOf()
{
return Any.create(size());
}
/// @method clear
/// Removess all mappings from this array.
/// @synopsis array clear()
/// @return this array cleared
public Any m_clear()
{
clear();
return this;
}
/// @method iterator
/// Returns an iterator for this array.
/// @synopsis iterator iterator()
public Any m_iterator()
{
return Any.create(hashlistIterator());
}
/// @method elements
/// Returns an enumeration of values in this array.
/// @synopsis enumeration elements()
public Any m_elements()
{
return new AnyBindingEnumeration(new IndexedEnumeration(elements()));
}
/// @method keys
/// Returns an enumeration of keys in this array.
/// @synopsis enumeration keys()
public Any m_keys()
{
return new AnyBindingEnumeration(new IndexedEnumeration(keys()));
}
/// @method keysAndElements
/// Returns an enumeration of keys and values in this array.
/// @synopsis enumeration keysAndElements()
public Any m_keysAndElements()
{
return new AnyBindingEnumeration(keysAndElements());
}
/// @method join
/// Joins the string representation of mapped values in this array
/// together with given clue.
/// @synopsis string join()
/// @synopsis string join(string clue)
/// @param clue Separator between values
public static final Object[] p_join = new Object[] { "*clue", null };
public synchronized Any m_join(String clue)
{
if (clue == null) {
clue = ", ";
}
StringBuffer buffer = new StringBuffer();
boolean first = true;
Entry e = head;
while(e != null) {
if (clue != null) {
if (first) {
first = false;
} else {
buffer.append(clue);
}
}
buffer.append(e.value.toString());
e = e.nextEntry;
}
return new AnyString(buffer.toString());
}
/// @method push
/// For each parameter, inserts the value or mapping into
/// the end of this array.
/// @synopsis array push(map mapping, ...)
/// @synopsis array push(object element, ...)
public static final Object[] p_push = new Object[] { "element", "elements" };
public Any m_push(Any element, Any[] elements)
{
if (element.isMap()) {
AnyMap m = element.toMap();
append(m.getLeft(), m.getRight());
} else {
append(element);
}
int n = elements.length;
for(int i=0; i<n; i++) {
Any a = elements[i];
if (a.isMap()) {
AnyMap m = a.toMap();
append(m.getLeft(), m.getRight());
} else {
append(a);
}
}
return this;
}
/// @method pop
/// Removes the last mapping from this array and
/// returns the value mapped.
/// @synopsis object pop()
public static final Object[] p_pop = new Object[] { "*index", null };
public Any m_pop(Any index)
{
if (index != null) {
Any removed = remove(index);
return (removed != null) ? removed : UNDEFINED;
} else {
int size = count;
if (size > 0) {
return removeAt(size - 1);
} else {
return UNDEFINED;
}
}
}
/// @method shift
/// Removes the first mapping from this array and
/// returns the value mapped.
/// @synopsis object shift()
public Any m_shift()
{
if (size() > 0) {
return removeAt(0);
} else {
return UNDEFINED;
}
}
/// @method unshift
/// For each parameter, inserts the value or mapping into
/// the start of this array.
/// @synopsis array unshift(map mapping, ...)
/// @synopsis array unshift(object value, ...)
/// @param mapping Mapping to add
/// @param value Value to add
/// @return this array modified
public static final Object[] p_unshift = new Object[] { "elements" };
public Any m_unshift(Any[] elements)
{
int n = elements.length;
for(int i=0; i<n; i++) {
Any a = elements[i];
if (a.isMap()) {
AnyMap m = a.toMap();
insert(m.getLeft(), m.getRight());
} else {
insert(a);
}
}
return this;
}
/// @method reverse
/// Reverses to order of mappings in this array.
/// @synopsis array reverse()
/// @return this array reversed
public Any m_reverse()
{
reverse();
return this;
}
/// @method getKeys
/// Returns list of keys in this array.
/// @synopsis list getKeys()
public synchronized Any m_getKeys()
{
Any[] list = new Any[count];
Entry e = head;
int i = 0;
while(e != null) {
list[i++] = e.value;
e = e.nextEntry;
}
return new AnyList(list);
}
/// @method getElements
/// Returns list of values in this array.
/// @synopsis list getElements()
public synchronized Any m_getElements()
{
Any[] list = new Any[count];
Entry e = head;
int i = 0;
while(e != null) {
list[i++] = e.value;
e = e.nextEntry;
}
return new AnyList(list);
}
/// @method walk
/// Iterates through this array and calls given
/// function at each mapping. Iteration ends when end of
/// array is reached or function returns <code>false</code>.
/// @synopsis array walk(Function callable, object data)
/// @synopsis object walk(Function walker)
/// @synopsis object walk(Function walker, object data)
/// @param walker Iterator function, either like
/// <code>function walker(key, value)</code> or
/// <code>function walker(key, value, 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 synchronized Any m_walk(Context context, Any callable, Any data)
{
Entry e = head;
int i = 0;
while(e != null) {
if (!callable.execute(
context, e.value, e.key, Any.create(i++), data).toBoolean()) {
break;
}
e = e.nextEntry;
}
return data;
}
/// @method select
/// Returns new array containing all mappings for which given function
/// returned <code>true</code>.
/// @synopsis array select(Function selector)
/// @synopsis array select(Function selector, object data)
/// @param selector Selector function, either like
/// <code>function selector(key, value)</code> or
/// <code>function selector(key, value, data)</code>.
/// @param data Data passed as a second parameter to selector function
/// @return New array containing selected elements.
public static final Object[] p_select = new Object[] { null, "selector", "*data", UNDEFINED };
public synchronized Any m_select(Context context, Any callable, Any data)
{
int i = 0;
Entry e = head;
Array selected = new Array();
while(e != null) {
if (selected.execute(context, e.value, e.key, Any.create(i++), data).toBoolean()) {
selected.append(e.key, e.value);
}
e = e.nextEntry;
}
return selected;
}
/// @method slice
/// Return mappings from given range.
/// @synopsis array slice(int start, int length)
/// @param start Start index
/// @param length Length of range
/// @return Mappings from given range
public static final Object[] p_slice = new Object[] { "start", "length" };
public Any m_slice(int start, int length)
{
return slice(new Array(), start, length);
}
/// @method cut
/// Removes given range from this array.
/// @synopsis array cut(int start, int length)
/// @param start Start index
/// @param length Length of range
/// @return this array modified
public static final Object[] p_cut = new Object[] { "start", "length" };
public Any m_cut(int start, int length)
{
cut(start, length);
return this;
}
/// @method crop
/// Contract this array to containg only given range.
/// @synopsis array crop(int start, int length)
/// @param start Start index
/// @param length Length of range
/// @return this array modified
public static final Object[] p_crop = new Object[] { "start", "length" };
public Any m_crop(int start, int length)
{
crop(start, length);
return this;
}
/// @method append
/// Append given value into this array.
/// @synopsis array append(object value)
/// @return this array modified
public static final Object[] p_append = new Object[] { "element", "elements" };
public Any m_append(Any element, Any[] elements)
{
append(element);
int n = elements.length;
for(int i=0; i<n; i++) {
append(elements[i]);
}
return this;
}
/// @method concat
/// Appends value or values of array into this array.
/// @synopsis array concat(array values)
/// @synopsis array concat(map mapping)
/// @synopsis array concat(object element)
/// @return this array modified
public static final Object[] p_concat = new Object[] { "element" };
public Any m_concat(Any value)
{
if (value.isArray()) {
Enumeration e = value.toArray().elements();
while(e.hasMoreElements()) {
append((Any)e.nextElement());
}
} else if (value.isMap()) {
AnyMap map = value.toMap();
append(map.getLeft(), map.getRight());
} else {
append(value);
}
return this;
}
/// @method insert
/// Inserts the mapped values of given array into given range in this array.
/// @synopsis array insert(int start, array values)
/// @synopsis array insert(int start, map mapping)
/// @synopsis array insert(int start, object element)
/// @synopsis array insert(int start, int length, array values)
/// @synopsis array insert(int start, int length, map mapping)
/// @synopsis array insert(int start, int length, object element)
/// @param values Values to insert
/// @param start Start index in this array
/// @param length Length of range to overwrite
/// @return this array modified
public static final Object[] p_insert = new Object[] { "start", "elementOrLength", "*element", null };
public Any m_insert(int start, Any p, Any insert)
{
int length = 0;
if (insert == null) {
insert = p;
} else {
length = p.toInt();
}
if (insert.isArray()) {
insert(start, length, insert.toArray());
} else if (insert.isMap()) {
AnyMap map = insert.toMap();
cut(start, length);
insertAt(start, map.getLeft(), map.getRight());
} else {
cut(start, length);
insertAt(start, insert);
}
return this;
}
/// @method union
/// Merges the keys and values. Existing values in this array are not overridden.
/// @synopsis array union(array set)
/// @param set Array to merge with
/// @return this array modified
public static final Object[] p_union = new Object[] { "set" };
public Any m_union(Any array)
{
if (array.isArray()) {
union(array.toArray());
}
return this;
}
/// @method intersect
/// Removes mappings whose key does not appear in both this array
/// and given set.
/// @synopsis array intersect(array set)
/// @param set Set of mappings
/// @return this array modified
public static final Object[] p_intersect = new Object[] { "set" };
public Any m_intersect(Any array)
{
if (array.isArray()) {
intersect(array.toArray());
}
return this;
}
/// @method subtract
/// Subtract mappings with the same keys as in given set.
/// @synopsis array subtract(array set)
/// @param set Set of mappings.
/// @return this array subtracted
public static final Object[] p_subtract = new Object[] { "set" };
public Any m_subtract(Any array)
{
if (array.isArray()) {
subtract(array.toArray());
}
return this;
}
/// @method pos
/// Return the index of mappping with given key.
/// @synopsis int pos(object key)
/// @return Index to array
public static final Object[] p_pos = new Object[] { "key" };
public Any m_pos(Any key)
{
return Any.create(indexOf(key));
}
/// @method key
/// Returns the mapped key at given index.
/// @synopsis object key(int index)
/// @param index Index to array
public static final Object[] p_key = new Object[] { "index" };
public Any m_key(int index)
{
return Any.create(keyAt(index));
}
/// @method value
/// Returns the mapped value at given index.
/// @synopsis object value(int index)
/// @param index Index to array
public static final Object[] p_value = new Object[] { "index" };
public Any m_value(int index)
{
return Any.create(elementAt(index));
}
private Any toMap(Holder holder)
{
if (holder != null) {
return new AnyMap(Any.create(holder.getKey()),
Any.create(holder.getValue()));
} else {
return UNDEFINED;
}
}
/// @method each
/// Returns mapping at given index.
/// @synopsis map each(int index)
/// @param index Index to array
public static final Object[] p_each = new Object[] { "index" };
public Any m_each(int index)
{
return toMap(holderAt(index));
}
/// @method first
/// Returns the first mapping in this array.
/// @synopsis map first()
public Any m_first()
{
return toMap(head);
}
/// @method firstKey
/// Returns the key of first mapping in this array.
/// @synopsis object firstKey()
public Any m_firstKey()
{
Entry first = head;
if (first != null) {
return first.key;
} else {
return UNDEFINED;
}
}
/// @method firstValue
/// Returns the value of first mapping in this array.
/// @synopsis object firstValue()
public Any m_firstValue()
{
Entry first = head;
if (first != null) {
return first.value;
} else {
return UNDEFINED;
}
}
/// @method last
/// Returns the last mapping in this array.
/// @synopsis map last()
public Any m_last()
{
return toMap(tail);
}
/// @method lastKey
/// Returns the key of last mapping in this array.
/// @synopsis object lastKey()
public Any m_lastKey()
{
Entry last = tail;
if (tail != null) {
return tail.key;
} else {
return UNDEFINED;
}
}
/// @method lastValue
/// Returns the value of last mapping in this array.
/// @synopsis object lastValue()
public Any m_lastValue()
{
Entry last = tail;
if (tail != null) {
return tail.value;
} else {
return UNDEFINED;
}
}
/// @method next
/// Return the next mapping of mapping
/// mapped with given key.
/// @synopsis map next(object ofKey)
public static final Object[] p_next = new Object[] { "ofKey" };
public Any m_next(Any key)
{
if (key.isMap()) {
key = key.toMap().getLeft();
}
Holder holder = nextOf(key);
return (holder != null) ? toMap(holder) : UNDEFINED;
}
/// @method nextKey
/// Return the key of next mapping of mapping
/// mapped with given key.
/// @synopsis object nextKey(object ofKey)
public static final Object[] p_nextKey = new Object[] { "ofKey" };
public Any m_nextKey(Any key)
{
if (key.isMap()) {
key = key.toMap().getLeft();
}
Holder holder = nextOf(key);
return (holder != null) ? (Any)holder.getKey() : UNDEFINED;
}
/// @method nextValue
/// Return the value of next mapping of mapping
/// mapped with given key.
/// @synopsis object nextValue(object ofKey)
public static final Object[] p_nextValue = new Object[] { "ofKey" };
public Any m_nextValue(Any key)
{
if (key.isMap()) {
key = key.toMap().getLeft();
}
Holder holder = nextOf(key);
return (holder != null) ? (Any)holder.getValue() : UNDEFINED;
}
/// @method previous
/// Return the previous mapping of mapping
/// mapped with given key.
/// @synopsis map previous(object ofKey)
public static final Object[] p_previous = new Object[] { "ofKey" };
public Any m_previous(Any key)
{
if (key.isMap()) {
key = key.toMap().getLeft();
}
Holder holder = previousOf(key);
return (holder != null) ? toMap(holder) : UNDEFINED;
}
/// @method previousKey
/// Return the key of previous mapping of mapping
/// mapped with given key.
/// @synopsis object previousKey(object ofKey)
/// @param ofKey Key to array
public static final Object[] p_previousKey = new Object[] { "ofKey" };
public Any m_previousKey(Any key)
{
if (key.isMap()) {
key = key.toMap().getLeft();
}
Holder holder = previousOf(key);
return (holder != null) ? (Any)holder.getKey() : UNDEFINED;
}
/// @method previousValue
/// Return the value of previous mapping of mapping
/// mapped with given key.
/// @synopsis object previousValue(object ofKey)
/// @param ofKey Key to array
public static final Object[] p_previousValue = new Object[] { "ofKey" };
public Any m_previousValue(Any key)
{
if (key.isMap()) {
key = key.toMap().getLeft();
}
Holder holder = previousOf(key);
return (holder != null) ? (Any)holder.getValue() : UNDEFINED;
}
/// @method sortByKey
/// Sorts this array according to keys.
/// @synopsis array sortByKey()
/// @synopsis array sortByKey(boolean asceding)
/// @boolean asceding if <code>true</code> array is sorted into asceding order,
/// otherwise desceding.
/// @return this array sorted
public static final Object[] p_sortByKey = new Object[] { "*ascending", Boolean.TRUE };
public Any m_sortByKey(boolean ascending)
{
sort(AnyUtils.COMPARE_BY_KEY, ascending);
return this;
}
/// @method sortByValue
/// Sorts this array according to mapped values.
/// @synopsis array sortByValue()
/// @synopsis array sortByValue(boolean asceding)
/// @boolean asceding if <code>true</code> array is sorted into asceding order,
/// otherwise desceding.
/// @return this array sorted
public static final Object[] p_sortByValue = new Object[] { "*ascending", Boolean.TRUE };
public Any m_sortByValue(boolean ascending)
{
sort(AnyUtils.COMPARE_BY_VALUE, ascending);
return this;
}
///
/// @method sort
/// Sorts this array.
/// @synopsis array sort(Function comparator)
/// @synopsis array sort(Function comparator, object data)
/// @param comparator Comparator function
/// <code>function comparator(key1, elem1, key2, elem2)</code>,
/// or <code>function comparator((key1, elem1, key2, elem2, data)</code>. Function should
/// return less than 0 if <code>elem1<elem2</code>, 0 if <code>elem1==elem2</code> or
/// more than 0 if <code>elem1>elem2</code>.
/// @param data Data passed as a fifth parameter to searching function
/// @return this array sorted
public static final Object[] p_sort = new Object[] { null, "comparator", "*data", UNDEFINED };
public Any m_sort(Context context, Any comparator_, Any data)
{
Comparator comparator = new AnyUtils.ArrayComparator(context, comparator_, data);
sort(comparator, true);
return this;
}
/// @method find
/// Finds and returns the key of first mapping whose value
/// was equal to given parameter.
/// @synopsis array find(object value)
/// @param value Value to search for
/// @return Key of matched mapping, or <code>undefined</code>.
public static final Object[] p_find = new Object[] { "value" };
public synchronized Any m_find(Any value)
{
Entry e = head;
while(e != null) {
if (e.value.equals(value)) {
return e.key;
}
e = e.nextEntry;
}
return UNDEFINED;
}
/// @method findAll
/// Finds and returns all mappings whose value was equal to given parameter.
/// @synopsis array findAll(object value)
/// @param value Value to search for
/// @return Array containing matched mappings
public static final Object[] p_findAll = new Object[] { "value" };
public synchronized Any m_findAll(Any value)
{
Array array = new Array();
Entry e = head;
while(e != null) {
if (e.value.equals(value)) {
array.append(e.key, e.value);
}
e = e.nextEntry;
}
return array;
}
private synchronized Any grep(Context context, Any keyPattern, Any valuePattern, boolean both)
{
boolean match;
Pattern kpattern = ObjectPool.createPattern(context, keyPattern);
Pattern vpattern = ObjectPool.createPattern(context, valuePattern);
if ((kpattern != null) || (vpattern != null)) {
Perl5Matcher matcher = new Perl5Matcher();
Array matched = new Array();
Entry e = head;
while(e != null) {
Any key = e.key;
Any value = e.value;
if (kpattern != null) {
match = matcher.contains(key.toString(), kpattern);
} else {
match = false;
}
if (vpattern != null) {
if (both) {
match = match && matcher.contains(value.toString(), vpattern);
} else if (!match) {
match = matcher.contains(value.toString(), vpattern);
}
}
if (match) {
matched.put(key, value);
}
e = e.nextEntry;
}
return matched;
} else {
return NULL;
}
}
/// @method grep
/// Returns new array containing all mappings whose
/// key and/or value matched given regular expressions.
/// @synopsis array grep(pattern keyPattern)
/// @synopsis array grep(string keyPattern)
/// @synopsis array grep(pattern keyPattern, pattern valuePattern [, boolean matchBoth])
/// @synopsis array grep(string keyPattern, string valuePattern [, boolean matchBoth] )
/// @param keyPattern Regular expression to match keys with
/// @param valuePattern Regular expression to match values with
/// @param matchBoth if <code>true</code> both key and value is required to match.
/// @return New array containing selected mappings
/// @throws MalformedPattern If any of patterns where invalid
public static final Object[] p_grep = new Object[]
{ null, "keyPattern", "*valuePattern", null, "*matchBoth", Boolean.FALSE };
public Any m_grep(Context context, Any key, Any value, boolean both)
{
return grep(context, key, value, both);
}
/// @method grepKeys
/// Returns new array containing all mappings whose
/// key matched matched given regular expression.
/// @synopsis array grepKeys(pattern pattern)
/// @synopsis array grepKeys(string pattern)
/// @param pattern Regular expression to match with
/// @return New array containing selected mappings
/// @throws MalformedPattern If pattern was invalid
public static final Object[] p_grepKeys = new Object[] { null, "pattern" };
public Any m_grepKeys(Context context, Any pattern)
{
return grep(context, pattern, null, false);
}
/// @method grepValues
/// Returns new array containing all mappings whose
/// value matched matched given regular expression.
/// @synopsis array grepValues(pattern pattern)
/// @synopsis array grepValues(string pattern)
/// @param pattern Regular expression to match with
/// @return New array containing selected mappings
/// @throws MalformedPattern If pattern was invalid
public static final Object[] p_grepValues = new Object[] { null, "pattern" };
public Any m_grepValues(Context context, Any pattern)
{
return grep(context, null, pattern, false);
}
private synchronized Any[] findMinMax(boolean fromKey)
{
Any min = UNDEFINED;
Any max = UNDEFINED;
boolean first = true;
Entry e = head;
Any value;
while(e != null) {
if (fromKey) {
value = e.key;
} else {
value = e.value;
}
if (first) {
min = max = value;
first = false;
} else {
if (value.compareTo(min) < 0) {
min = value;
} else if (value.compareTo(max) > 0) {
max = value;
}
}
e = e.nextEntry;
}
return new Any[] { min, max };
}
/// @method minmax
/// Finds and returns minimum and maximum value from this array.
/// @synopsis tuple minmax()
/// @return tuple containing <code>(minElement, maxElement)</code>
public Any m_minmax()
{
return new AnyTuple(findMinMax(false));
}
/// @method minmaxKeys
/// Finds and returns minimum and maximum key from this array.
/// @synopsis tuple minmaxKeys()
/// @return tuple containing <code>(minKey, maxKey)</code>
public Any m_minmaxKeys()
{
return new AnyTuple(findMinMax(true));
}
/// @method setDefault
/// Sets the default value that will be returned if non-existent
/// key is acccessed.
/// @synopsis array setDefault(object defaultValue)
/// @return this array
public static final Object[] p_setDefault = new Object[] { "value" };
public Any m_setDefault(Any value)
{
_default = value;
return this;
}
/// @method getDefault
/// Gets the default value returned if non-existent
/// key is acccessed.
/// @synopsis object getDefault()
public Any m_getDefault()
{
if (_default == null) {
return Any.UNDEFINED;
} else {
return _default;
}
}
/// @method enqueue
/// Adds given element to end of array.
/// @synopsis array enqueue(object element)
/// @synopsis array enqueue(object key, object element)
/// @param element Element to add
public static final Object[] p_enqueue = new Object[] { "p", "*q", null };
public Any m_enqueue(Any p, Any q)
{
if (q == null) {
put(Any.create(getNextSequence()), p);
} else {
Entry e = getEntry(p);
if (e != null) {
e.remove();
}
put(p, q);
}
return this;
}
/// @method dequeue
/// Removes and returns first <code>key=>value</code>
/// from this array.
/// @synopsis map dequeue()
public synchronized Any m_dequeue()
{
Entry e = head;
if (e != null) {
AnyTuple list = new AnyTuple(new Any[] { e.key, e.value } );
e.remove();
return list;
}
return NULL;
}
/// @method get
/// Fetches value from multi dimensional array. (i.e. array
/// containing nested arrays). If missing key is encountered
/// <code>undefined</code> is returned.
/// @synopsis object get(object key1, ...)
public static final Object[] p_get = new Object[] { "indices" };
public Any m_get(Any[] parameters)
{
int n = parameters.length;
Any self = this;
int i=0;
Any key;
while(i<n) {
if (self.isArray()) {
key = parameters[i];
Array a = self.toArray();
self = a.get(key);
if (self == null) {
return UNDEFINED;
}
} else {
return UNDEFINED;
}
i++;
}
return self;
}
/// @method set
/// Sets value at given multi-dimensional array (i.e. array
/// containing nested array). If missing key is encountered
/// arrays remain unchanged.
/// @synopsis object set(object key1, ..., object value)
/// @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, "array.set");
}
Any value = parameters[n-1];
Any self = this;
int i=0;
Any key;
while(i<n-2) {
if (self.isArray()) {
key = parameters[i];
Array a = self.toArray();
self = a.get(key);
if (self == null) {
self = new Array();
a.put(key, self);
}
} else {
return value;
}
i++;
}
if (self.isArray()) {
self.toArray().put(parameters[i], value);
}
return value;
}
/// @method swap
/// Swaps the values pointed by given keys.
/// @synopsis array swap(object key1, object key2)
/// @return this array
public static final Object[] p_swap = new Object[] { "key1", "key2" };
public synchronized Any m_swap(Any key1, Any key2)
{
Entry e = getEntry(key1);
if (e != null) {
Entry f = getEntry(key2);
if (f != null) {
Any value = e.value;
e.value = f.value;
f.value = value;
}
}
return this;
}
/// @method swapOrder
/// Swaps order the mappings pointed by given keys.
/// @synopsis array swapOrder(object key1, object key2)
/// @return this array
public static final Object[] p_swapOrder = new Object[] { "key1", "key2" };
public synchronized Any m_swapOrder(Any key1, Any key2)
{
Entry e = getEntry(key1);
if (e != null) {
Entry f = getEntry(key1);
if (f != null && e != f) {
Entry e_prev = e.prevEntry;
Entry e_next = e.nextEntry;
Entry f_prev = f.prevEntry;
Entry f_next = f.nextEntry;
if (e_prev != null) {
e_prev.nextEntry = f;
} else {
head = f;
}
if (e_next != null) {
e_next.prevEntry = f;
} else {
tail = f;
}
if (f_prev != null) {
f_prev.nextEntry = e;
} else {
head = e;
}
if (f_next != null) {
f_next.prevEntry = e;
} else {
tail = e;
}
e.prevEntry = (f_prev!=e) ? f_prev : f;
e.nextEntry = (f_next!=e) ? f_next : f;
f.prevEntry = (e_prev!=f) ? e_prev : e;
f.nextEntry = (e_next!=f) ? e_next : e;
}
}
return this;
}
public static final anvil.script.compiler.NativeClass __class__ =
new anvil.script.compiler.NativeClass("array", Array.class,
//DOC{{
""+
" @class array\n" +
" Array is collections of keys mapped to values. Array \n" +
" has capabilities of list as it also retains doubly linked\n" +
" list of its elements.\n" +
"\n" +
" @operator sizeOf\n" +
" Returns the number of elements in this array.\n" +
" @synopsis int sizeof self\n" +
"\n" +
" @operator toBoolean\n" +
" <code>true</code> if number of mappings in this array is greater than 0, \n" +
" <code>false</code> otherwise.\n" +
" @synopsis boolean (boolean)self\n" +
" @operator \"array[key]\"\n" +
" @synopsis object <b>this</b>[object key] ; Returns element at given key\n" +
" @synopsis array <b>this</b>[object start..object end] ; Returns array from given range\n" +
" @synopsis array <b>this</b>[indices...] ; Returns array of elements\n" +
" at given keys and ranges\n" +
" @param key key to array \n" +
" @param start start key of range (included) \n" +
" @param end end key of range (included)\n" +
"\n" +
" @operator \"array[key] = value\"\n" +
" @synopsis <b>this</b>[object key] = object ; Sets the element at given index\n" +
" @synopsis <b>this</b>[object start..object end] = object ; Sets the content of range\n" +
" @synopsis <b>this</b>[object start..object end] = array ; Sets the content of range\n" +
" @param key key to array \n" +
" @param start start key of range (included) \n" +
" @param end end key of range (included)\n" +
"\n" +
" @operator \"array[] = value\"\n" +
" @synopsis <b>this</b>[] = object ; Appends element to end of this sequence\n" +
" @synopsis <b>this</b>[] = map ; Appends mapping to end of this sequence\n" +
"\n" +
" @operator \"delete array[key]\"\n" +
" @synopsis delete <b>this</b>[object key] ; Removes element at given key\n" +
" @synopsis delete <b>this</b>[object start..object end] ; Removes given range\n" +
" @synopsis delete <b>this</b>[indices...] ; Removes keys and ranges\n" +
" @param key key to array \n" +
" @param start start key of range (included) \n" +
" @param end end key of range (included)\n" +
"\n" +
" @operator in\n" +
" @synopsis object in <b>this</b> ; Checks if given element is in this array\n" +
" @synopsis map in <b>this</b> ; Checks if given mapping is in this array\n" +
"\n" +
" @operator enumeration\n" +
" Returns enumeration of keys and elements in this array\n" +
"\n" +
" @constructor array\n" +
" Constructs array. Same as builtin <code>[elements, ...]</code> constructor.\n" +
" @synopsis array(object element, ...)\n" +
" @param element If parameter is map, corresponding key and value are \n" +
" added instead of map.\n" +
" @method size\n" +
" Returns the number of elements in array\n" +
" @synopsis int size()\n" +
" @return Number of elements\n" +
" @method sizeOf\n" +
" Returns the number of elements in array\n" +
" @synopsis int sizeOf()\n" +
" @return Number of elements\n" +
" @method clear\n" +
" Removess all mappings from this array.\n" +
" @synopsis array clear()\n" +
" @return this array cleared\n" +
" @method iterator\n" +
" Returns an iterator for this array.\n" +
" @synopsis iterator iterator()\n" +
" @method elements\n" +
" Returns an enumeration of values in this array.\n" +
" @synopsis enumeration elements()\n" +
" @method keys\n" +
" Returns an enumeration of keys in this array.\n" +
" @synopsis enumeration keys()\n" +
" @method keysAndElements\n" +
" Returns an enumeration of keys and values in this array.\n" +
" @synopsis enumeration keysAndElements()\n" +
" @method join\n" +
" Joins the string representation of mapped values in this array \n" +
" together with given clue.\n" +
" @synopsis string join()\n" +
" @synopsis string join(string clue)\n" +
" @param clue Separator between values\n" +
" @method push\n" +
" For each parameter, inserts the value or mapping into\n" +
" the end of this array.\n" +
" @synopsis array push(map mapping, ...)\n" +
" @synopsis array push(object element, ...)\n" +
" @method pop\n" +
" Removes the last mapping from this array and\n" +
" returns the value mapped.\n" +
" @synopsis object pop()\n" +
" @method shift\n" +
" Removes the first mapping from this array and\n" +
" returns the value mapped.\n" +
" @synopsis object shift()\n" +
" @method unshift\n" +
" For each parameter, inserts the value or mapping into\n" +
" the start of this array.\n" +
" @synopsis array unshift(map mapping, ...)\n" +
" @synopsis array unshift(object value, ...)\n" +
" @param mapping Mapping to add\n" +
" @param value Value to add\n" +
" @return this array modified\n" +
" @method reverse\n" +
" Reverses to order of mappings in this array.\n" +
" @synopsis array reverse()\n" +
" @return this array reversed\n" +
" @method getKeys\n" +
" Returns list of keys in this array.\n" +
" @synopsis list getKeys()\n" +
" @method getElements\n" +
" Returns list of values in this array.\n" +
" @synopsis list getElements()\n" +
" @method walk\n" +
" Iterates through this array and calls given\n" +
" function at each mapping. Iteration ends when end of \n" +
" array is reached or function returns <code>false</code>.\n" +
" @synopsis array walk(Function callable, object data)\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(key, value)</code> or\n" +
" <code>function walker(key, value, data)</code>.\n" +
" @param data Data passed as a second parameter to walker function\n" +
" @return Returns 'data' parameter\n" +
" @method select\n" +
" Returns new array containing all mappings for which given function \n" +
" returned <code>true</code>.\n" +
" @synopsis array select(Function selector)\n" +
" @synopsis array select(Function selector, object data)\n" +
" @param selector Selector function, either like\n" +
" <code>function selector(key, value)</code> or\n" +
" <code>function selector(key, value, data)</code>.\n" +
" @param data Data passed as a second parameter to selector function\n" +
" @return New array containing selected elements.\n" +
" @method slice\n" +
" Return mappings from given range.\n" +
" @synopsis array slice(int start, int length)\n" +
" @param start Start index\n" +
" @param length Length of range\n" +
" @return Mappings from given range\n" +
" @method cut\n" +
" Removes given range from this array.\n" +
" @synopsis array cut(int start, int length)\n" +
" @param start Start index\n" +
" @param length Length of range\n" +
" @return this array modified\n" +
" @method crop\n" +
" Contract this array to containg only given range.\n" +
" @synopsis array crop(int start, int length)\n" +
" @param start Start index\n" +
" @param length Length of range\n" +
" @return this array modified\n" +
" @method append\n" +
" Append given value into this array. \n" +
" @synopsis array append(object value)\n" +
" @return this array modified\n" +
" @method concat\n" +
" Appends value or values of array into this array.\n" +
" @synopsis array concat(array values)\n" +
" @synopsis array concat(map mapping)\n" +
" @synopsis array concat(object element)\n" +
" @return this array modified\n" +
" @method insert\n" +
" Inserts the mapped values of given array into given range in this array.\n" +
" @synopsis array insert(int start, array values)\n" +
" @synopsis array insert(int start, map mapping)\n" +
" @synopsis array insert(int start, object element)\n" +
" @synopsis array insert(int start, int length, array values)\n" +
" @synopsis array insert(int start, int length, map mapping)\n" +
" @synopsis array insert(int start, int length, object element)\n" +
" @param values Values to insert\n" +
" @param start Start index in this array\n" +
" @param length Length of range to overwrite\n" +
" @return this array modified\n" +
" @method union\n" +
" Merges the keys and values. Existing values in this array are not overridden.\n" +
" @synopsis array union(array set)\n" +
" @param set Array to merge with\n" +
" @return this array modified\n" +
" @method intersect\n" +
" Removes mappings whose key does not appear in both this array\n" +
" and given set.\n" +
" @synopsis array intersect(array set)\n" +
" @param set Set of mappings\n" +
" @return this array modified\n" +
" @method subtract\n" +
" Subtract mappings with the same keys as in given set.\n" +
" @synopsis array subtract(array set)\n" +
" @param set Set of mappings.\n" +
" @return this array subtracted\n" +
" @method pos\n" +
" Return the index of mappping with given key.\n" +
" @synopsis int pos(object key)\n" +
" @return Index to array\n" +
" @method key\n" +
" Returns the mapped key at given index.\n" +
" @synopsis object key(int index)\n" +
" @param index Index to array\n" +
" @method value\n" +
" Returns the mapped value at given index.\n" +
" @synopsis object value(int index)\n" +
" @param index Index to array\n" +
" @method each\n" +
" Returns mapping at given index.\n" +
" @synopsis map each(int index)\n" +
" @param index Index to array\n" +
" @method first\n" +
" Returns the first mapping in this array.\n" +
" @synopsis map first()\n" +
" @method firstKey\n" +
" Returns the key of first mapping in this array.\n" +
" @synopsis object firstKey()\n" +
" @method firstValue\n" +
" Returns the value of first mapping in this array.\n" +
" @synopsis object firstValue()\n" +
" @method last\n" +
" Returns the last mapping in this array.\n" +
" @synopsis map last()\n" +
" @method lastKey\n" +
" Returns the key of last mapping in this array.\n" +
" @synopsis object lastKey()\n" +
" @method lastValue\n" +
" Returns the value of last mapping in this array.\n" +
" @synopsis object lastValue()\n" +
" @method next\n" +
" Return the next mapping of mapping\n" +
" mapped with given key.\n" +
" @synopsis map next(object ofKey)\n" +
" @method nextKey\n" +
" Return the key of next mapping of mapping\n" +
" mapped with given key.\n" +
" @synopsis object nextKey(object ofKey)\n" +
" @method nextValue\n" +
" Return the value of next mapping of mapping\n" +
" mapped with given key.\n" +
" @synopsis object nextValue(object ofKey)\n" +
" @method previous\n" +
" Return the previous mapping of mapping\n" +
" mapped with given key.\n" +
" @synopsis map previous(object ofKey)\n" +
" @method previousKey\n" +
" Return the key of previous mapping of mapping\n" +
" mapped with given key.\n" +
" @synopsis object previousKey(object ofKey)\n" +
" @param ofKey Key to array\n" +
" @method previousValue\n" +
" Return the value of previous mapping of mapping\n" +
" mapped with given key.\n" +
" @synopsis object previousValue(object ofKey)\n" +
" @param ofKey Key to array\n" +
" @method sortByKey\n" +
" Sorts this array according to keys.\n" +
" @synopsis array sortByKey()\n" +
" @synopsis array sortByKey(boolean asceding)\n" +
" @boolean asceding if <code>true</code> array is sorted into asceding order,\n" +
" otherwise desceding.\n" +
" @return this array sorted\n" +
" @method sortByValue\n" +
" Sorts this array according to mapped values.\n" +
" @synopsis array sortByValue()\n" +
" @synopsis array sortByValue(boolean asceding)\n" +
" @boolean asceding if <code>true</code> array is sorted into asceding order,\n" +
" otherwise desceding.\n" +
" @return this array sorted\n" +
"\n" +
" @method sort\n" +
" Sorts this array.\n" +
" @synopsis array sort(Function comparator)\n" +
" @synopsis array sort(Function comparator, object data)\n" +
" @param comparator Comparator function\n" +
" <code>function comparator(key1, elem1, key2, elem2)</code>,\n" +
" or <code>function comparator((key1, elem1, key2, elem2, data)</code>. Function should\n" +
" return less than 0 if <code>elem1<elem2</code>, 0 if <code>elem1==elem2</code> or \n" +
" more than 0 if <code>elem1>elem2</code>.\n" +
" @param data Data passed as a fifth parameter to searching function\n" +
" @return this array sorted\n" +
" @method find\n" +
" Finds and returns the key of first mapping whose value\n" +
" was equal to given parameter.\n" +
" @synopsis array find(object value)\n" +
" @param value Value to search for\n" +
" @return Key of matched mapping, or <code>undefined</code>.\n" +
" @method findAll\n" +
" Finds and returns all mappings whose value was equal to given parameter.\n" +
" @synopsis array findAll(object value)\n" +
" @param value Value to search for\n" +
" @return Array containing matched mappings\n" +
" @method grep\n" +
" Returns new array containing all mappings whose\n" +
" key and/or value matched given regular expressions.\n" +
" @synopsis array grep(pattern keyPattern)\n" +
" @synopsis array grep(string keyPattern)\n" +
" @synopsis array grep(pattern keyPattern, pattern valuePattern [, boolean matchBoth])\n" +
" @synopsis array grep(string keyPattern, string valuePattern [, boolean matchBoth] )\n" +
" @param keyPattern Regular expression to match keys with\n" +
" @param valuePattern Regular expression to match values with\n" +
" @param matchBoth if <code>true</code> both key and value is required to match.\n" +
" @return New array containing selected mappings\n" +
" @throws MalformedPattern If any of patterns where invalid\n" +
" @method grepKeys\n" +
" Returns new array containing all mappings whose\n" +
" key matched matched given regular expression.\n" +
" @synopsis array grepKeys(pattern pattern)\n" +
" @synopsis array grepKeys(string pattern)\n" +
" @param pattern Regular expression to match with\n" +
" @return New array containing selected mappings\n" +
" @throws MalformedPattern If pattern was invalid\n" +
" @method grepValues\n" +
" Returns new array containing all mappings whose\n" +
" value matched matched given regular expression.\n" +
" @synopsis array grepValues(pattern pattern)\n" +
" @synopsis array grepValues(string pattern)\n" +
" @param pattern Regular expression to match with\n" +
" @return New array containing selected mappings\n" +
" @throws MalformedPattern If pattern was invalid\n" +
" @method minmax\n" +
" Finds and returns minimum and maximum value from this array.\n" +
" @synopsis tuple minmax()\n" +
" @return tuple containing <code>(minElement, maxElement)</code>\n" +
" @method minmaxKeys\n" +
" Finds and returns minimum and maximum key from this array.\n" +
" @synopsis tuple minmaxKeys()\n" +
" @return tuple containing <code>(minKey, maxKey)</code>\n" +
" @method setDefault\n" +
" Sets the default value that will be returned if non-existent\n" +
" key is acccessed.\n" +
" @synopsis array setDefault(object defaultValue)\n" +
" @return this array\n" +
" @method getDefault\n" +
" Gets the default value returned if non-existent\n" +
" key is acccessed.\n" +
" @synopsis object getDefault()\n" +
" @method enqueue\n" +
" Adds given element to end of array.\n" +
" @synopsis array enqueue(object element)\n" +
" @synopsis array enqueue(object key, object element)\n" +
" @param element Element to add\n" +
" @method dequeue\n" +
" Removes and returns first <code>key=>value</code>\n" +
" from this array.\n" +
" @synopsis map dequeue()\n" +
" @method get\n" +
" Fetches value from multi dimensional array. (i.e. array\n" +
" containing nested arrays). If missing key is encountered\n" +
" <code>undefined</code> is returned.\n" +
" @synopsis object get(object key1, ...)\n" +
" @method set\n" +
" Sets value at given multi-dimensional array (i.e. array\n" +
" containing nested array). If missing key is encountered \n" +
" arrays remain unchanged.\n" +
" @synopsis object set(object key1, ..., object value)\n" +
" @return value\n" +
" @method swap\n" +
" Swaps the values pointed by given keys.\n" +
" @synopsis array swap(object key1, object key2)\n" +
" @return this array\n" +
" @method swapOrder\n" +
" Swaps order the mappings pointed by given keys.\n" +
" @synopsis array swapOrder(object key1, object key2)\n" +
" @return this array\n"
//}}DOC
);
static {
LangModule.class.getName();
}
}