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.
_______________________________________________ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel