1  /*
     2   * Copyright the original author or authors.
     3   * 
     4   * Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   * 
     8   *      http://www.mozilla.org/MPL/MPL-1.1.html
     9   * 
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  import org.as2lib.data.holder.List;
    18  import org.as2lib.data.holder.Iterator;
    19  import org.as2lib.data.holder.array.ArrayIterator;
    20  import org.as2lib.data.holder.list.AbstractList;
    21  import org.as2lib.data.holder.IndexOutOfBoundsException;
    22  
    23  /**
    24   * {@code ArrayList} is a resizable-array implementation of {@code List} interface.
    25   * 
    26   * <p>Example:
    27   * <code>
    28   *   var list:List = new ArrayList();
    29   *   list.insert("myValue1");
    30   *   list.insertFirst("myValue2");
    31   *   list.insertLast("myValue3");
    32   *   trace(list.contains("myValue2"));
    33   *   trace(list.remove(0));
    34   *   trace(list.contains("myValue2"));
    35   *   trace(list.removeLast());
    36   *   trace(list.get(0));
    37   *   list.clear();
    38   *   trace(list.size());
    39   * </code>
    40   * 
    41   * <p>Output:
    42   * <pre>
    43   *   true
    44   *   myValue2
    45   *   false
    46   *   myValue3
    47   *   myValue1
    48   *   0
    49   * </pre>
    50   * 
    51   * @author Simon Wacker
    52   */
    53  class org.as2lib.data.holder.list.ArrayList extends AbstractList implements List {
    54  	
    55  	/** Makes the static variables of the super-class accessible through this class. */
    56  	private static var __proto__:Function = AbstractList;
    57  	
    58  	/** Holds added values. */
    59  	private var data:Array;
    60  	
    61  	/**
    62  	 * Constructs a new {@code ArrayList} instance.
    63  	 *
    64  	 * @param source (optional) an array that contains values to populate this new list
    65  	 * with
    66  	 */
    67  	public function ArrayList(source:Array) {
    68  		if (source) {
    69  			data = source.concat();
    70  		} else {
    71  			data = new Array();
    72  		}
    73  	}
    74  	
    75  	/**
    76  	 * Inserts {@code value} at the given {@code index}.
    77  	 * 
    78  	 * <p>The element that is currently at the given {@code index} is shifted by one to
    79  	 * the right, as well as any subsequent elements.
    80  	 * 
    81  	 * @param index the index at which to insert the {@code value}
    82  	 * @param value the value to insert
    83  	 * @throws IndexOutOfBoundsException if the given {@code index} is not in range,
    84  	 * this is less than 0 or greater than this list's size
    85  	 */
    86  	public function insertByIndexAndValue(index:Number, value):Void {
    87  		if (index < 0 || index > data.length) {
    88  			throw new IndexOutOfBoundsException("Argument 'index' [" + index + "] is out of range, this is less than 0 or greater than this list's size [" + size() + "].", this, arguments);
    89  		}
    90  		if (index == data.length) {
    91  			data.push(value);
    92  			return;
    93  		}
    94  		if (index == 0) {
    95  			data.unshift(value);
    96  			return;
    97  		}
    98  		data.splice(index, 0, value);
    99  	}
   100  	
   101  	/**
   102  	 * Removes the value at given {@code index} from this list and returns it.
   103  	 * 
   104  	 * @param index the index of the value to remove
   105  	 * @return the removed value that was originally at given {@code index}
   106  	 * @throws IndexOutOfBoundsException if given {@code index} is less than 0 or
   107  	 * equal to or greater than this list's size
   108  	 */
   109  	public function removeByIndex(index:Number) {
   110  		if (index < 0 || index >= data.length) {
   111  			throw new IndexOutOfBoundsException("Argument 'index' [" + index + "] is out of range, this is less than 0 or equal to or greater than this list's size [" + size() + "].", this, arguments);
   112  		}
   113  		if (index == 0) {
   114  			return data.shift();
   115  		}
   116  		if (index == data.length - 1) {
   117  			return data.pop();
   118  		}
   119  		var result = data[index];
   120  		data.splice(index, 1);
   121  		return result;
   122  	}
   123  	
   124  	/**
   125  	 * Sets {@code value} to given {@code index} on this list.
   126  	 * 
   127  	 * @param index the index of {@code value}
   128  	 * @param value the {@code value} to set to given {@code index}
   129  	 * @return the value that was orignially at given {@code index}
   130  	 * @throws IndexOutOfBoundsException if given {@code index} is less than 0 or
   131  	 * equal to or greater than this list's size
   132  	 */
   133  	public function set(index:Number, value) {
   134  		if (index < 0 || index >= data.length) {
   135  			throw new IndexOutOfBoundsException("Argument 'index' [" + index + "] is out of range, this is less than 0 or equal to or greater than this list's size [" + size() + "].", this, arguments);
   136  		}
   137  		var result = data[index];
   138  		data[index] = value;
   139  		return result;
   140  	}
   141  	
   142  	/**
   143  	 * Returns the value at given {@code index}.
   144  	 * 
   145  	 * @param index the index to return the value of
   146  	 * @return the value that is at given {@code index}
   147  	 * @throws IndexOutOfBoundsException if given {@code index} is less than 0 or
   148  	 * equal to or greater than this list's size
   149  	 */
   150  	public function get(index:Number) {
   151  		if (index < 0 || index >= data.length) {
   152  			throw new IndexOutOfBoundsException("Argument 'index' [" + index + "] is out of range, this is less than 0 or equal to or greater than this list's size [" + size() + "].", this, arguments);
   153  		}
   154  		return data[index];
   155  	}
   156  	
   157  	/**
   158  	 * Removes all values from this list.
   159  	 */
   160  	public function clear(Void):Void {
   161  		data = new Array();
   162  	}
   163  	
   164  	/**
   165  	 * Returns the number of added values.
   166  	 * 
   167  	 * @return the number of added values
   168  	 */
   169  	public function size(Void):Number {
   170  		return data.length;
   171  	}
   172  	
   173  	/**
   174  	 * Returns the iterator to iterate over this list.
   175  	 * 
   176  	 * @return the iterator to iterate over this list
   177  	 */
   178  	public function iterator(Void):Iterator {
   179  		return new ArrayIterator(data);
   180  	}
   181  	
   182  	/**
   183  	 * Returns the array representation of this list.
   184  	 * 
   185  	 * @return the array representation of this list
   186  	 */
   187  	public function toArray(Void):Array {
   188  		return data.concat();
   189  	}
   190  
   191  }