Recent

Author Topic: Associative arrays class implementation  (Read 22807 times)

BioHazard

  • Jr. Member
  • **
  • Posts: 57
  • Starless...
Associative arrays class implementation
« on: February 09, 2011, 01:24:41 pm »
All the questions and bugs presented in the topic opening were solved during topic and post contains active working associative array unit:

--------------------------------------------------------------------------------------------------------------

Hm as i have coded a bit in any languages during my experience i meet comfort in php in many cases. And after that when i had project in other languages was implementing libraries with php similar functionality. The associative array is the major tool in everyday use. So i had a working class with basics of associative array in Delphi. I want to implement it in Lazarus but it throws some errors for this time:

And they are represented as three questions in topic:

2. Second is: It seams that i cant have class method and some class method local variable with same names ?

1. First is: I dont remember why i needed stdcall flags on some class methods.

But i remember that i had some projects in delphi. Before i translate this code for lazarus i want to introduce myself why this features are disabled or not working ?

3. And is some of them caused by compiler directive {$mode objfpc} ?

Code: [Select]
unit _Arrays;

{$mode objfpc}

interface

uses
  Classes, SysUtils;

type generic TArray <TIndex, TValue> = class
private
  Values: array of TValue;
  Indexes: array of TIndex;
  Ticker: Integer;
  function Key (Index: TIndex): Integer;
  procedure Write (Index: TIndex; Value: TValue);
  function Read (Index: TIndex): TValue;
public
  Position: Integer;
  constructor Create;
  property Items [Index: TIndex]: TValue read Read write Write; default;
  procedure Reset;
  function Index: TIndex;
  function Value: TValue;
  function Foreach: Boolean;
  function Count: Integer;
  procedure Sort;
  procedure Delete (Element: TIndex);
end;

type
  TArrayIntegerString = specialize TArray <Integer, String>;
  TArrayStringInteger = specialize TArray <String, Integer>;
  TArrayStringString = specialize TArray <String, String>;
  TArrayIntegerInteger = specialize TArray <String, String>;

implementation

constructor TArray.Create;
 begin
   SetLength(Indexes, 0);
   SetLength(Values, 0);
   Position := 0;
   Ticker := 0;
 end;

 function TArray.Foreach: Boolean;
 begin
   if (Ticker<Count) then
   begin
     Result := True;
     Ticker := Ticker + 1;
     Position := Ticker - 1;
   end
   else
   begin
     Result := False;
     Reset;
   end;
 end;

 function TArray.Count: Integer;
 begin
   Result := Length (Indexes)
 end;

 function TArray.Index: TIndex;
 begin
   Result := Indexes[Position];
 end;

 function TArray.Value: TValue;
 begin
   Result:= Values[Position];
 end;

 procedure TArray.Reset;
 begin
   Ticker := 0;
   Position := 0;
 end;

 procedure TArray.Write (Index: TIndex; Value: TValue);
 var Cursor: Integer;
 begin
   Cursor := Key(Index);
   if Cursor=-1 then
   begin
     SetLength (Indexes, Length(Indexes)+1);
     SetLength (Values, Length(Values)+1);
     Cursor := Length(Indexes)-1;
   end;
   Indexes[Cursor] := Index;
   Values[Cursor] := Value;
 end;

 function TArray.Read (Index: TIndex): TValue;
 var Cursor: Integer;
 begin
   Cursor := Key (Index);
   if Cursor=-1 then
   begin
     Result := Null;
   end
   else
   begin
     Result := Values[Cursor];
   end;
 end;

 function TArray.Key (Index: TIndex): Integer;
 var
   Current,Records: Integer;
 begin
   Result := -1;
   Records := Length (Indexes);
   for Current:=0 to Records-1 do
   begin
     if Indexes[Current]=Index then
     begin
       Result := Current;
       break;
     end;
   end;
 end;

 procedure TArray.Sort;
 var
   Current,Records: Integer;
   ValueBuffer: TValue;
   IndexBuffer: TIndex;
 begin
   Records := Length (Indexes);
   ValueBuffer := Values[0];
   for Current:=1 to Records-1 do
   begin
        if (ValueBuffer>Values[Current]) then
        begin
          Values[Current-1]:= Values[Current];
          Values[Current] := ValueBuffer;
          IndexBuffer := Indexes[Current-1];
          Indexes[Current-1] := Indexes[Current];
          Indexes[Current] := IndexBuffer;
        end;
        ValueBuffer := Values[Current];
   end;
 end;

 procedure TArray.Delete (Element: TIndex);
 var
   Current: Integer;
 begin
   Current := Key(Element);
   if Current > High(Indexes) then
   begin
      Exit;
   end;
   if Current < Low(Indexes) then
   begin
      Exit;
   end;
   if Current = High(Indexes) then
   begin
     SetLength(Indexes, Length(Indexes) - 1) ;
     Exit;
   end;
   Finalize(Indexes[Current]) ;
   System.Move(Indexes[Current +1], Indexes[Current],(Length(Indexes) - Current -1) * SizeOf(TIndex) + 1) ;
   SetLength(Indexes, Length(Indexes) - 1);
   if Current > High(Values) then
   begin
      Exit;
   end;
   if Current < Low(Values) then
   begin
      Exit;
   end;
   if Current = High(Values) then
   begin
     SetLength(Values, Length(Values) - 1) ;
     Exit;
   end;
   Finalize(Values[Current]) ;
   System.Move(Values[Current +1], Values[Current],(Length(Values) - Current -1) * SizeOf(TValue) + 1) ;
   SetLength(Values, Length(Values) - 1);
 end;

