In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

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
Get Adobe Flash player
by leichtgewicht 01 May 2012
    Embed
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 {}