package org.libspark.collection.array { import org.libspark.collection.access.AbstractCollection; import org.libspark.common.Any; import org.libspark.common.ability.IComparable; import org.libspark.common.store.IReadableStore; import org.libspark.common.store.IWritableStore; import org.libspark.util.Classes; public class ArrayedArray extends AbstractCollection implements IMutableArray { public static function makeEmpty():ArrayedArray { return new ArrayedArray(); } public static function fromArray(source:Array, copy:Boolean = false):ArrayedArray { return new ArrayedArray(source, copy); } public function ArrayedArray(source:Array = null, copy:Boolean = false) { if (source != null) { if (copy) { array = source.concat(); } else { array = source; } } else { array = []; } } private var _array:Array; protected function get array():Array { return _array; } protected function set array(value:Array):void { _array = value; } public function add(item:Object):void { array.push(item); } public function mutableSubarray(start:int, end:int):IMutableArray { return new ArrayedArray(array.slice(start, end + 1)); } public function mutableConcatenated(other:IArray):IMutableArray { var result:IMutableArray = new ArrayedArray(array.concat()); var l:uint = other.count; var i:int; for (i = 0; i < l; ++i) { result.add(other.itemAt(i)); } return result; } public function lastIndexOf(item:Object, fromIndex:int=0x7fffffff):int { var result:int; if (useEqualityComparsion && item is IComparable) { var comparable:IComparable = item as IComparable; var a:Array = array; for (result = Math.min(fromIndex, a.length); result >= 0; --result) { var obj:IComparable = a[result] as IComparable; if (obj != null) { if (comparable.isEqual(obj)) { break; } } } } else { result = array.lastIndexOf(item, fromIndex); } return result; } public function get endIndex():int { return count - 1; } public function get lastItem():Object { return itemAt(endIndex) } public function subarray(start:int, end:int):IArray { return mutableSubarray(start, end); } public function concatenated(other:IArray):IArray { return mutableConcatenated(other); } public function get toArray():Array { return array.concat(); } public function isValidIndex(index:int):Boolean { return 0 <= index && index < count; } public function itemAt(index:int):Object { return array[index]; } public function indexOf(item:Object, fromIndex:int=0):int { var result:int; if (useEqualityComparsion && item is IComparable) { var comparable:IComparable = item as IComparable; var a:Array = array; var l:uint = a.length; for (result = fromIndex; result < l; ++result) { var obj:IComparable = a[result] as IComparable; if (obj != null) { if (comparable.isEqual(obj)) { break; } } } if (result >= l) { result = -1; } } else { result = array.indexOf(item, fromIndex); } return result; } public function get beginIndex():int { return 0; } public function get firstItem():Object { return itemAt(beginIndex) } public function get count():uint { return array.length; } public function countOf(item:Object):uint { var result:uint = 0; var a:Array = array; var l:uint = a.length; var i:int; if (useEqualityComparsion && item is IComparable) { var comparable:IComparable = item as IComparable; for (i = 0; i < l; ++i) { var obj:IComparable = a[i] as IComparable; if (obj != null) { if (comparable.isEqual(obj)) { ++result; } } } } else { for (i = 0; i < l; ++i) { if (a[i] == item) { ++result; } } } return result; } public function isValidInsertableIndex(index:int):Boolean { return 0 <= index && index <= count; } public function insert(item:Object, index:int):void { array.splice(index, 0, item); } public function replace(item:Object, index:int):void { array[index] = item; } public function swap(indexA:int, indexB:int):void { var a:Object = array[indexA]; var b:Object = array[indexB]; array[indexA] = b; array[indexB] = a; } public function removeAt(index:int):void { array.splice(index, 1); } public function remove(item:Object):void { var index:int = indexOf(item); if (index != -1) { removeAt(index); } } public function removeAll(item:Object):void { var a:Array = array; var l:int = a.length; var i:int; if (useEqualityComparsion && item is IComparable) { var comparable:IComparable = item as IComparable; for (i = 0; i < l; ++i) { var obj:IComparable = a[i] as IComparable; if (obj != null) { if (comparable.isEqual(obj)) { removeAt(i); --i; --l; } } } } else { for (i = 0; i < l; ++i) { if (a[i] == item) { removeAt(i); --i; --l; } } } } public function clear():void { array.length = 0; } public function resize(count:uint):void { array.length = count; } override public function get isEmpty():Boolean { return count == 0; } override public function has(item:Object):Boolean { return indexOf(item) != -1; } override public function isEqual(o:IComparable):Boolean { if (!Classes.sameType(this, o)) { return false; } var other:ArrayedArray = o as ArrayedArray; if (useEqualityComparsion != other.useEqualityComparsion) { return false; } var a:Array = array; var l:uint = a.length; var oa:Array = other.array; var ol:uint = oa.length; if (l != ol) { return false; } var i:int; if (useEqualityComparsion) { for (i = 0; i < l; ++i) { var item:Object = a[i]; var otherItem:Object = oa[i]; if (item == null) { if (otherItem != null) { return false; } } else { var comparable:IComparable = item as IComparable; if (comparable != null) { var otherComparable:IComparable = otherItem as IComparable; if (otherComparable == null) { return false; } if (!comparable.isEqual(otherComparable)) { return false; } } else { if (item != otherItem) { return false; } } } } } else { for (i = 0; i < l; ++i) { if (a[i] != oa[i]) { return false; } } } return true; } override protected function copyFrom(other:Any):void { super.copyFrom(other); array = array.concat(); } override public function store(to:IWritableStore):void { super.store(to); to.writeArray('array', array); } override public function restore(from:IReadableStore):void { super.restore(from); array = from.readArray('array', null) || []; } } }