diff --git a/src/as/com/threerings/presents/client/Client.as b/src/as/com/threerings/presents/client/Client.as index 6483df5da..10e05ff3e 100644 --- a/src/as/com/threerings/presents/client/Client.as +++ b/src/as/com/threerings/presents/client/Client.as @@ -174,7 +174,7 @@ public class Client extends EventDispatcher public function getService (clazz :Class) :InvocationService { if (_bstrap != null) { - for each (var isvc :InvocationService in _bstrap.services.source) { + for each (var isvc :InvocationService in _bstrap.services.asArray()) { if (isvc is clazz) { return isvc; } diff --git a/src/as/com/threerings/presents/client/ClientDObjectMgr.as b/src/as/com/threerings/presents/client/ClientDObjectMgr.as index 4bf50c235..0b738fe0d 100644 --- a/src/as/com/threerings/presents/client/ClientDObjectMgr.as +++ b/src/as/com/threerings/presents/client/ClientDObjectMgr.as @@ -26,8 +26,6 @@ import flash.events.TimerEvent; import flash.utils.Timer; import flash.utils.getTimer; // function import -import mx.collections.IList; - import com.threerings.util.ClassUtil; import com.threerings.util.HashMap; @@ -227,10 +225,10 @@ public class ClientDObjectMgr // if this is a compound event, we need to process its contained // events in order if (event is CompoundEvent) { - var events :IList = (event as CompoundEvent).getEvents(); + var events :Array = (event as CompoundEvent).getEvents(); var ecount :int = events.length; for (var ii :int = 0; ii < ecount; ii++) { - dispatchEvent(events.getItemAt(ii) as DEvent); + dispatchEvent(events[ii] as DEvent); } return; } diff --git a/src/as/com/threerings/presents/client/InvocationDirector.as b/src/as/com/threerings/presents/client/InvocationDirector.as index 81f638b35..17e6b4bad 100644 --- a/src/as/com/threerings/presents/client/InvocationDirector.as +++ b/src/as/com/threerings/presents/client/InvocationDirector.as @@ -2,10 +2,7 @@ package com.threerings.presents.client { import flash.utils.getTimer; // function import -import mx.collections.IViewCursor; -import mx.collections.ArrayCollection; - -import com.threerings.util.HashMap; +import com.threerings.util.Hashtable; import com.threerings.presents.data.InvocationMarshaller_ListenerMarshaller; @@ -60,7 +57,7 @@ public class InvocationDirector */ public function registerReceiver (decoder :InvocationDecoder) :void { - _reclist.addItem(decoder); + _reclist.push(decoder); // if we're already online, assign a recevier id now if (_clobj != null) { @@ -74,12 +71,11 @@ public class InvocationDirector public function unregisterReceiver (receiverCode :String) :void { // remove the receiver from the list - for (var iter :IViewCursor = _reclist.createCursor(); - iter.moveNext(); ) { + for (var ii :int = _reclist.length - 1; ii >= 0; ii--) { var decoder :InvocationDecoder = - (iter.current as InvocationDecoder); + (_reclist[ii] as InvocationDecoder); if (decoder.getReceiverCode() === receiverCode) { - iter.remove(); + _reclist.splice(ii, 1); } } @@ -122,10 +118,7 @@ public class InvocationDirector { _clobj.startTransaction(); try { - for (var itr :IViewCursor = _reclist.createCursor(); - itr.moveNext(); ) { - var decoder :InvocationDecoder = - (itr.current as InvocationDecoder); + for each (var decoder :InvocationDecoder in _reclist) { assignReceiverId(decoder); } } finally { @@ -354,14 +347,14 @@ public class InvocationDirector /** Used to keep track of invocation service listeners which will * receive responses from invocation service requests. */ - protected var _listeners :HashMap = new HashMap(); + protected var _listeners :Hashtable = new Hashtable(); /** Used to keep track of invocation notification receivers. */ - protected var _receivers :HashMap = new HashMap(); + protected var _receivers :Hashtable = new Hashtable(); /** All registered receivers are maintained in a list so that we can * assign receiver ids to them when we go online. */ - internal var _reclist :ArrayCollection = new ArrayCollection(); + internal var _reclist :Array = []; /** The last time we flushed our listeners. */ protected var _lastFlushTime :Number; diff --git a/src/as/com/threerings/presents/dobj/CompoundEvent.as b/src/as/com/threerings/presents/dobj/CompoundEvent.as index 1498c1b23..84f194755 100644 --- a/src/as/com/threerings/presents/dobj/CompoundEvent.as +++ b/src/as/com/threerings/presents/dobj/CompoundEvent.as @@ -21,8 +21,6 @@ package com.threerings.presents.dobj { -import mx.collections.IList; - import com.threerings.io.ObjectInputStream; import com.threerings.io.ObjectOutputStream; @@ -65,16 +63,16 @@ public class CompoundEvent extends DEvent */ public function postEvent (event :DEvent) :void { - _events.addItem(event); + _events.add(event); } /** * Returns the list of events contained within this compound event. * Don't mess with it. */ - public function getEvents () :IList + public function getEvents () :Array { - return _events; + return _events.asArray(); } /** @@ -90,11 +88,11 @@ public class CompoundEvent extends DEvent // then post this event onto the queue (but only if we actually // accumulated some events) - switch (_events.length) { + switch (_events.size()) { case 0: // nothing doing break; case 1: // no point in being compound - _omgr.postEvent(_events.getItemAt(0) as DEvent); + _omgr.postEvent(_events.get(0) as DEvent); break; default: // now we're talking _omgr.postEvent(this); @@ -111,7 +109,7 @@ public class CompoundEvent extends DEvent // clear our target clearTarget(); // clear our event queue in case someone holds onto us - _events.removeAll(); + _events.clear(); } /** @@ -140,8 +138,9 @@ public class CompoundEvent extends DEvent buf.append("COMPOUND:"); super.toStringBuf(buf); - for (var ii :int = 0; ii < _events.length; ii++) { - buf.append(", ", _events.getItemAt(ii)); + var nn :int = _events.size(); + for (var ii :int = 0; ii < nn; ii++) { + buf.append(", ", _events.get(ii)); } } diff --git a/src/as/com/threerings/presents/dobj/DSet.as b/src/as/com/threerings/presents/dobj/DSet.as index 6f575911c..d871e53cb 100644 --- a/src/as/com/threerings/presents/dobj/DSet.as +++ b/src/as/com/threerings/presents/dobj/DSet.as @@ -1,7 +1,5 @@ package com.threerings.presents.dobj { -import mx.utils.ObjectUtil; - import com.threerings.util.ArrayIterator; import com.threerings.util.Cloneable; import com.threerings.util.Equalable; @@ -117,7 +115,7 @@ public class DSet if (_entries.length == 0) { // there is nothing in the map yet, check the key validity var key :Object = elem.getKey(); - if (!(key is Equalable) && !ObjectUtil.isSimple(key)) { + if (!(key is Equalable) && !Util.isSimple(key)) { throw new Error("Element key is not 'simple' or Equalable"); } diff --git a/src/as/com/threerings/util/ArrayIterator.as b/src/as/com/threerings/util/ArrayIterator.as index e8695cf6c..508a25b31 100644 --- a/src/as/com/threerings/util/ArrayIterator.as +++ b/src/as/com/threerings/util/ArrayIterator.as @@ -1,5 +1,7 @@ package com.threerings.util { +import flash.errors.IllegalOperationError; + /** * Provides a generic iterator for an Array. * No co-modification checking is done. @@ -25,13 +27,29 @@ public class ArrayIterator // documentation inherited from interface Iterator public function next () :Object { + _lastIndex = _index; return _arr[_index++]; } + // documentation inherited from interface Iterator + public function remove () :void + { + if (_lastIndex == -1) { + throw new IllegalOperationError(); + + } else { + _arr.splice(_lastIndex, 1); + _lastIndex = -1; + } + } + /** The array we're iterating over. */ protected var _arr :Array; /** The current index. */ protected var _index :int; + + /** The last-removed index. */ + protected var _lastIndex :int = -1; } } diff --git a/src/as/com/threerings/util/ArrayUtil.as b/src/as/com/threerings/util/ArrayUtil.as index d7e5743e1..cc5130b3e 100644 --- a/src/as/com/threerings/util/ArrayUtil.as +++ b/src/as/com/threerings/util/ArrayUtil.as @@ -20,6 +20,22 @@ public class ArrayUtil }); } + /** + * Randomly shuffle the elements in the specified array. + */ + public static function shuffle (arr :Array) :void + { + // starting from the end of the list, repeatedly swap the element in + // question with a random element previous to it up to and including + // itself + for (var ii :int = arr.length - 1; ii > 0; ii--) { + var idx :int = int(Math.random() * (ii + 1)); + var tmp :Object = arr[idx]; + arr[idx] = arr[ii]; + arr[ii] = tmp; + } + } + public static function indexOf (arr :Array, element :Object) :int { if (arr != null) { diff --git a/src/as/com/threerings/util/Collections.as b/src/as/com/threerings/util/Collections.as deleted file mode 100644 index f17ddc5d6..000000000 --- a/src/as/com/threerings/util/Collections.as +++ /dev/null @@ -1,25 +0,0 @@ -package com.threerings.util { - -import mx.collections.ListCollectionView; - -/** - * Various collections-related utility methods. - */ -public class Collections -{ - /** - * Randomly shuffle the elements in the specified list. - */ - public static function shuffle (collection :ListCollectionView) :void - { - // starting from the end of the list, repeatedly swap the element - // in question with a random element previous to it up - // to and including itself - for (var ii :int = collection.length - 1; ii > 0; ii--) { - var idx :int = int(Math.random() * (ii + 1)) - var item :Object = collection.getItemAt(idx); - collection.setItemAt(collection.setItemAt(item, ii), idx); - } - } -} -} diff --git a/src/as/com/threerings/util/Iterator.as b/src/as/com/threerings/util/Iterator.as index e843fabe5..9f805bef8 100644 --- a/src/as/com/threerings/util/Iterator.as +++ b/src/as/com/threerings/util/Iterator.as @@ -18,6 +18,9 @@ public interface Iterator */ function next () :Object; - // TODO: remove() ? + /** + * Remove the last returned element. + */ + function remove () :void; } } diff --git a/src/as/com/threerings/util/StreamableArrayList.as b/src/as/com/threerings/util/StreamableArrayList.as index e75816c23..1d6d39358 100644 --- a/src/as/com/threerings/util/StreamableArrayList.as +++ b/src/as/com/threerings/util/StreamableArrayList.as @@ -1,66 +1,157 @@ package com.threerings.util { -import mx.collections.ArrayCollection; - import com.threerings.io.ObjectInputStream; import com.threerings.io.ObjectOutputStream; import com.threerings.io.Streamable; -public class StreamableArrayList extends ArrayCollection +public class StreamableArrayList implements Streamable { - /** - * Returns the index of the specified object in this collection, using - * Equalable.equals() if possible. - */ - public function indexOf (object :Object) :int + public function StreamableArrayList (values :Array = null) { - return ArrayUtil.indexOf(source, object); + _array = (values == null) ? new Array() : values; + } + + public function add (item :Object, index :int = -1) :Boolean + { + _array.splice(index, 0, item); + return true; } /** - * Removes the first instance of the supplied object from this array, using - * Equalable.equals() to determine equality. Returns the removed object if - * a match was found, null otherwise. + * Add all the elements in the other list. + * + * @param otherList may be another StreamableArrayList or an Array */ - public function remove (object :Object) :Object + public function addAll (otherList :*, index :int = -1) :Boolean { - return ArrayUtil.removeFirst(source, object); - } + var other :Array = getArray(otherList); - /** - * Adds all of the elements of the supplied collection to the end of this - * list. - */ - public function addAll (list :ArrayCollection) :void - { - for (var ii :int = 0; ii < list.length; ii++) { - addItem(list.getItemAt(ii)); + // splice each element in at the index + for (var ii :int = other.length - 1; ii >= 0; ii--) { + _array.splice(index, 0, other[ii]); } + return (other.length > 0); + } + + public function clear () :void + { + _array.length = 0; + } + + public function contains (item :Object) :Boolean + { + return ArrayUtil.contains(_array, item); + } + + public function get (index :int) :* + { + return _array[index]; + } + + public function indexOf (item :Object) :int + { + return ArrayUtil.indexOf(_array, item); + } + + public function isEmpty () :Boolean + { + return (_array.length == 0); + } + + public function iterator () :Iterator + { + return new ArrayIterator(_array); + } + + public function remove (item :Object) :Boolean + { + return ArrayUtil.removeFirst(_array, item); + } + + public function removeAll (otherList :*) :Boolean + { + var other :Array = getArray(otherList); + + var removed :Boolean = false; + for (var ii :int = other.length - 1; ii >= 0; ii--) { + if (remove(other[ii])) { + removed = true; + } + } + return removed; + } + + public function removeAt (index :int) :Object + { + return _array.splice(index, 1)[0]; + } + + public function set (index :int, item :Object) :Object + { + var ret :Object = _array[index]; + _array[index] = item; + return ret; + } + + public function size () :int + { + return _array.length; + } + + /** + * Return the actual array storage. + */ + public function asArray () :Array + { + return _array; + } + + /** + * Return a copy of the internal storage array. + */ + public function toArray () :Array + { + return _array.concat(); } // documentation inherited from interface Streamable public function writeObject (out :ObjectOutputStream) :void { - out.writeInt(source.length); - for (var ii :int = 0; ii < source.length; ii++) { - out.writeObject(source[ii]); + var len :int = _array.length; + out.writeInt(len); + for (var ii :int = 0; ii < len; ii++) { + out.writeObject(_array[ii]); } } // documentation inherited from interface Streamable public function readObject (ins :ObjectInputStream) :void { - var ecount :int = ins.readInt(); - disableAutoUpdate(); - removeAll(); - try { - for (var ii :int = 0; ii < ecount; ii++) { - addItem(ins.readObject()); - } - } finally { - enableAutoUpdate(); + var len :int = ins.readInt(); + _array.length = len; // truncate (or grow once) + for (var ii :int = 0; ii < len; ii++) { + _array[ii] = ins.readObject(); } } + + /** + * Return an array representing the argument. + */ + protected function getArray (otherList :*) :Array + { + if (otherList is StreamableArrayList) { + return (otherList as StreamableArrayList).asArray(); + + } else if (otherList is Array) { + return (otherList as Array); + + } else { + throw new ArgumentError(); + } + } + + /** Storage. */ + protected var _array :Array; } } diff --git a/src/as/com/threerings/util/Util.as b/src/as/com/threerings/util/Util.as index 8019c7a6e..d195aa629 100644 --- a/src/as/com/threerings/util/Util.as +++ b/src/as/com/threerings/util/Util.as @@ -6,6 +6,26 @@ import com.threerings.util.StringBuilder; public class Util { + /** + * Is the specified object 'simple': one of the basic built-in flash types. + */ + public static function isSimple (obj :Object) :Boolean + { + var type :String = typeof(obj); + switch (type) { + case "number": + case "string": + case "boolean": + return true; + + case "object": + return (obj is Date) || (obj is Array); + + default: + return false; + } + } + /** * A nice utility method for testing equality in a better way. * If the objects are Equalable, then that will be tested. Arrays