[fpc-devel] RTTI module and "IsManaged" critical problem

Sven Barth pascaldragon at googlemail.com
Mon Dec 12 20:41:43 CET 2016


On 09.12.2016 22:57, Maciej Izak wrote:
> Hi,
> 
> thanks Sven, finally we have initial RTTI.pas version on trunk. Let me
> start with first serious issue and eventually patch:
> 
> function IsManaged(TypeInfo: PTypeInfo): boolean;
> 
> IsManaged can't work with records because we need know managed fields
> count (in Delphi when ManagedFldCount is bigger than 0 it means that
> record has managed fields and problem is solved). Two possible (and IMO
> correct) solutions:

So, my own idea for this.

Keep the following points in mind however:
- reasonable source(!) backwards compatibility (see for example what I
did when I switched from PTypeInfo to PPTypeInfo: the fields were
changed to PPTypeInfo, but properties were added that return PTypeInfo;
this means that code using e.g. ParentInfo will continue to work, but
code that uses the address to ParentInfo will not; also code that writes
to ParentInfo will fail (as did Lazarus for example))
- the INIT RTTI is left as is; it only contains the managed fields
already and should be as compact as possible as it has to be written for
every record while the FULL RTTI is only written for records that need
it (used by TypeInfo(), used as published property (ToDo)) [Note: I'm
aware that extended RTTI will influence that due to the typelist, but
even then the availability can still be controlled by the user (think
$weaklinkrtti for example)]

=== code begin ===

type
  TRecordField = record
    Visibility: TVisibility;
    TypeRef: PPTypeInfo;
    FldOffset: Integer;
    Name: PShortString; { can be NULL if no ext RTTI }
  end;

  TManagedField = TRecordField deprecated;

  TTypeData = record
  // ...
    tkRecord: (
      RecSize: Integer;
      { maybe if needed: RecInitTable: Pointer; can still be added later
on }
      ManagedFieldCount: Integer;
      ManagedFieldTable: PRecordField; // points to first entry of
ManagedFields
      case Boolean of
        True: (ManagedFldCount: Integer deprecated 'Use
ManagedFieldCount or TotalFieldCount depending on your use case')
        False: (TotalFieldCount: Integer)
      { Fields: array[1..TotalFieldCount] of TRecordField }
      { ManagedFields: array[1..ManagedFieldCount] of PRecordField } //
points to corresponding entry in Fields
      { Names: array[1..TotalFieldCount] of {packed} ShortString }
    );
  end;

=== code end ===

This allows all fields to be enumerated as usual (namely by getting a
pointer to the area after ManagedFldCount/TotalFieldCount and indexing
TRecordField/TManagedField there.
ManagedFieldTable allows a fast access to a table of pointers to all
managed fields (considering that RTTI is usually used in more processing
intensive contexts (e.g. form instantiation, scripting, invoke, etc) the
additional indirection is acceptable.
Additionally there is the optional name table which is referenced from
each field.

To ease access we could add properties that do the heavy lifting, though
I'd move all that to a new type TRecordData which is referenced from
TTypeData inside a case branch as RecordData: TRecordData with RecSize,
ManagedFieldCount, ManagedFieldTable and the
ManagedFldCount/TotalFieldCount case in the other branch.

Regards,
Sven



More information about the fpc-devel mailing list