Thursday, February 26, 2009

Which is faster in ActionScript if, switch or object of function pointers

In an effort to parse a kml file as quickly as possible, I need to know if it was faster to use if statements, switch statements or an object with each tag as a key to a function pointer. I created a test function for each of these methods. I then timed each of the test functions, as I iterated it 1000, 10,000, 100,000, and 1,000,000 times. The results show that the object wiith function pointers is by far the fastest when you have lots of iterations. There seems to be some start up cost associated with creating the object and the functions. Here is a table of the results, as you can see the results from 10,000 on are all very linear.

iterations if statements switch statements function pointers
1000 0.015 0.031 0.032
10,000 0.218 0.25 0.141
100,000 2.297 2.563 1.343
1,000,000 22.813 26.313 13.203

So I started off with the if statements:
private function testIfStatements( names:Array , iterations:int ) : int {
 
 var x:int = 0;
 for( var i:int = 0; i < iterations; i++ ){
  for( var j:int = 0; j < names.length; j++ ){
   if( names[j] == 'amy' ){ x = x + 1; }
   else if( names[j] == 'bob' ){ x = x + 1; } 
   else if( names[j] == 'curly'  ){ x = x + 1; }
   else if( names[j] == 'dawn'  ){ x = x + 1; }
   else if( names[j] == 'erick'  ){ x = x + 1; }
   else if( names[j] == 'fred'  ){ x = x + 1; }
   else if( names[j] == 'george'  ){ x = x + 1; }
   else if( names[j] == 'harley'  ){ x = x + 1; }
   else if( names[j] == 'ian'  ){ x = x + 1; }
   else if( names[j] == 'jim'  ){ x = x + 1; }
   else if( names[j] == 'kim'  ){ x = x + 1; }
   else if( names[j] == 'liam'  ){ x = x + 1; }
   else if( names[j] == 'moe'  ){ x = x + 1; }
   else if( names[j] == 'nate'  ){ x = x + 1; }
   else if( names[j] == 'oliver'  ){ x = x + 1; }
   else if( names[j] == 'penelope'  ){ x = x + 1; }
   else if( names[j] == 'quinn'  ){ x = x + 1; }
   else if( names[j] == 'robb'  ){ x = x + 1; }
   else if( names[j] == 'silas'  ){ x = x + 1; }
   else if( names[j] == 'tim'  ){ x = x + 1; }
   else if( names[j] == 'ulysses'  ){ x = x + 1; }
   else if( names[j] == 'victor'  ){ x = x + 1; }
   else if( names[j] == 'waldo'  ){ x = x + 1; }
   else if( names[j] == 'xavier'  ){ x = x + 1; }
   else if( names[j] == 'yolanda'  ){ x = x + 1; }
   else if( names[j] == 'zidian'  ){ x = x + 1; }
  }
 }
 
 return x;
}

Next I looked at the switch statements.
private  function testSwitchStatements( names:Array , iterations:int ) : int {
 var x:int = 0;
 for( var i:int = 0; i < iterations; i++ ){
  for( var j:int = 0; j < names.length; j++ ){
   switch(names[j]){
       case 'amy':
        x = x + 1;
        break; 
       case 'bob':
        x = x + 1;
        break;
       case 'curly' :
        x = x + 1;
        break;
       case 'dawn' :
        x = x + 1;
        break;
       case 'erick' :
        x = x + 1;
        break;
       case 'fred' :
        x = x + 1;
        break;
       case 'george' :
        x = x + 1;
        break;
       case 'harley' :
        x = x + 1;
        break;
       case 'ian' :
        x = x + 1;
        break;
       case 'jim' :
        x = x + 1;
        break;
       case 'kim' :
        x = x + 1;
        break;
       case 'liam' :
        x = x + 1;
        break;
       case 'moe' :
        x = x + 1;
        break;
       case 'nate' :
        x = x + 1;
        break;
       case 'oliver' :
        x = x + 1;
        break;
       case 'penelope' :
        x = x + 1;
        break;
       case 'quinn' :
        x = x + 1;
        break;
       case 'robb' :
        x = x + 1;
        break;
       case 'silas' :
        x = x + 1;
        break;
       case 'tim' :
        x = x + 1;
        break;
       case 'ulysses' :
        x = x + 1;
        break;
       case 'victor':
        x = x + 1;
        break; 
       case 'waldo' :
        x = x + 1;
        break;
       case 'xavier' :
        x = x + 1;
        break;
       case 'yolanda' :
        x = x + 1;
        break;
       case 'zidian' :
        x = x + 1;
        break;
       default :
      }
     }
    }
    return x;
}