end.

Together world will be better...

: )
« Last Edit: February 11, 2011, 08:20:17 pm by BioHazard »

theo

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1946
Re: Associative arrays: Implementing it by class [class parsing bugs ?]
« Reply #1 on: February 09, 2011, 01:44:11 pm »
3. And is some of them caused by compiler directive {$mode objfpc} ?

Try {$mode delphi} and see if it changes sth.

BioHazard

  • Jr. Member
  • **
  • Posts: 57
  • Starless...
Re: Associative arrays: Implementing it by class [class parsing bugs ?]
« Reply #2 on: February 09, 2011, 01:47:29 pm »
3. And is some of them caused by compiler directive {$mode objfpc} ?

Try {$mode delphi} and see if it changes sth.

Lol it worked in delphi mode without any changes...

Thanks...

: )

Where can i find what are the basic differences between modes ?

captian jaster

  • Guest
Re: Associative arrays: Implementing it by class [class parsing bugs ?]
« Reply #3 on: February 09, 2011, 02:10:23 pm »
3. And is some of them caused by compiler directive {$mode objfpc} ?

Try {$mode delphi} and see if it changes sth.

Lol it worked in delphi mode without any changes...

Thanks...

: )

Where can i find what are the basic differences between modes ?
Here ya go

Leledumbo

  • Hero Member
  • *****
  • Posts: 8836
  • Programming + Glam Metal + Tae Kwon Do = Me

BioHazard

  • Jr. Member
  • **
  • Posts: 57
  • Starless...
Re: Associative arrays: Implementing it by class [class parsing bugs ?]
« Reply #5 on: February 09, 2011, 09:15:22 pm »
Well i modified unit for interpreter or compiler object pascal mode:

Now it needs sorting as water dont needs fish and speed optimization cause of variants.

It uses variants for all type support in keys or in indexes. I dont know for now how to achieve the same effect by pointers or something else in lazarus and free pascal for now.


Usage exactly:

Code: [Select]
procedure TForm1.Button3Click(Sender: TObject);
var
  FruitColors: TArray;
  TestString: String;
begin
  FruitColors := TArray.Create;
  FruitColors['Apple'] := 'Green';
  FruitColors['Peach'] := False;
  FruitColors['Some Fruit'] := 14;
  Form1.Caption := FruitColors['Some Fruit'];
  while FruitColors.Foreach do
  begin
    Form1.Caption := FruitColors[FruitColors.Position];
  end;
  Form1.Caption := FruitColors.Count;
end;

Class unit after modify:

Code: [Select]
unit _Arrays;

{$mode objfpc}

interface

uses
  Classes, SysUtils;

type TArray = class
private
  Values: array of Variant;
  Indexes: array of Variant;
  function Key (Index: Variant): Integer;
  procedure Write (Index, Value: Variant);
  function Read (Index: Variant): Variant;
public
  Position: Integer;
  constructor Create;
  property Items [Index: Variant]: Variant read Read write Write; default;
  procedure Reset;
  function Index: Variant;
  function Value: Variant;
  function Foreach: Boolean;
  function Count: Integer;
  procedure Sort;
end;

implementation

