Package anvil.core

Source Code of anvil.core.Array$Iterator

/*
* $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&lt;elem2</code>, 0 if <code>elem1==elem2</code> or
  /// more than 0 if <code>elem1&gt;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&lt;elem2</code>, 0 if <code>elem1==elem2</code> or \n" +
      " more than 0 if <code>elem1&gt;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();
  }

}
TOP

Related Classes of anvil.core.Array$Iterator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.