Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2012-05

Streaming of Generics

5 messages · 4 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Kornel Kisielewicz

Hello all,

I want to find a way to write a streaming mechanic for Generic data structures. For simplicity let's assume that I want to write a class or function to stream TFPGList (I do not use them, but my set of generic classes is written in a similar manner). However, due to FPC's restricted generics support I cannot find a way to reasonably do that.

Ideally, I'd only like to write the streaming mechanism for each set of types (normal, anisstring, dynamic array, objects, interfaced objects) once, and use it for every set of items. However, there's no reasonable way to detect the type and do an execution for it. Ideally I'd be able to write a generic procedure :

procedure StreamType( Stream : TStream; Data : T );

... but we don't have generic procedures yet. Still, even if using classes, the inability to do specializations makes it impossible to write a generic streaming system. Is there a way to detect a type easily of "any passed value"? It would be enough for me to have a function

procedure StreamType( Stream : TStream;  var Data );

... that could detect the type of data, as long as it would accept simple types, ansistrings, classes and dynamic arrays.

regards, Kornel Kisielewicz http://chaosforge.org/

Reply by email

Jorge Aldo G. de F. Junior
to Kornel Kisielewicz

Can you create a generic that is based on a class that can stream itself using rtti regardles of its structure ?

Something like

Type
TFundamentalClass = Class(TObject)
Public
Function GetProperty(Propertyname : String): Variant;
Procedure SetProperty(PropertyName : String; Value : Variant);
Procedure WritePropertiesToStream(Const aStream : TStream); bla bla
End;
Type
Generic TMyGeneric = Class(TFundamentalClass)
Blabla
End;
Type
TMySpecialization = Specialize TMyGeneric<String>;

Did you tried that ?

2012/5/28 Kornel Kisielewicz :

Show quoted text 34 lines
Hello all, I want to find a way to write a streaming mechanic for Generic data structures. For simplicity let's assume that I want to write a class or function to stream TFPGList (I do not use them, but my set of generic classes is written in a similar manner). However, due to FPC's restricted generics support I cannot find a way to reasonably do that. Ideally, I'd only like to write the streaming mechanism for each set of types (normal, anisstring, dynamic array, objects, interfaced objects) once, and use it for every set of items. However, there's no reasonable way to detect the type and do an execution for it. Ideally I'd be able to write a generic procedure : procedure StreamType( Stream : TStream; Data : T ); ... but we don't have generic procedures yet. Still, even if using classes, the inability to do specializations makes it impossible to write a generic streaming system. Is there a way to detect a type easily of "any passed value"? It would be enough for me to have a function procedure StreamType( Stream : TStream;  var Data ); ... that could detect the type of data, as long as it would accept simple types, ansistrings, classes and dynamic arrays. -- regards, Kornel Kisielewicz http://chaosforge.org/ _______________________________________________ fpc-pascal maillist  -   http://lists.freepascal.org/mailman/listinfo/fpc-pascal

Reply by email

kyan
to Kornel Kisielewicz: I want to find a way to write a streaming mechanic for Generic data structures. For…
Ideally, I'd only like to write the streaming mechanism for each set of types (normal, anisstring, dynamic array, objects, interfaced objects) once, and use it for every set of items. However, there's no reasonable way to detect the type and do an execution for it. Ideally

You can use the "magic" function TypeInfo() to detect the type of a generic parameter inside a method of a generic class. It returns a PTypeInfo pointer so you can use PTypeInfo(TypeInfo(T))^ record to determine the data type (Kind) -and other attributes- of the generic type.

For the lack of generic procedures, you can substitute a generic procedure with a generic class method:

type
  generic TStreamer<T> = class
  public
    procedure StreamType( Stream : TStream; Data : T );
  end;
procedure TStreamer.StreamType( Stream : TStream; Data : T );
begin
  case PTypeInfo(TypeInfo(Data))^.Kind of
    tkString:
      ...
    tkInteger:
      ..
  end;
end;

HTH

Constantine.

Reply by email

Kornel Kisielewicz
to kyan
kyan wrote 10 lines
> Ideally, I'd only like to write the streaming mechanism for each set > of types (normal, anisstring, dynamic array, objects, interfaced > objects) once, and use it for every set of items. However, there's no > reasonable way to detect the type and do an execution for it. Ideally You can use the "magic" function TypeInfo() to detect the type of a generic parameter inside a method of a generic class. It returns a PTypeInfo pointer so you can use PTypeInfo(TypeInfo(T))^ record to determine the data type (Kind) -and other attributes- of the generic type.

Seems TypeInfo is the only reasonable way. Somehow function overloading is resolved before Generic type substitution so that won't work. The set of generic classes is very basic, so speed is up the essence (no variants).

I did manage to create a TStream helper, with the following prototypes

procedure ReadTyped( Ptr : Pointer; Size : Integer; Typ : PTypeInfo );
procedure WriteTyped( Ptr : Pointer; Size : Integer; Typ : PTypeInfo );

Surprisingly, trying to wrap it up nicely into

procedure ReadTyped( var Data );

... doesn't work because TypeInfo is lost (tkUnknown).

regards, Kornel Kisielewicz http://chaosforge.org/

Reply by email

Sven Barth
to Kornel Kisielewicz
Kornel Kisielewicz wrote 27 lines
On Tue, May 29, 2012 at 10:40 AM, kyan wrote: >> Ideally, I'd only like to write the streaming mechanism for each set >> of types (normal, anisstring, dynamic array, objects, interfaced >> objects) once, and use it for every set of items. However, there's no >> reasonable way to detect the type and do an execution for it. Ideally > > You can use the "magic" function TypeInfo() to detect the type of a > generic parameter inside a method of a generic class. It returns a > PTypeInfo pointer so you can use PTypeInfo(TypeInfo(T))^ record to > determine the data type (Kind) -and other attributes- of the generic > type. Seems TypeInfo is the only reasonable way. Somehow function overloading is resolved before Generic type substitution so that won't work. The set of generic classes is very basic, so speed is up the essence (no variants). I did manage to create a TStream helper, with the following prototypes procedure ReadTyped( Ptr : Pointer; Size : Integer; Typ : PTypeInfo ); procedure WriteTyped( Ptr : Pointer; Size : Integer; Typ : PTypeInfo ); Surprisingly, trying to wrap it up nicely into procedure ReadTyped( var Data ); ... doesn't work because TypeInfo is lost (tkUnknown).

This isn't surprising, as TypeInfo resolves the type at compile time based on the expression you give it, but "var Data" has no type, thus tkUnknown.

Regards,
Sven

Reply by email