constructor TArray.Create;
 begin
   SetLength(Indexes, 0);
   SetLength(Values, 0);
   Self.Position := 0;
 end;

 function TArray.Foreach: Boolean;
 begin
   Self.Position := Self.Position + 1;
   if Self.Position>Self.Count-1 then
   begin
     Result := True;
   end
   else
   begin
     Result := False;
   end;
 end;

 function TArray.Count: Integer;
 begin
   Result := Length (Self.Indexes)
 end;

 function TArray.Index: Variant;
 begin
   Result := Self.Indexes[Self.Position];
 end;

 function TArray.Value: Variant;
 begin
   Result:= Self.Values[Self.Position];
 end;

 procedure TArray.Reset;
 begin
   Self.Position := 0;
 end;

 procedure TArray.Write (Index, Value: Variant);
 var Cursor: Integer;
 begin
   Cursor := Self.Key(Index);
   if Cursor=-1 then
   begin
     SetLength (Self.Indexes, Length(Self.Indexes)+1);
     SetLength (Self.Values, Length(Self.Values)+1);
     Cursor := Length(Self.Indexes)-1;
   end;
   Self.Indexes[Cursor] := Index;
   Self.Values[Cursor] := Value;
 end;

 function TArray.Read (Index: Variant): Variant;
 var Cursor: Integer;
 begin
   Cursor := Self.Key (Index);
   if Cursor=-1 then
   begin
     Result := '';
   end
   else
   begin
     Result := Self.Values[Cursor];
   end;
 end;

 function TArray.Key (Index: Variant): Integer;
 var Current,Records: Integer;
 begin
   Result := -1;
   Records := Length (Self.Indexes);
   for Current:=0 to Records-1 do
   begin
     if Self.Indexes[Current]=Index then
     begin
       Result := Current;
       break;
     end;
   end;
 end;

 procedure TArray.Sort;
 var Current,Records: Integer;
 begin
   Records := Length (Self.Indexes);
   for Current:=0 to Records-1 do
   begin

   end;
 end;

end.
« Last Edit: February 09, 2011, 09:21:17 pm by BioHazard »

Marc

  • Administrator
  • Hero Member
  • *
  • Posts: 2695
Re: Associative arrays class implementation
« Reply #6 on: February 10, 2011, 01:52:38 am »
In a strong typed language like pascal, why would I need to store different types in the same array ?
If you need this your class/program design is wrong.
//--
{$I stdsig.inc}
//-I still can't read someones mind
//-Bugs reported here will be forgotten. Use the bug tracker

BioHazard

  • Jr. Member
  • **
  • Posts: 57
  • Starless...
Re: Associative arrays class implementation
« Reply #7 on: February 10, 2011, 09:29:39 am »
In a strong typed language like pascal, why would I need to store different types in the same array ?
If you need this your class/program design is wrong.

Yes you are right but variants are caused because of the goal - an associative array class to work with any types of indexes and values.

It may be redesigned like to pass key and value types to constructor: like TArray.Create (String, Float);

But I do not know yet how to implement it in pascal gently.

It is clear that there is need of associative arrays for to have more productive programing process focused on program logic and not on technical solutions besides logic. There was always important high level programing tools on low level programing languages for me of course pascal is not low level compared with c++ but its low compared with php.

So my question is how can I implement something like this:

TArray.Create (String, Float);

And after that private arrays values TArray.Indexes and TArray.Values became string (Values: array of String) and float (Values: array of Float) and in some other cases some type and some type ?

Must i have some predefined propertys of class type of array for every basic type in pascal and use some of them after key and value types are specified in class constructor ?

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12847
  • FPC developer.
Re: Associative arrays class implementation
« Reply #8 on: February 10, 2011, 11:18:19 am »
Generics are the way to do this. Look at the fgl unit.

BioHazard

  • Jr. Member
  • **
  • Posts: 57
  • Starless...
Re: Associative arrays class implementation
« Reply #9 on: February 10, 2011, 03:11:10 pm »
Well I modified library it now uses generics not anymore variants but I meet with one discomfort as compiler says generics without type specializations cannot be used as type of variable on:

FruitColors: TArray <Integer, String>;

 And I am forced to declare TArrayStringString = specialize TArray <String, String> for associative array with strings in keys and values and then use it:

 FruitColors: TArrayStringString;

* * *

 Question: Am I doing something wrong there FruitColors: TArray <Integer, String> or compiler does not support it yet / forever ?

Code: [Select]
procedure TForm1.Button3Click(Sender: TObject);
var
  //FruitColors: TArray <Integer, String>; //Error: Generics without specialization cannot be used as a type for a variable
  FruitColors: TArrayStringString;
begin
  
  FruitColors := TArrayStringString.Create;
  FruitColors['Something'] := 'Somehow';
  FruitColors['Bannana'] := 'Yellow';
  FruitColors['Manana'] := 'White';
  FruitColors['Apple'] := 'Red';

  Form1.Caption := FruitColors['Bannana'];

end;

The generic version of associative array class is:

Code: [Select]
unit _Arrays;

{$mode objfpc}

interface

uses
  Classes, SysUtils;

type generic TArray <TIndex, TValue> = class
private
  Values: array of TValue;
  Indexes: array of TIndex;
  function Key (Index: TIndex): Integer;
  procedure Write (Index: TIndex; Value: TValue);
  function Read (Index: TIndex): TValue;
public
  Position: Integer;
  constructor Create;
  property Items [Index: TIndex]: TValue read Read write Write; default;
  procedure Reset;
  function Index: TIndex;
  function Value: TValue;
  function Foreach: Boolean;
  function Count: Integer;
  procedure Sort;
end;

