[fpc-devel] Dynamic indexing (multi-dimensional-indexing) (alternative version 0.07 build-in enumerator for TDynamicIndex, order corrected )

Skybuck Flying skybuck2000 at hotmail.com
Sun Jul 3 04:00:18 CEST 2011


I forgot how important it was to start with the lowest dimension first when 
multiplieing dimensions.

This is the only slightly dangerous issue/problem remaining which could 
probably be solved by a compiler.

The compiler could perhaps put it in the correct order somehow.

Maybe the programmer would need to indicate the order of the dimensions like 
so:

Block.Order := 2;
Element.Order := 1;

Corrected version 0.07 test program:

// *** Begin of Test Program ***

program TestProgram;


{$APPTYPE CONSOLE}

{

TDynamicIndex

alternative version 0.06 created on 3 july 2011 by Skybuck Flying.

TDynamicIndex reduced to the most basic/simpelst form so that it can be used
for many other types/arrays and so forth.

Instead TMemory is created which accepts TDynamicIndex as parameters to do
lookups. TMemory also has been made more generic so it can contain
different kinds of types.

A more realistic example.

There might still be room to improve this technique if TDynamicIndex could
be used as the loop variable. This will be examined in a next (alternative)
version ! ;)


(It's all about reducing the ammount of code and keep it as simple and well
readable/understandable/self documenting as possible
with quick insight into what everthing does which is good for algorithm
design/development/inspection)

(re-created from my usenet posting from my archive, delphi overwrite
this example with the project file of another folder ?!
fortunately nothing was lost in the process except this text slightly
reformatted.)

}

{

alternative version 0.07 created on 3 july 2011 by Skybuck Flying.

Very nice :

TDynamicIndex improvements:

+ Build-in support for enumerators
+ Build-in enumerator for TDynamicIndex
+ Implicit conversion to integer   (index is returned as integer)
+ Implicit conversion to string    (index is returned as string)
+ Additional properties to get value (index) and dimension.

DynamicIndex can now be used in for in loops ! ;) =D

TMemory improvements:
+ memory cleaned up via setting count property to zero

!!! CAUTION !!!:

It is important to write the lowest dimensions first and the highest 
dimensions later
when multiplieing otherwise it won't work properly.

!!!!!!!!!!!!!!!


}


uses
SysUtils;

type
{
TDynamicIndexEnumerator = record
private
  FArray: TBytes;
  FIndex: Integer;
  function GetCurrent : integer;
public

end;
}

TDynamicIndex = record
private
  mIndex : integer;
  mDimension : integer;

  function GetCurrent : TDynamicIndex; inline;

  function StoreIndex( ParaIndex : integer ) : TDynamicIndex; inline;
public
  constructor Create( ParaDimension : integer );

  property IndexOperator[ ParaIndex : integer ] : TDynamicIndex read 
StoreIndex; default;

  property Dimension : integer read mDimension write mDimension;
  property Value : integer read mIndex write mIndex;

  class operator Multiply( ParaA, ParaB : TDynamicIndex ) : TDynamicIndex;

  // enumerator functions
  function MoveNext : Boolean; inline;
  property Current : TDynamicIndex read GetCurrent;

  function GetEnumerator : TDynamicIndex;

  // implicit operator so .Value doesn't need to be used when assinging the 
dynamic index to an integer ;)
  class operator Implicit( ParaDynamicIndex : TDynamicIndex  ) : integer;

  // another implicit operator so it automatically gets converted to a 
string ! ;) :)
  class operator Implicit( ParaDynamicIndex : TDynamicIndex ) : string;
end;

constructor TDynamicIndex.Create( ParaDimension : integer );
begin
mIndex := 0;
mDimension := 1;

if ParaDimension > 1 then
begin
  mDimension := ParaDimension;
end;
end;

function TDynamicIndex.StoreIndex( ParaIndex : integer ) : TDynamicIndex;
begin
mIndex := ParaIndex;
result.mIndex := mIndex;
result.mDimension := mDimension;
end;

class operator TDynamicIndex.Multiply( ParaA, ParaB : TDynamicIndex ) : 
TDynamicIndex;
begin
result.mIndex := ParaA.mIndex + (ParaA.mDimension * ParaB.mIndex);
result.mDimension := ParaA.mDimension * ParaB.mDimension;
end;

