Jackson Dunstan's subclass check - cached version
Jackson Dunstan compared the performance of various approaches to test if a class is a subclass of another class:
http://jacksondunstan.com/articles/1836
I used the code and added a cached version
package
{
import flash.utils.Dictionary;
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.utils.describeType;
import flash.utils.getDefinitionByName;
import flash.utils.getQualifiedClassName;
import flash.utils.getQualifiedSuperclassName;
import flash.utils.getTimer;
public class ClassInheritanceSpeed extends Sprite
{
private var __logger:TextField = new TextField();
private function row(...cols): void
{
__logger.appendText(cols.join(",")+"\n");
}
public function ClassInheritanceSpeed()
{
var logger:TextField = __logger;
logger.autoSize = TextFieldAutoSize.LEFT;
addChild(logger);
row("--All Versions--");
row("Version", "Time");
var beforeTime:int;
var afterTime:int;
var REPS:int = 500;
var i:int;
beforeTime = getTimer();
for (i = 0; i < REPS; ++i)
{
isSubclassOfSkyboy(ClassInheritanceSpeed, ClassInheritanceSpeed);
isSubclassOfSkyboy(ClassInheritanceSpeed, Sprite);
isSubclassOfSkyboy(ClassInheritanceSpeed, DisplayObject);
isSubclassOfSkyboy(InterfaceTop, InterfaceTop);
isSubclassOfSkyboy(InterfaceMiddle, InterfaceTop);
isSubclassOfSkyboy(InterfaceBottom, InterfaceTop);
isSubclassOfSkyboy(ClassTop, InterfaceTop);
isSubclassOfSkyboy(ClassMiddle, InterfaceTop);
isSubclassOfSkyboy(ClassBottom, InterfaceTop);
isSubclassOfSkyboy(Sprite, ClassTop);
isSubclassOfSkyboy(Sprite, ClassInheritanceSpeed);
isSubclassOfSkyboy(DisplayObject, ClassInheritanceSpeed);
isSubclassOfSkyboy(InterfaceTop, InterfaceMiddle);
isSubclassOfSkyboy(InterfaceTop, InterfaceBottom);
isSubclassOfSkyboy(InterfaceTop, ClassMiddle);
isSubclassOfSkyboy(InterfaceTop, ClassBottom);
}
afterTime = getTimer();
row("Skyboy", (afterTime-beforeTime));
beforeTime = getTimer();
for (i = 0; i < REPS; ++i)
{
isSubclassOfP03(ClassInheritanceSpeed, ClassInheritanceSpeed);
isSubclassOfP03(ClassInheritanceSpeed, Sprite);
isSubclassOfP03(ClassInheritanceSpeed, DisplayObject);
isSubclassOfP03(InterfaceTop, InterfaceTop);
isSubclassOfP03(InterfaceMiddle, InterfaceTop);
isSubclassOfP03(InterfaceBottom, InterfaceTop);
isSubclassOfP03(ClassTop, InterfaceTop);
isSubclassOfP03(ClassMiddle, InterfaceTop);
isSubclassOfP03(ClassBottom, InterfaceTop);
isSubclassOfP03(Sprite, ClassTop);
isSubclassOfP03(Sprite, ClassInheritanceSpeed);
isSubclassOfP03(DisplayObject, ClassInheritanceSpeed);
isSubclassOfP03(InterfaceTop, InterfaceMiddle);
isSubclassOfP03(InterfaceTop, InterfaceBottom);
isSubclassOfP03(InterfaceTop, ClassMiddle);
isSubclassOfP03(InterfaceTop, ClassBottom);
}
afterTime = getTimer();
row("P03", (afterTime-beforeTime));
beforeTime = getTimer();
for (i = 0; i < REPS; ++i)
{
isSubclassOfBloodhound(ClassInheritanceSpeed, ClassInheritanceSpeed);
isSubclassOfBloodhound(ClassInheritanceSpeed, Sprite);
isSubclassOfBloodhound(ClassInheritanceSpeed, DisplayObject);
isSubclassOfBloodhound(InterfaceTop, InterfaceTop);
isSubclassOfBloodhound(InterfaceMiddle, InterfaceTop);
isSubclassOfBloodhound(InterfaceBottom, InterfaceTop);
isSubclassOfBloodhound(ClassTop, InterfaceTop);
isSubclassOfBloodhound(ClassMiddle, InterfaceTop);
isSubclassOfBloodhound(ClassBottom, InterfaceTop);
isSubclassOfBloodhound(Sprite, ClassTop);
isSubclassOfBloodhound(Sprite, ClassInheritanceSpeed);
isSubclassOfBloodhound(DisplayObject, ClassInheritanceSpeed);
isSubclassOfBloodhound(InterfaceTop, InterfaceMiddle);
isSubclassOfBloodhound(InterfaceTop, InterfaceBottom);
isSubclassOfBloodhound(InterfaceTop, ClassMiddle);
isSubclassOfBloodhound(InterfaceTop, ClassBottom);
}
afterTime = getTimer();
row("Bloodhound", (afterTime-beforeTime));
beforeTime = getTimer();
for (i = 0; i < REPS; ++i)
{
isSubclassOfLab9(ClassInheritanceSpeed, ClassInheritanceSpeed);
isSubclassOfLab9(ClassInheritanceSpeed, Sprite);
isSubclassOfLab9(ClassInheritanceSpeed, DisplayObject);
isSubclassOfLab9(InterfaceTop, InterfaceTop);
isSubclassOfLab9(InterfaceMiddle, InterfaceTop);
isSubclassOfLab9(InterfaceBottom, InterfaceTop);
isSubclassOfLab9(ClassTop, InterfaceTop);
isSubclassOfLab9(ClassMiddle, InterfaceTop);
isSubclassOfLab9(ClassBottom, InterfaceTop);
isSubclassOfLab9(Sprite, ClassTop);
isSubclassOfLab9(Sprite, ClassInheritanceSpeed);
isSubclassOfLab9(DisplayObject, ClassInheritanceSpeed);
isSubclassOfLab9(InterfaceTop, InterfaceMiddle);
isSubclassOfLab9(InterfaceTop, InterfaceBottom);
isSubclassOfLab9(InterfaceTop, ClassMiddle);
isSubclassOfLab9(InterfaceTop, ClassBottom);
}
afterTime = getTimer();
row("Lab9", (afterTime-beforeTime));
beforeTime = getTimer();
for (i = 0; i < REPS; ++i)
{
isSubclassOfJackson(ClassInheritanceSpeed, ClassInheritanceSpeed);
isSubclassOfJackson(ClassInheritanceSpeed, Sprite);
isSubclassOfJackson(ClassInheritanceSpeed, DisplayObject);
isSubclassOfJackson(InterfaceTop, InterfaceTop);
isSubclassOfJackson(InterfaceMiddle, InterfaceTop);
isSubclassOfJackson(InterfaceBottom, InterfaceTop);
isSubclassOfJackson(ClassTop, InterfaceTop);
isSubclassOfJackson(ClassMiddle, InterfaceTop);
isSubclassOfJackson(ClassBottom, InterfaceTop);
isSubclassOfJackson(Sprite, ClassTop);
isSubclassOfJackson(Sprite, ClassInheritanceSpeed);
isSubclassOfJackson(DisplayObject, ClassInheritanceSpeed);
isSubclassOfJackson(InterfaceTop, InterfaceMiddle);
isSubclassOfJackson(InterfaceTop, InterfaceBottom);
isSubclassOfJackson(InterfaceTop, ClassMiddle);
isSubclassOfJackson(InterfaceTop, ClassBottom);
}
afterTime = getTimer();
row("Jackson", (afterTime-beforeTime));
beforeTime = getTimer();
for (i = 0; i < REPS; ++i)
{
isSubclassOfJacksonCached(ClassInheritanceSpeed, ClassInheritanceSpeed);
isSubclassOfJacksonCached(ClassInheritanceSpeed, Sprite);
isSubclassOfJacksonCached(ClassInheritanceSpeed, DisplayObject);
isSubclassOfJacksonCached(InterfaceTop, InterfaceTop);
isSubclassOfJacksonCached(InterfaceMiddle, InterfaceTop);
isSubclassOfJacksonCached(InterfaceBottom, InterfaceTop);
isSubclassOfJacksonCached(ClassTop, InterfaceTop);
isSubclassOfJacksonCached(ClassMiddle, InterfaceTop);
isSubclassOfJacksonCached(ClassBottom, InterfaceTop);
isSubclassOfJacksonCached(Sprite, ClassTop);
isSubclassOfJacksonCached(Sprite, ClassInheritanceSpeed);
isSubclassOfJacksonCached(DisplayObject, ClassInheritanceSpeed);
isSubclassOfJacksonCached(InterfaceTop, InterfaceMiddle);
isSubclassOfJacksonCached(InterfaceTop, InterfaceBottom);
isSubclassOfJacksonCached(InterfaceTop, ClassMiddle);
isSubclassOfJacksonCached(InterfaceTop, ClassBottom);
}
afterTime = getTimer();
row("Jackson Cached", (afterTime-beforeTime));
row("");
row("--Fast Versions Only--");
row("Version", "Time");
REPS = 1000000;
beforeTime = getTimer();
for (i = 0; i < REPS; ++i)
{
isSubclassOfSkyboy(ClassInheritanceSpeed, ClassInheritanceSpeed);
isSubclassOfSkyboy(ClassInheritanceSpeed, Sprite);
isSubclassOfSkyboy(ClassInheritanceSpeed, DisplayObject);
isSubclassOfSkyboy(InterfaceTop, InterfaceTop);
isSubclassOfSkyboy(InterfaceMiddle, InterfaceTop);
isSubclassOfSkyboy(InterfaceBottom, InterfaceTop);
isSubclassOfSkyboy(ClassTop, InterfaceTop);
isSubclassOfSkyboy(ClassMiddle, InterfaceTop);
isSubclassOfSkyboy(ClassBottom, InterfaceTop);
isSubclassOfSkyboy(Sprite, ClassTop);
isSubclassOfSkyboy(Sprite, ClassInheritanceSpeed);
isSubclassOfSkyboy(DisplayObject, ClassInheritanceSpeed);
isSubclassOfSkyboy(InterfaceTop, InterfaceMiddle);
isSubclassOfSkyboy(InterfaceTop, InterfaceBottom);
isSubclassOfSkyboy(InterfaceTop, ClassMiddle);
isSubclassOfSkyboy(InterfaceTop, ClassBottom);
}
afterTime = getTimer();
row("Skyboy", (afterTime-beforeTime));
beforeTime = getTimer();
for (i = 0; i < REPS; ++i)
{
isSubclassOfBloodhound(ClassInheritanceSpeed, ClassInheritanceSpeed);
isSubclassOfBloodhound(ClassInheritanceSpeed, Sprite);
isSubclassOfBloodhound(ClassInheritanceSpeed, DisplayObject);
isSubclassOfBloodhound(InterfaceTop, InterfaceTop);
isSubclassOfBloodhound(InterfaceMiddle, InterfaceTop);
isSubclassOfBloodhound(InterfaceBottom, InterfaceTop);
isSubclassOfBloodhound(ClassTop, InterfaceTop);
isSubclassOfBloodhound(ClassMiddle, InterfaceTop);
isSubclassOfBloodhound(ClassBottom, InterfaceTop);
isSubclassOfBloodhound(Sprite, ClassTop);
isSubclassOfBloodhound(Sprite, ClassInheritanceSpeed);
isSubclassOfBloodhound(DisplayObject, ClassInheritanceSpeed);
isSubclassOfBloodhound(InterfaceTop, InterfaceMiddle);
isSubclassOfBloodhound(InterfaceTop, InterfaceBottom);
isSubclassOfBloodhound(InterfaceTop, ClassMiddle);
isSubclassOfBloodhound(InterfaceTop, ClassBottom);
}
afterTime = getTimer();
row("Bloodhound", (afterTime-beforeTime));
beforeTime = getTimer();
for (i = 0; i < REPS; ++i)
{
isSubclassOfJacksonCached(ClassInheritanceSpeed, ClassInheritanceSpeed);
isSubclassOfJacksonCached(ClassInheritanceSpeed, Sprite);
isSubclassOfJacksonCached(ClassInheritanceSpeed, DisplayObject);
isSubclassOfJacksonCached(InterfaceTop, InterfaceTop);
isSubclassOfJacksonCached(InterfaceMiddle, InterfaceTop);
isSubclassOfJacksonCached(InterfaceBottom, InterfaceTop);
isSubclassOfJacksonCached(ClassTop, InterfaceTop);
isSubclassOfJacksonCached(ClassMiddle, InterfaceTop);
isSubclassOfJacksonCached(ClassBottom, InterfaceTop);
isSubclassOfJacksonCached(Sprite, ClassTop);
isSubclassOfJacksonCached(Sprite, ClassInheritanceSpeed);
isSubclassOfJacksonCached(DisplayObject, ClassInheritanceSpeed);
isSubclassOfJacksonCached(InterfaceTop, InterfaceMiddle);
isSubclassOfJacksonCached(InterfaceTop, InterfaceBottom);
isSubclassOfJacksonCached(InterfaceTop, ClassMiddle);
isSubclassOfJacksonCached(InterfaceTop, ClassBottom);
}
afterTime = getTimer();
row("Jackson Cached", (afterTime-beforeTime));
}
private function isSubclassOfSkyboy(a:Class, b:Class): Boolean
{
if (int(!a) | int(!b)) return false;
return (a == b || a.prototype instanceof b);
}
private function isSubclassOfP03(type:Class, superClass:Class): Boolean
{
if (superClass == Object)
{
return true;
}
try
{
for (
var c:Class = type;
c != Object;
c = Class(getDefinitionByName(getQualifiedSuperclassName(c)))
)
{
if (c == superClass)
{
return true;
}
}
}
catch(e:Error)
{
}
return false;
}
private function isSubclassOfBloodhound(a:Class, b:Class): Boolean
{
return b.prototype.isPrototypeOf( a.prototype );
}
private function isSubclassOfLab9(tested:Class, type:Class): Boolean
{
var desc:XML = XML(describeType(tested));
var name:String = getQualifiedClassName(type);
return Boolean(desc.factory.extendsClass.@type.contains(name)
|| desc.factory.implementsInterface.@type.contains(name));
}
private function isSubclassOfJackson(a:Class, b:Class): Boolean
{
if (a == b)
{
return true;
}
var factoryNode:XMLList = XML(describeType(a)).factory;
var superclassName:String = getQualifiedClassName(b);
return factoryNode.extendsClass.@type.contains(superclassName)
|| factoryNode.implementsInterface.@type.contains(superclassName);
}
private const jacksonCache: Dictionary = new Dictionary(true);
private function isSubclassOfJacksonCached(a:Class, b:Class): Boolean
{
var map: Dictionary = jacksonCache[a] ||= new Dictionary(true);
var result: Boolean;
if (map[b] !== null)
{
result = map[b];
}
else
{
if (a == b)
{
return true;
}
var factoryNode:XMLList = XML(describeType(a)).factory;
var superclassName:String = getQualifiedClassName(b);
result = factoryNode.extendsClass.@type.contains(superclassName)
|| factoryNode.implementsInterface.@type.contains(superclassName);
}
return result;
}
}
}
interface InterfaceTop {}
interface InterfaceMiddle extends InterfaceTop {}
interface InterfaceBottom extends InterfaceMiddle {}
class ClassTop implements InterfaceTop {}
class ClassMiddle implements InterfaceMiddle {}
class ClassBottom implements InterfaceBottom {}