type
  //Some beta specializations
  TArrayIntegerString = specialize TArray <Integer, String>;
  TArrayStringInteger = specialize TArray <String, Integer>;
  TArrayStringString = specialize TArray <String, String>;
  TArrayIntegerInteger = specialize TArray <String, String>;

implementation

constructor TArray.Create;
 begin
   SetLength(Indexes, 0);
   SetLength(Values, 0);
   Self.Position := 0;
 end;

 function TArray.Foreach: Boolean;
 begin
   Self.Position := Self.Position + 1;
   if Self.Position>Self.Count-1 then
   begin
     Result := True;
   end
   else
   begin
     Result := False;
   end;
 end;

 function TArray.Count: Integer;
 begin
   Result := Length (Self.Indexes)
 end;

 function TArray.Index: TIndex;
 begin
   Result := Self.Indexes[Self.Position];
 end;

 function TArray.Value: TValue;
 begin
   Result:= Self.Values[Self.Position];
 end;

 procedure TArray.Reset;
 begin
   Self.Position := 0;
 end;

 procedure TArray.Write (Index: TIndex; Value: TValue);
 var Cursor: Integer;
 begin
   Cursor := Self.Key(Index);
   if Cursor=-1 then
   begin
     SetLength (Self.Indexes, Length(Self.Indexes)+1);
     SetLength (Self.Values, Length(Self.Values)+1);
     Cursor := Length(Self.Indexes)-1;
   end;
   Self.Indexes[Cursor] := Index;
   Self.Values[Cursor] := Value;
 end;

 function TArray.Read (Index: TIndex): TValue;
 var Cursor: Integer;
 begin
   Cursor := Self.Key (Index);
   if Cursor=-1 then
   begin
     Result := Null;
   end
   else
   begin
     Result := Self.Values[Cursor];
   end;
 end;

 function TArray.Key (Index: TIndex): Integer;
 var Current,Records: Integer;
 begin
   Result := -1;
   Records := Length (Self.Indexes);
   for Current:=0 to Records-1 do
   begin
     if Self.Indexes[Current]=Index then
     begin
       Result := Current;
       break;
     end;
   end;
 end;

 procedure TArray.Sort;
 var Current,Records: Integer;
 begin
   Records := Length (Self.Indexes);
   for Current:=0 to Records-1 do
   begin

   end;
 end;

end.
« Last Edit: February 10, 2011, 03:14:07 pm by BioHazard »

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12847
  • FPC developer.
Re: Associative arrays class implementation
« Reply #10 on: February 10, 2011, 05:43:05 pm »
  Question: Am I doing something wrong there FruitColors: TArray <Integer, String> or compiler does not support it yet / forever ?

Yes that is normal, and I'm not aware of plans to change that. This because such type actually creates code, and using the same TSometype<x,y> declaration in different units would generate multiple instances.   This is fixable, but quite hard, so don't hold your breath.
 

Leledumbo

  • Hero Member
  • *****
  • Posts: 8836
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Associative arrays class implementation
« Reply #11 on: February 10, 2011, 06:36:25 pm »
Quote
This because such type actually creates code, and using the same TSometype<x,y> declaration in different units would generate multiple instances.
Yep, this is an advantage over C++/Delphi implementation actually, with the cost of flexibility (recursive definition etc.).

BioHazard

  • Jr. Member
  • **
  • Posts: 57
  • Starless...
Re: Associative arrays class implementation
« Reply #12 on: February 10, 2011, 07:30:31 pm »
Hm it makes a sense of discomfort but its ok just in case as hardware is being improved over day you can think a bit less on performance and improve programing process comfort. This is still my opinion that future programing languages will take this goal...


Leledumbo

  • Hero Member
  • *****
  • Posts: 8836
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Associative arrays class implementation
« Reply #13 on: February 11, 2011, 08:25:36 am »
Just FYI, associative array is actually already implemented in fgl unit as TFPGMap. Moreover, STLPascal project has also implemented it.

BioHazard

  • Jr. Member
  • **
  • Posts: 57
  • Starless...
Re: Associative arrays class implementation
« Reply #14 on: February 11, 2011, 11:53:12 am »
Fgl unit fires compilation errors. So i updated foreach method. Added value sort method. And updated unit code in the first post.

Works like butter on the bread.

It needs key and delete methods. It is not using TList class.

foreach usage:

Code: [Select]
 while FruitColors.Foreach do
  begin
    Form1.Caption:= Form1.Caption+'[' + FruitColors.Index + ']:' + FruitColors.Value;
  end

array is declared using some pre specialized type:

Code: [Select]
TArrayStringString = specialize TArray <String, String>; //This is predeclared in _Array.pas

var FruitColors : TArrayStringString; //means strings in keys and values

FruitColors:= TArrayStringString.Create;
« Last Edit: February 11, 2011, 11:54:59 am by BioHazard »

 

TinyPortal © 2005-2018