Results 1 to 10 of 18

Thread: iterator for array structure

Threaded View

Previous Post Previous Post   Next Post Next Post
  1. #9
    I just made test project in which I implemented Enumeration for 3D array. Implementing Enumeration wasn't hard. But I'm disapointed that I'm geting poorer performance when using enumeration and for in loop in comparison to nested foor loops. This slowdown might be result of my poor implementation.

    Anywhay here is code with some comments for you guys to studdy and use if it comes usefull to you.
    Code:
    unit Unit2;
    interface
    
    uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
      Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, System.Diagnostics, System.TimeSpan, System.Math;
    
    type
      T3DPosition = record
        X,Y,Z: Integer;
      end;
    
      TWorldDataEnumerator = class
      private
        FOwner: TObject;
        FXPos: Integer;
        FYPos: Integer;
        FZPos: Integer;
      protected
        function GetCurrent: T3DPosition;
        function GetWidth: Integer;
        function GetHeight: Integer;
        function GetDepth: Integer;
      public
        constructor Create(AOwner: TObject);
        function MoveNext: Boolean; virtual;
        property Current: T3DPosition read GetCurrent;
        property Width: Integer read GetWidth;
        property Height: Integer read GetHeight;
        property Depth: Integer read GetDepth;
      end;
    
      TWorldData = class(TObject)
      private
        FWidth: Integer;
        FHeight: Integer;
        FDepth: Integer;
        FData: Array of array of array of T3DPosition;
      protected
        function GetData(X,Y,Z: Integer): T3DPosition;
        procedure SetData(X,Y,Z: Integer; Position: T3Dposition);
      public
        constructor Create(Width, Height, Depth: Integer);
        function GetEnumerator: TWorldDataEnumerator;
        property Data[X, Y, Z: Integer]: T3DPosition read GetData write SetData;
        property Width: Integer read FWidth;
        property Height: Integer read FHeight;
        property Depth: Integer read FDepth;
      end;
    
      TForm2 = class(TForm)
        Button1: TButton;
        Memo1: TMemo;
        procedure Button1Click(Sender: TObject);
        procedure FormCreate(Sender: TObject);
        procedure FormDestroy(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
    
    var
      Form2: TForm2;
      WorldData: TWorldData;
    
    implementation
    
    {$R *.dfm}
    
    { TWorldDataEnumerator }
    
    constructor TWorldDataEnumerator.Create(AOwner: TObject);
    begin
        inherited Create;
        //Here we set the owner of this enumerator so we know hose data we itearate though
        FOwner := AOwner;
        //Needs alsways to be one before first item since MoveNext always moves to next item
        FXpos := -1;
        //FYpos and FZpos are not -1 since MoveNext primarly moves only on X axis
        FYpos := 0;
        FZpos := 0;
    end;
    
    function TWorldDataEnumerator.GetCurrent: T3DPosition;
    begin
        result := TWorldData(FOwner).Data[FXpos,FYpos,FZpos];
    end;
    
    function TWorldDataEnumerator.GetDepth: Integer;
    begin
        result := TWorldData(FOwner).Depth;
    end;
    
    function TWorldDataEnumerator.GetHeight: Integer;
    begin
        result := TWorldData(FOwner).Height;
    end;
    
    function TWorldDataEnumerator.GetWidth: Integer;
    begin
        result := TWorldData(FOwner).Width;
    end;
    
    function TWorldDataEnumerator.MoveNext: Boolean;
    begin
        //We set default result of our function to true
        result := True;
        FXpos := FXpos + 1;
        //If FXpos is larger than the width of our data cluster we move to the start
        //of next line
        if FXpos > Width-1 then
        begin
            FXpos := 0;
            FYpos := FYpos + 1;
            //If YPos is larger than height of our data cluster we move to the start
            //of next level
            if FYpos > Height-1 then
            begin
                FYpos := 0;
                FZpos := FZpos + 1;
                //If FZpos is larger than the depth of our data cluster we are already
                //out of bouds of our data cluster so we set result to false so the
                //iterator know it came to the end
                if FZpos > Depth-1 then result := False;
            end;
        end;
    end;
    
    { TWorldData }
    
    constructor TWorldData.Create(Width, Height, Depth: Integer);
    begin
        inherited Create;
        FWidth := Width;
        FHeight := Height;
        FDepth := Depth;
        //Set size of test data
        SetLength(FData,Width,Height,Depth);
    end;
    
    function TWorldData.GetData(X, Y, Z: Integer): T3DPosition;
    begin
        //Get data at certain position
        result := FData[X,Y,Z];
    end;
    
    function TWorldData.GetEnumerator: TWorldDataEnumerator;
    begin
        //We create TWorldDataEnumerator object and pass it as result
        result := TWorldDataEnumerator.Create(self);
    end;
    
    procedure TWorldData.SetData(X, Y, Z: Integer; Position: T3Dposition);
    begin
        //Set data at certain positon
        FData[X,Y,Z] := Position;
    end;
    
    { TForm2 }
    
    procedure TForm2.FormCreate(Sender: TObject);
    var X,Y,Z: Integer;
        Position: T3DPosition;
    begin
        //Create test data
        WorldData := TWorldData.Create(200,200,200);
        for Z := 0 to WorldData.Depth-1 do
        begin
            for Y := 0 to WorldData.Height-1 do
            begin
                for X := 0 to WorldData.Width-1 do
                begin
                    Position.X := X;
                    Position.Y := Y;
                    Position.Z := Z;
                    WorldData.Data[X,Y,Z] := Position;
                end;
            end;
        end;
    end;
    
    procedure TForm2.FormDestroy(Sender: TObject);
    begin
        WorldData.Free;
    end;
    
    procedure TForm2.Button1Click(Sender: TObject);
    var Position: T3DPosition;
        Pos: T3DPosition;
        StopWatch: TStopWatch;
        ElapsedTime: TTimeSpan;
        I,G: Integer;
        X,Y,Z: Integer;
    begin
        G := 10;
        for I := 0 to G do
        begin
            StopWatch := TStopWatch.StartNew;
            for Position in WorldData do
            begin
                Pos := Position;
            end;
            StopWatch.Stop;
            ElapsedTime := StopWatch.Elapsed;
            Memo1.Lines.Add('for in enumeration:'+IntToStr(ElapsedTime.Milliseconds));
        end;
        for I := 0 to g do
        begin
            StopWatch := TStopWatch.StartNew;
            for Z := 0 to WorldData.Depth-1 do
            begin
                for Y := 0 to WorldData.Height-1 do
                begin
                    for X := 0 to WorldData.Width-1 do
                    begin
                        Pos := WorldData.Data[X,Y,Z];
                    end;
                end;
            end;
            StopWatch.Stop;
            ElapsedTime := StopWatch.Elapsed;
            Memo1.Lines.Add('regular nested for loops:'+IntToStr(ElapsedTime.Milliseconds));
        end;
    end;
    
    end.
    EDIT1: Code is written in Delphi XE3.
    As you can see I relly on TStopWatch for time profiling. As far as I know TStopWatch is Delphi specific so you will unfortunately have to find your own way of time-prifiling the code in FPC.
    EDIT2: After a quick search on the web I found that it seems to be similar implementation of TStopWatch made for FPC
    http://stackoverflow.com/questions/1...his-tstopwatch
    Last edited by SilverWarior; 20-06-2013 at 12:56 PM.

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •