Recent

Author Topic: [SOLVED] hashlist with multiple specialization of TNullable  (Read 2386 times)

nomorelogic

  • Full Member
  • ***
  • Posts: 155
[SOLVED] hashlist with multiple specialization of TNullable
« on: January 10, 2022, 09:36:27 am »
hi all

I've a FpHashList where I store multiple specializaed instances of TNullable using New and Dispose.
Below you can see I store in the hashlist a specialized string and a specialized integer.

Using Dispose I need to call Dispose with the correct typed pointer but - during the for loop - I don't know the type at the current position.
Uncommentig "this code works" no exception is raised.

How I can detect the correct pointer type to call Dispose?
I need something like the "is" when comparing classes but for advanced records.

thanks
nomorelgoic


Code: Pascal  [Select][+][-]
  1. program test_hashlist_nullable;
  2.  
  3. uses sysutils, nullable, Contnrs;
  4.  
  5. procedure TestNullable;
  6. type
  7.   TNullString = specialize TNullable<String>;
  8.   PNullString = ^TNullString;
  9.  
  10.   TNullInteger= specialize TNullable<Integer>;
  11.   PNullInteger = ^TNullInteger;
  12.  
  13. var nullint: PNullInteger;
  14.     nullstr: PNullString;
  15.     i: integer;
  16.     HashList: TFPHashList;
  17. begin
  18.   WriteLn('Start');
  19.   HashList:=TFPHashList.Create;
  20.   try
  21.     // set values
  22.     nullstr:=new(PNullString);
  23.     nullstr^:='value 1';
  24.     HashList.Add('one', nullstr);
  25.  
  26.     nullint:=new(PNullInteger);
  27.     nullint^:=2;
  28.     HashList.Add('two', nullint);
  29.  
  30.     // write
  31.     WriteLn('one = ', PNullString(HashList.Find('one'))^.Value);
  32.     WriteLn('two = ', PNullInteger(HashList.Find('two'))^ .Value);
  33.  
  34.  
  35.     // free values
  36.     for i := 0 to HashList.Count -1 do begin
  37.         try
  38.           WriteLn('Dispose ' + i.ToString);
  39.           Dispose( PNullString(HashList[i]) );
  40.  
  41.           { this code works
  42.           case i of
  43.             0: Dispose( PNullString(HashList[i]) );
  44.             1: Dispose( PNullInteger(HashList[i]) );
  45.           end;
  46.           }
  47.         except
  48.           on e: exception do begin
  49.              WriteLn('Error during dispose (' + i.ToString + '):' + e.Message);
  50.           end;
  51.         end;
  52.     end;
  53.  
  54.   finally
  55.     // free resources
  56.     FreeAndNil(HashList);
  57.     WriteLn('Stop');
  58.   end;
  59. end;
  60.  
  61.  
  62. begin
  63.   TestNullable;
  64. end.
  65.  


Edit:
fixed a message in code
« Last Edit: January 10, 2022, 04:05:05 pm by nomorelogic »

Thaddy

  • Hero Member
  • *****
  • Posts: 11517
Re: hashlist with multiple specialization of TNullable
« Reply #1 on: January 10, 2022, 11:11:54 am »
Well, rtti might help a little here. Although with generics you can't - possibly easily -retrieve the distinct type name, of the specialization,the crc value is distinct for any speciailzation.
Here you can see that s2 has the same type as s and that n2 has the same type as n.
Consider:
Code: Pascal  [Select][+][-]
  1. {$mode obfpc}
  2. uses nullable,typinfo;
  3. type
  4.   TNullableInteger = specialize TNullable<integer>;
  5.   TNullableString = specialize TNullable<string>;
  6. var
  7.   Info:PTypeInfo;
  8.   n,n2:TNullableInteger;
  9.   s,s2:TNullableString;
  10. begin
  11.   Info := TypeInfo(n);
  12.   writeln(info^.name);
  13.   Info := TypeInfo(s);
  14.   writeln(info^.name);  
  15.   Info := TypeInfo(n2);
  16.   writeln(info^.name);  
  17.   Info := TypeInfo(s2);
  18.   writeln(info^.name);  
  19. end.
But this may very well be implementation detail.
I will see if I can get at the typeinfo for TNullable.value.
If that is possible you get tkInteger and tkString.
Currenty experimenting with TrttiContext from rtti.pp

« Last Edit: January 10, 2022, 12:11:12 pm by Thaddy »
Путин преступник. Россияне дезинформированы.

nomorelogic

  • Full Member
  • ***
  • Posts: 155
Re: hashlist with multiple specialization of TNullable
« Reply #2 on: January 10, 2022, 11:34:53 am »
I will see if I can get at the typeinfo for TNullable.value.
If that is possible you get tkInteger and tkString.

I think this is surely a better way for performances


Thaddy

  • Hero Member
  • *****
  • Posts: 11517