function TDynamicIndex.MoveNext : Boolean;
begin
result := false;

mIndex := mIndex + 1;
if mIndex < mDimension then
begin
  result := true;
end;
end;

function TDynamicIndex.GetCurrent : TDynamicIndex;
begin
result.mIndex := mIndex;
result.mDimension := mDimension;
end;

function TDynamicIndex.GetEnumerator : TDynamicIndex;
begin
result.mIndex := -1;
result.mDimension := mDimension;
end;

class operator TDynamicIndex.Implicit( ParaDynamicIndex : TDynamicIndex  ) : 
integer;
begin
result := ParaDynamicIndex.mIndex;
end;

class operator TDynamicIndex.Implicit( ParaDynamicIndex : TDynamicIndex ) : 
string;
begin
result := IntToStr( ParaDynamicIndex.mIndex );
end;

type
TMemory<GenericType> = class
private

protected
  mMemory : array of GenericType;
  mCount : integer;

  procedure SetCount( ParaCount : integer );

  function GetElement( ParaIndex : TDynamicIndex ) : GenericType;
  procedure SetElement( ParaIndex : TDynamicIndex; ParaValue : 
GenericType );

public
  constructor Create;
  destructor Destroy; override;

  property Count : integer read mCount write SetCount;

  property Element[ ParaIndex : TDynamicIndex ] : GenericType read 
GetElement write SetElement; default;
end;

constructor TMemory<GenericType>.Create;
begin
inherited Create;

end;

destructor TMemory<GenericType>.Destroy;
begin
Count := 0;

inherited Destroy;
end;

procedure TMemory<GenericType>.SetCount( ParaCount : integer );
begin
mCount := ParaCount;
SetLength( mMemory, mCount );
end;

function TMemory<GenericType>.GetElement( ParaIndex : TDynamicIndex ) : 
GenericType;
begin
result := mMemory[ParaIndex.Value];
end;

procedure TMemory<GenericType>.SetElement( ParaIndex : TDynamicIndex; 
ParaValue : GenericType );
begin
mMemory[ParaIndex.Value] := ParaValue;
end;


procedure Main;
var
mBlockCount : integer;
mElementCount : integer;

mMemory : TMemory<integer>;

mBlock : TDynamicIndex;
mElement : TDynamicIndex;

vBlockIndex : TDynamicIndex;
vElementIndex : TDynamicIndex;
begin
// smaller values set to make the program end soon to test clean up too ;)
mBlockCount := 5;
mElementCount := 20;

mMemory := TMemory<integer>.Create;
mMemory.Count := mBlockCount * mElementCount;

// functions as a dimension holder ;)
mBlock := TDynamicIndex.Create( mBlockCount );
mElement := TDynamicIndex.Create( mElementCount );

// functions as index iterators
vBlockIndex := mBlock;
vElementIndex := mElement;

for vBlockIndex in mBlock do
begin
  for vElementIndex in mElement do
  begin
   mMemory[ vElementIndex * vBlockIndex ] := (vElementIndex * 
vBlockIndex).Value; // nice and short ! ;)
  end;
end;

for vBlockIndex in mBlock do
begin
  for vElementIndex in mElement do
  begin
   writeln( 'BlockIndex: ' + vBlockIndex + ' ElementIndex: ' + vElementIndex 
+ ' mMemory: ', mMemory[ vElementIndex * vBlockIndex ] );

   // I would still ike to be able to write it like this, but I don't know 
if it's possible to make writeln recgonized it
   // and how to do it ;) :) the above method is better for dialogs though 
;)
//   writeln( 'BlockIndex: ', vBlockIndex, ' ElementIndex: ', vElementIndex, 
'mMemory: ', mMemory[ vElementIndex * vBlockIndex ] );
  end;
  readln;
end;

mMemory.Free;
end;

begin
try
  Main;
except
  on E: Exception do
   Writeln(E.ClassName, ': ', E.Message);
end;
ReadLn;
end.

// *** End of Test Program ***

Bye,
  Skybuck. 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freepascal.org/pipermail/fpc-devel/attachments/20110703/0405b4f6/attachment.html>


More information about the fpc-devel mailing list