Finally I created a function for the object of function pointers.
private function testFunctionPtrs( names:Array , iterations:int ) : int {
 
 var functions:Object = new Object();
 functions['amy'] = function a( y:int ) : int { return (y+1); };
 functions['bob'] = function b( y:int ) : int { return (y+1); };
 functions['curly'] = function c( y:int ) : int { return (y+1); };
 functions['dawn'] = function d( y:int ) : int { return (y+1); };
 functions['erick'] = function e( y:int ) : int { return (y+1); };
 functions['fred'] = function f( y:int ) : int { return (y+1); };
 functions['george'] = function g( y:int ) : int { return (y+1); };
 functions['harley'] = function h( y:int ) : int { return (y+1); };
 functions['ian'] = function i( y:int ) : int { return (y+1); };
 functions['jim'] = function j( y:int ) : int { return (y+1); };
 functions['kim'] = function k( y:int ) : int { return (y+1); };
 functions['liam'] = function l( y:int ) : int { return (y+1); };
 functions['moe'] = function m( y:int ) : int { return (y+1); };
 functions['nate'] = function n( y:int ) : int { return (y+1); };
 functions['oliver'] = function o( y:int ) : int { return (y+1); };
 functions['penelope'] = function p( y:int ) : int { return (y+1); };
 functions['quinn'] = function q( y:int ) : int { return (y+1); };
 functions['robb'] = function r( y:int ) : int { return (y+1); };
 functions['silas'] = function s( y:int ) : int { return (y+1); };
 functions['tim'] = function t( y:int ) : int { return (y+1); };
 functions['ulysses'] = function u( y:int ) : int { return (y+1); };
 functions['victor'] = function v( y:int ) : int { return (y+1); };
 functions['waldo'] = function w( y:int ) : int { return (y+1); };
 functions['xavier'] = function X( y:int ) : int { return (y+1); };
 functions['yolanda'] = function Y( y:int ) : int { return (y+1); };
 functions['zidian'] = function Z( y:int ) : int { return (y+1); };
 
 var x:int = 0;
 for( var i:int = 0; i < iterations; i++ ){
  for( var j:int = 0; j < names.length; j++ ){
   x = functions[names[j]](x);
  }
 }
 
 return x;
}

Tuesday, February 24, 2009

Add Image overlay to ESRI Map in FLEX

Adding an image overlay to an ESRI Map in Flex is not really a default functionality. So when a project came along that required one I wrote this. There does seem to be a size limitation for the image you are trying to load. I did not really have a chance to explore the issue, but it worked when the image width was under 2500 pixels wide.
package com.cinque_fiori.mapping.symbols
{
 import com.esri.ags.Graphic;
 import com.esri.ags.Map;
 import com.esri.ags.esri_internal;
 import com.esri.ags.geometry.MapPoint;
 import com.esri.ags.symbol.Symbol;
 
 import flash.display.BitmapData;
 import flash.geom.Matrix;

 use namespace esri_internal;
 


 public class BitmapMarkerSymbol extends Symbol
 {
  
  private var _bitmap:BitmapData;
  private var _lowerLeft:MapPoint;
  private var _visible:Boolean;

  public function BitmapMarkerSymbol ()
  {
   super();
   this._lowerLeft = new MapPoint();
   this._bitmap;
   this._visible = true;
  }


  override esri_internal function drawGraphic( map : Map, graphic : Graphic ): void
  {
   if( graphic.geometry is MapPoint ) {
    drawBitmapOnMap( map, graphic, MapPoint( graphic.geometry ));
   }
  }


  private function drawBitmapOnMap( map : Map, graphic:Graphic,mapPoint:MapPoint ): void {
   if( this._lowerLeft != null && this._bitmap != null ){
    graphic.x = map.mapToContainerX(mapPoint.x);
    graphic.y = map.mapToContainerY(mapPoint.y);

    var w:Number = map.mapToContainerX(this._lowerLeft.x) - graphic.x;
    var h:Number = map.mapToContainerY(this._lowerLeft.y) - graphic.y;
    var m:Matrix = new Matrix(w/this._bitmap.width,0,0,h/this._bitmap.height,0,0);

    graphic.graphics.clear();
    if(this._visible){
     graphic.graphics.beginBitmapFill( this._bitmap, m , false , true );
     graphic.graphics.drawRect(0,0,w,h);
     graphic.graphics.endFill();
    }
   }
  }

  public function get lowerLeft() : MapPoint{
   return this._lowerLeft;
  }

  public function set lowerLeft( pt:MapPoint ) : void{
   this._lowerLeft = pt;
  }

  public function get bitmap() : BitmapData{
   return this._bitmap;
  }

  public function set bitmap( bitmapData:BitmapData ) : void{
   this._bitmap = bitmapData;
  }
  
  public function get visible() : Boolean{
   return this._visible; 
  }
  
  public function set visible( visible:Boolean ) : void{
   this._visible = visible;
  }
 }
}