Re: hashlist with multiple specialization of TNullable
« Reply #3 on: January 10, 2022, 01:27:03 pm »
Must have been sleeping. It is really easy:
Code: Pascal  [Select][+][-]
  1. {$mode obfpc}
  2. uses nullable,typinfo;
  3. type
  4.   TNullableInteger = specialize TNullable<integer>;
  5.   TNullableString = specialize TNullable<string>;
  6. var
  7.   Info:PTypeInfo;
  8.   n,n2:TNullableInteger;
  9.   s,s2:TNullableString;
  10. begin
  11.   Info := TypeInfo(n.value);
  12.   writeln(info^.kind);
  13.   Info := TypeInfo(s.value);
  14.   writeln(info^.kind);  
  15.   Info := TypeInfo(n2.value);
  16.   writeln(info^.kind);  
  17.   Info := TypeInfo(s2.value);
  18.   writeln(info^.kind);  
  19. end.
So to determin the concrete type, simply query the typeinfo for TNullable<T>.Value.
« Last Edit: January 10, 2022, 02:53:59 pm by Thaddy »
Путин преступник. Россияне дезинформированы.

PascalDragon

  • Hero Member
  • *****
  • Posts: 4014
  • Compiler Developer
Re: hashlist with multiple specialization of TNullable
« Reply #4 on: January 10, 2022, 01:29:34 pm »
Well, rtti might help a little here. Although with generics you can't - possibly easily -retrieve the distinct type name, of the specialization,the crc value is distinct for any speciailzation.

RTTI won't help here, because all that nomorelogic has is a pointer. And neither the pointer nor what it points to has any type information by itself.

So to determin the concrete type, simply query the typeinfo for TNullable<T>.Value.

That is nonsense, because nomorelogic would need to cast to a specialized TNullable<> first and then the type information would be whatever it was casted to.

How I can detect the correct pointer type to call Dispose?
I need something like the "is" when comparing classes but for advanced records.

There is no safe way to do this. You additionally need to store what kind of type you're dealing with. You need to do this anyway if you want to use the values, because there you'd have to guess as well otherwise.

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: hashlist with multiple specialization of TNullable
« Reply #5 on: January 10, 2022, 02:31:57 pm »
For the simple example you have, the compiler emits FreeMem for Dispose (to be more precise it calls fpc_freemem). You can, in this specific case, replace Dispose with FreeMem:
Code: Pascal  [Select][+][-]
  1.           //Dispose( PNullString(HashList[i]) );
  2.           Freemem(HashList[i]);

In the general case, this may not work, the compiler generates a node for Dispose statements
Dispose ==> in_dispose_x ==> new_dispose_statement(is_new:boolean) : tnode;

Take a look at function new_dispose_statement(is_new:boolean) in unit pinline.pas

nomorelogic

  • Full Member
  • ***
  • Posts: 155
Re: hashlist with multiple specialization of TNullable
« Reply #6 on: January 10, 2022, 04:00:58 pm »
thank you all for suggestions

@Thaddy and @PascalDragon
yes the question is I only have a pointer and no other info

anyway what I need is: instead of this

Code: [Select]
var i: integer
begin
  i := 5;
  writeln('integer I =', i);
end;

I want to write this

Code: [Select]
var ms: TMemoryspace;
begin
  ms:=TMemoryspace.Create;
  // property TMemoryspace.Integers wraps TNullableIntegers using Getter and Setter
  ms.Integers['i'] := 5;
  writeln('integer I =',ms.Integers['i']);
  ms.Free;
end;

thus I know what type I need to have a value
but don't know at dispose time

@engkin
yes, your suggestion about use FreeMem works
following code works fine


Code: Pascal  [Select][+][-]
  1. program test_hashlist_nullable;
  2.  
  3. uses sysutils, nullable, Contnrs;
  4.  
  5. procedure TestNullable;
  6. type
  7.   TNullString = specialize TNullable<String>;
  8.   PNullString = ^TNullString;
  9.  
  10.   TNullInteger= specialize TNullable<Integer>;
  11.   PNullInteger = ^TNullInteger;
  12.  
  13. var nullint: PNullInteger;
  14.     nullstr: PNullString;
  15.     i: integer;
  16.     HashList: TFPHashList;
  17. begin
  18.   WriteLn('Start');
  19.   HashList:=TFPHashList.Create;
  20.   try
  21.     // set values
  22.     nullstr:=new(PNullString);
  23.     nullstr^:='value 1';
  24.     HashList.Add('one', nullstr);
  25.  
  26.     nullint:=new(PNullInteger);
  27.     nullint^:=2;
  28.     HashList.Add('two', nullint);
  29.  
  30.     // write
  31.     WriteLn('one = ', PNullString(HashList.Find('one'))^.Value);
  32.     WriteLn('two = ', PNullInteger(HashList.Find('two'))^ .Value);
  33.  
  34.  
  35.     // free values
  36.     for i := 0 to HashList.Count -1 do begin
  37.         try
  38.           WriteLn('Dispose ' + i.ToString);
  39.           // Dispose( PNullString(HashList[i]) );
  40.           FreeMem(HashList[i]);
  41.         except
  42.           on e: exception do begin
  43.              WriteLn('Error during sispose (' + i.ToString + '):' + e.Message);
  44.           end;
  45.         end;
  46.     end;
  47.  
  48.   finally
  49.     // free resources
  50.     FreeAndNil(HashList);
  51.     WriteLn('Stop');
  52.   end;
  53. end;
  54.  
  55.  
  56. begin
  57.   TestNullable;
  58. end.
  59.  

anyway I think I'm going to store the type in order to have "schema"

thank you all again
nomorelogic

 

TinyPortal © 2005-2018