Refactor to avoid linear lookup of streamers.
This was a bit of a rabbit hole and took longer than expected, and I had a stupid bug that took a while to find, but in the end there are way more lines of code removed than added, so I'll call it a win. Streamer lookup is now via a Dictionary. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@5608 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -72,7 +72,7 @@ public class ObjectOutputStream
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ObjectInputStream.DEBUG) {
|
if (ObjectInputStream.DEBUG) {
|
||||||
log.debug("Assigning class code [code=" + cmap.code + ", class=" + cname + "].");
|
log.debug("Assigning class code", "code", cmap.code, "class", cname);
|
||||||
}
|
}
|
||||||
|
|
||||||
writeShort(-cmap.code);
|
writeShort(-cmap.code);
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
package com.threerings.io {
|
package com.threerings.io {
|
||||||
|
|
||||||
import flash.utils.ByteArray;
|
import flash.utils.ByteArray;
|
||||||
|
import flash.utils.Dictionary;
|
||||||
|
|
||||||
import com.threerings.util.ClassUtil;
|
import com.threerings.util.ClassUtil;
|
||||||
import com.threerings.util.Enum;
|
import com.threerings.util.Enum;
|
||||||
@@ -41,33 +42,11 @@ public class Streamer
|
|||||||
{
|
{
|
||||||
public static function getStreamer (obj :Object) :Streamer
|
public static function getStreamer (obj :Object) :Streamer
|
||||||
{
|
{
|
||||||
initStreamers();
|
|
||||||
|
|
||||||
var streamer :Streamer;
|
|
||||||
for each (streamer in _streamers) {
|
|
||||||
if (streamer.isStreamerFor(obj)) {
|
|
||||||
return streamer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// from here on out we're creating new streamers
|
|
||||||
|
|
||||||
if (obj is TypedArray) {
|
if (obj is TypedArray) {
|
||||||
streamer = new ArrayStreamer((obj as TypedArray).getJavaType());
|
return getStreamerByJavaName(TypedArray(obj).getJavaType());
|
||||||
|
|
||||||
} else if (obj is Enum) {
|
|
||||||
streamer = new EnumStreamer(ClassUtil.getClass(obj));
|
|
||||||
|
|
||||||
} else if (obj is Streamable) {
|
|
||||||
streamer = new Streamer(ClassUtil.getClass(obj));
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return getStreamerByClass(ClassUtil.getClass(obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
// add the new streamer and return it
|
|
||||||
_streamers.push(streamer);
|
|
||||||
return streamer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getStreamerByClass (clazz :Class) :Streamer
|
public static function getStreamerByClass (clazz :Class) :Streamer
|
||||||
@@ -78,11 +57,9 @@ public class Streamer
|
|||||||
throw new Error("Broken, TODO");
|
throw new Error("Broken, TODO");
|
||||||
}
|
}
|
||||||
|
|
||||||
var streamer :Streamer;
|
var streamer :Streamer = _byClass[clazz] as Streamer;
|
||||||
for each (streamer in _streamers) {
|
if (streamer != null) {
|
||||||
if (streamer.isStreamerForClass(clazz)) {
|
return streamer;
|
||||||
return streamer;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ClassUtil.isAssignableAs(Enum, clazz)) {
|
if (ClassUtil.isAssignableAs(Enum, clazz)) {
|
||||||
@@ -96,7 +73,7 @@ public class Streamer
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add the new streamer and return it
|
// add the new streamer and return it
|
||||||
_streamers.push(streamer);
|
registerStreamer(streamer);
|
||||||
return streamer;
|
return streamer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,11 +86,9 @@ public class Streamer
|
|||||||
}
|
}
|
||||||
|
|
||||||
// see if we have a streamer for it
|
// see if we have a streamer for it
|
||||||
var streamer :Streamer;
|
var streamer :Streamer = _byJName[jname] as Streamer;
|
||||||
for each (streamer in _streamers) {
|
if (streamer != null) {
|
||||||
if (streamer.getJavaClassName() === jname) {
|
return streamer;
|
||||||
return streamer;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// see if it's an array that we unstream using an ArrayStreamer
|
// see if it's an array that we unstream using an ArrayStreamer
|
||||||
@@ -136,7 +111,7 @@ public class Streamer
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add the good new streamer
|
// add the good new streamer
|
||||||
_streamers.push(streamer);
|
registerStreamer(streamer);
|
||||||
return streamer;
|
return streamer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,16 +123,6 @@ public class Streamer
|
|||||||
_jname = (jname != null) ? jname : Translations.getToServer(ClassUtil.getClassName(targ));
|
_jname = (jname != null) ? jname : Translations.getToServer(ClassUtil.getClassName(targ));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isStreamerFor (obj :Object) :Boolean
|
|
||||||
{
|
|
||||||
return isStreamerForClass(ClassUtil.getClass(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function isStreamerForClass (clazz :Class) :Boolean
|
|
||||||
{
|
|
||||||
return (clazz == _target);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the String to use to identify the class that we're streaming.
|
* Return the String to use to identify the class that we're streaming.
|
||||||
*/
|
*/
|
||||||
@@ -166,6 +131,14 @@ public class Streamer
|
|||||||
return _jname;
|
return _jname;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the Class identifying that which we stream, or null to not be registered.
|
||||||
|
*/
|
||||||
|
public function getClass () :Class
|
||||||
|
{
|
||||||
|
return _target;
|
||||||
|
}
|
||||||
|
|
||||||
public function writeObject (obj :Object, out :ObjectOutputStream) :void
|
public function writeObject (obj :Object, out :ObjectOutputStream) :void
|
||||||
//throws IOError
|
//throws IOError
|
||||||
{
|
{
|
||||||
@@ -185,6 +158,16 @@ public class Streamer
|
|||||||
(obj as Streamable).readObject(ins);
|
(obj as Streamable).readObject(ins);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static function registerStreamer (st :Streamer) :void
|
||||||
|
{
|
||||||
|
_byJName[st.getJavaClassName()] = st;
|
||||||
|
trace(": registered " + st.getJavaClassName());
|
||||||
|
var c :Class = st.getClass();
|
||||||
|
if (c != null) {
|
||||||
|
_byClass[c] = st;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize our streamers. This cannot simply be done statically
|
* Initialize our streamers. This cannot simply be done statically
|
||||||
* because we cannot instantiate a subclass when this class is still
|
* because we cannot instantiate a subclass when this class is still
|
||||||
@@ -192,20 +175,15 @@ public class Streamer
|
|||||||
*/
|
*/
|
||||||
private static function initStreamers () :void
|
private static function initStreamers () :void
|
||||||
{
|
{
|
||||||
if (_streamers == null) {
|
if (_byJName != null) {
|
||||||
// Init like this so that _streamers is not null asap.
|
return;
|
||||||
_streamers = [];
|
}
|
||||||
// We could add each one by one, so that any later streamers
|
_byJName = new Dictionary();
|
||||||
// can find and use the earlier ones as delegates.
|
_byClass = new Dictionary();
|
||||||
_streamers.push(new StringStreamer(),
|
for each (var c :Class in
|
||||||
new NumberStreamer(),
|
[ StringStreamer, NumberStreamer, ByteStreamer, IntegerStreamer, LongStreamer,
|
||||||
new ByteStreamer(),
|
FloatStreamer, ArrayStreamer, ByteArrayStreamer ]) {
|
||||||
new ShortStreamer(),
|
registerStreamer(Streamer(new c()));
|
||||||
new IntegerStreamer(),
|
|
||||||
new LongStreamer(),
|
|
||||||
new FloatStreamer(),
|
|
||||||
new ArrayStreamer(),
|
|
||||||
new ByteArrayStreamer());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,7 +191,7 @@ public class Streamer
|
|||||||
|
|
||||||
protected var _jname :String;
|
protected var _jname :String;
|
||||||
|
|
||||||
/** Just a list of our standard streamers. */
|
protected static var _byClass :Dictionary;
|
||||||
protected static var _streamers :Array;
|
protected static var _byJName :Dictionary;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,10 @@ public class Translations
|
|||||||
// initialize some standard classes
|
// initialize some standard classes
|
||||||
addTranslation("Object", "java.lang.Object");
|
addTranslation("Object", "java.lang.Object");
|
||||||
addTranslation("String", "java.lang.String");
|
addTranslation("String", "java.lang.String");
|
||||||
|
addTranslation("flash.utils.ByteArray", "[B");
|
||||||
addTranslation("com.threerings.util.langBoolean", "java.lang.Boolean");
|
addTranslation("com.threerings.util.langBoolean", "java.lang.Boolean");
|
||||||
|
addTranslation("com.threerings.util.Byte", "java.lang.Byte");
|
||||||
|
addTranslation("com.threerings.util.Integer", "java.lang.Integer");
|
||||||
|
addTranslation("com.threerings.util.Float", "java.lang.Float");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,35 +61,16 @@ public class ArrayStreamer extends Streamer
|
|||||||
_elementType = Boolean;
|
_elementType = Boolean;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Log.getLog(this).warning("Other array types are " +
|
Log.getLog(this).warning("Other array types are not yet handled", "jname", jname);
|
||||||
"currently not handled yet [jname=" + jname + "].");
|
|
||||||
throw new Error("Don't know how to stream '" + jname + "' instances.");
|
throw new Error("Don't know how to stream '" + jname + "' instances.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override public function isStreamerFor (obj :Object) :Boolean
|
override public function getClass () :Class
|
||||||
{
|
{
|
||||||
if (obj is TypedArray) {
|
// this is a little weird, but basically, we don't want to be registered for Array
|
||||||
// TypedArrays need the same element type
|
// unless we're the basic Object array streamer.
|
||||||
return ((obj as TypedArray).getJavaType() === _jname);
|
return (_jname == "[Ljava.lang.Object;") ? Array : null;
|
||||||
|
|
||||||
} else {
|
|
||||||
// any other array is streamed as Object[]
|
|
||||||
return (obj is Array) && (_jname === "[Ljava.lang.Object;");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override public function isStreamerForClass (clazz :Class) :Boolean
|
|
||||||
{
|
|
||||||
if (clazz == TypedArray) {
|
|
||||||
return false; // TODO: we're kinda fucked for finding a streamer
|
|
||||||
// by class for TypedArrays here. The caller should be passing
|
|
||||||
// the java name.
|
|
||||||
|
|
||||||
} else {
|
|
||||||
return ClassUtil.isAssignableAs(Array, clazz) &&
|
|
||||||
(_jname === "[Ljava.lang.Object;");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override public function createObject (ins :ObjectInputStream) :Object
|
override public function createObject (ins :ObjectInputStream) :Object
|
||||||
|
|||||||
@@ -37,11 +37,6 @@ public class LongStreamer extends Streamer
|
|||||||
super(Long, "java.lang.Long");
|
super(Long, "java.lang.Long");
|
||||||
}
|
}
|
||||||
|
|
||||||
override public function createObject (ins :ObjectInputStream) :Object
|
|
||||||
{
|
|
||||||
return new Long();
|
|
||||||
}
|
|
||||||
|
|
||||||
override public function writeObject (obj :Object, out :ObjectOutputStream) :void
|
override public function writeObject (obj :Object, out :ObjectOutputStream) :void
|
||||||
{
|
{
|
||||||
var longy :Long = (obj as Long);
|
var longy :Long = (obj as Long);
|
||||||
|
|||||||
Reference in New Issue
Block a user