Browse Source

* rework Rtti pool so that non-types (e.g. properties, etc.) can be stored as well based on their handle

git-svn-id: trunk@37417 -
svenbarth 7 years ago
parent
commit
1cbb4266d7
1 changed files with 65 additions and 10 deletions
  1. 65 10
      packages/rtl-objpas/src/inc/rtti.pp

+ 65 - 10
packages/rtl-objpas/src/inc/rtti.pp

@@ -355,6 +355,9 @@ resourcestring
 
 
 implementation
 implementation
 
 
+uses
+  fgl;
+
 function aligntoptr(p : pointer) : pointer;inline;
 function aligntoptr(p : pointer) : pointer;inline;
    begin
    begin
 {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
 {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
@@ -383,13 +386,18 @@ type
   { TRttiPool }
   { TRttiPool }
 
 
   TRttiPool = class
   TRttiPool = class
+  private type
+    TRttiObjectMap = specialize TFPGMap<Pointer, TRttiObject>;
   private
   private
+    FObjectMap: TRttiObjectMap;
     FTypesList: specialize TArray<TRttiType>;
     FTypesList: specialize TArray<TRttiType>;
     FTypeCount: LongInt;
     FTypeCount: LongInt;
     FLock: TRTLCriticalSection;
     FLock: TRTLCriticalSection;
   public
   public
     function GetTypes: specialize TArray<TRttiType>;
     function GetTypes: specialize TArray<TRttiType>;
     function GetType(ATypeInfo: PTypeInfo): TRttiType;
     function GetType(ATypeInfo: PTypeInfo): TRttiType;
+    function GetByHandle(aHandle: Pointer): TRttiObject;
+    procedure AddObject(aObject: TRttiObject);
     constructor Create;
     constructor Create;
     destructor Destroy; override;
     destructor Destroy; override;
   end;
   end;
@@ -431,6 +439,8 @@ resourcestring
   SErrUnableToGetValueForType = 'Unable to get value for type %s';
   SErrUnableToGetValueForType = 'Unable to get value for type %s';
   SErrUnableToSetValueForType = 'Unable to set value for type %s';
   SErrUnableToSetValueForType = 'Unable to set value for type %s';
   SErrInvalidTypecast         = 'Invalid class typecast';
   SErrInvalidTypecast         = 'Invalid class typecast';
+  SErrRttiObjectNoHandle      = 'RTTI object instance has no valid handle property';
+  SErrRttiObjectAlreadyRegistered = 'A RTTI object with handle 0x%x is already registered';
 
 
 var
 var
   PoolRefCount : integer;
   PoolRefCount : integer;
@@ -674,6 +684,7 @@ end;
 function TRttiPool.GetType(ATypeInfo: PTypeInfo): TRttiType;
 function TRttiPool.GetType(ATypeInfo: PTypeInfo): TRttiType;
 var
 var
   i: integer;
   i: integer;
+  obj: TRttiObject;
 begin
 begin
   if not Assigned(ATypeInfo) then
   if not Assigned(ATypeInfo) then
     Exit(Nil);
     Exit(Nil);
@@ -682,14 +693,9 @@ begin
   try
   try
 {$endif}
 {$endif}
     Result := Nil;
     Result := Nil;
-    for i := 0 to FTypeCount - 1 do
-      begin
-        if FTypesList[i].FTypeInfo = ATypeInfo then
-          begin
-            Result := FTypesList[i];
-            Break;
-          end;
-      end;
+    obj := GetByHandle(ATypeInfo);
+    if Assigned(obj) then
+      Result := obj as TRttiType;
     if not Assigned(Result) then
     if not Assigned(Result) then
       begin
       begin
         if FTypeCount = Length(FTypesList) then
         if FTypeCount = Length(FTypesList) then
@@ -709,6 +715,7 @@ begin
           Result := TRttiType.Create(ATypeInfo);
           Result := TRttiType.Create(ATypeInfo);
         end;
         end;
         FTypesList[FTypeCount] := Result;
         FTypesList[FTypeCount] := Result;
+        FObjectMap.Add(ATypeInfo, Result);
         Inc(FTypeCount);
         Inc(FTypeCount);
       end;
       end;
 {$ifdef FPC_HAS_FEATURE_THREADING}
 {$ifdef FPC_HAS_FEATURE_THREADING}
@@ -718,20 +725,68 @@ begin
 {$endif}
 {$endif}
 end;
 end;
 
 
+function TRttiPool.GetByHandle(aHandle: Pointer): TRttiObject;
+var
+  idx: LongInt;
+begin
+  if not Assigned(aHandle) then
+    Exit(Nil);
+{$ifdef FPC_HAS_FEATURE_THREADING}
+  EnterCriticalsection(FLock);
+  try
+{$endif}
+    idx := FObjectMap.IndexOf(aHandle);
+    if idx < 0 then
+      Result := Nil
+    else
+      Result := FObjectMap.Data[idx];
+{$ifdef FPC_HAS_FEATURE_THREADING}
+  finally
+    LeaveCriticalsection(FLock);
+  end;
+{$endif}
+end;
+
+procedure TRttiPool.AddObject(aObject: TRttiObject);
+var
+  idx: LongInt;
+begin
+  if not Assigned(aObject) then
+    Exit;
+  if not Assigned(aObject.Handle) then
+    raise EArgumentException.Create(SErrRttiObjectNoHandle);
+{$ifdef FPC_HAS_FEATURE_THREADING}
+  EnterCriticalsection(FLock);
+  try
+{$endif}
+    idx := FObjectMap.IndexOf(aObject.Handle);
+    if idx < 0 then
+      FObjectMap.Add(aObject.Handle, aObject)
+    else if FObjectMap.Data[idx] <> aObject then
+      raise EInvalidOpException.CreateFmt(SErrRttiObjectAlreadyRegistered, [aObject.Handle]);
+{$ifdef FPC_HAS_FEATURE_THREADING}
+  finally
+    LeaveCriticalsection(FLock);
+  end;
+{$endif}
+end;
+
 constructor TRttiPool.Create;
 constructor TRttiPool.Create;
 begin
 begin
 {$ifdef FPC_HAS_FEATURE_THREADING}
 {$ifdef FPC_HAS_FEATURE_THREADING}
   InitCriticalSection(FLock);
   InitCriticalSection(FLock);
 {$endif}
 {$endif}
   SetLength(FTypesList, 32);
   SetLength(FTypesList, 32);
+  FObjectMap := TRttiObjectMap.Create;
 end;
 end;
 
 
 destructor TRttiPool.Destroy;
 destructor TRttiPool.Destroy;
 var
 var
   i: LongInt;
   i: LongInt;
 begin
 begin
-  for i := 0 to length(FTypesList)-1 do
-    FTypesList[i].Free;
+  for i := 0 to FObjectMap.Count - 1 do
+    FObjectMap.Data[i].Free;
+  FObjectMap.Free;
 {$ifdef FPC_HAS_FEATURE_THREADING}
 {$ifdef FPC_HAS_FEATURE_THREADING}
   DoneCriticalsection(FLock);
   DoneCriticalsection(FLock);
 {$endif}
 {$endif}