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.
Bookmarks