Browse Source

* rework TValueDataIntImpl to work more as it does in Delphi (especially important for GetReferenceToRawData); note: the class avoids the use of an allocation in case it's a managed pointer type

git-svn-id: trunk@36963 -
svenbarth 8 years ago
parent
commit
95523157e5
1 changed files with 62 additions and 16 deletions
  1. 62 16
      packages/rtl-objpas/src/inc/rtti.pp

+ 62 - 16
packages/rtl-objpas/src/inc/rtti.pp

@@ -273,10 +273,14 @@ type
 
 
   TValueDataIntImpl = class(TInterfacedObject, IValueData)
   TValueDataIntImpl = class(TInterfacedObject, IValueData)
   private
   private
-    FDataSize: integer;
-    FBuffer: pointer;
+    FBuffer: Pointer;
+    FDataSize: SizeInt;
+    FTypeInfo: PTypeInfo;
+    FIsCopy: Boolean;
+    FUseAddRef: Boolean;
   public
   public
-    constructor Create(ACopyFromBuffer: Pointer; ALen: integer);
+    constructor CreateCopy(ACopyFromBuffer: Pointer; ALen: SizeInt; ATypeInfo: PTypeInfo; AAddRef: Boolean);
+    constructor CreateRef(AData: Pointer; ATypeInfo: PTypeInfo; AAddRef: Boolean);
     destructor Destroy; override;
     destructor Destroy; override;
     procedure ExtractRawData(ABuffer: pointer);
     procedure ExtractRawData(ABuffer: pointer);
     procedure ExtractRawDataNoCopy(ABuffer: pointer);
     procedure ExtractRawDataNoCopy(ABuffer: pointer);
@@ -417,31 +421,71 @@ end;
 
 
 { TValueDataIntImpl }
 { TValueDataIntImpl }
 
 
-constructor TValueDataIntImpl.create(ACopyFromBuffer: Pointer; ALen: integer);
+procedure IntFinalize(APointer, ATypeInfo: Pointer);
+  external name 'FPC_FINALIZE';
+procedure IntAddRef(APointer, ATypeInfo: Pointer);
+  external name 'FPC_ADDREF';
+
+constructor TValueDataIntImpl.CreateCopy(ACopyFromBuffer: Pointer; ALen: SizeInt; ATypeInfo: PTypeInfo; AAddRef: Boolean);
 begin
 begin
+  FTypeInfo := ATypeInfo;
   FDataSize:=ALen;
   FDataSize:=ALen;
   if ALen>0 then
   if ALen>0 then
     begin
     begin
       Getmem(FBuffer,FDataSize);
       Getmem(FBuffer,FDataSize);
       system.move(ACopyFromBuffer^,FBuffer^,FDataSize);
       system.move(ACopyFromBuffer^,FBuffer^,FDataSize);
     end;
     end;
+  FIsCopy := True;
+  FUseAddRef := AAddRef;
+  if AAddRef and (ALen > 0) then
+    IntAddRef(FBuffer, FTypeInfo);
+end;
+
+constructor TValueDataIntImpl.CreateRef(AData: Pointer; ATypeInfo: PTypeInfo; AAddRef: Boolean);
+begin
+  FTypeInfo := ATypeInfo;
+  FDataSize := SizeOf(Pointer);
+  FBuffer := PPointer(AData)^;
+  FIsCopy := False;
+  FUseAddRef := AAddRef;
+  if AAddRef then
+    IntAddRef(@FBuffer, FTypeInfo);
 end;
 end;
 
 
 destructor TValueDataIntImpl.Destroy;
 destructor TValueDataIntImpl.Destroy;
 begin
 begin
-  if assigned(FBuffer) then
-    Freemem(FBuffer);
+  if Assigned(FBuffer) then begin
+    if FUseAddRef then
+      if FIsCopy then
+        IntFinalize(FBuffer, FTypeInfo)
+      else
+        IntFinalize(@FBuffer, FTypeInfo);
+    if FIsCopy then
+      Freemem(FBuffer);
+  end;
   inherited Destroy;
   inherited Destroy;
 end;
 end;
 
 
 procedure TValueDataIntImpl.ExtractRawData(ABuffer: pointer);
 procedure TValueDataIntImpl.ExtractRawData(ABuffer: pointer);
 begin
 begin
-  system.move(FBuffer^,ABuffer^,FDataSize);
+  if FDataSize = 0 then
+    Exit;
+  if FIsCopy then
+    System.Move(FBuffer^, ABuffer^, FDataSize)
+  else
+    System.Move(FBuffer{!}, ABuffer^, FDataSize);
+  if FUseAddRef then
+    IntAddRef(ABuffer, FTypeInfo);
 end;
 end;
 
 
 procedure TValueDataIntImpl.ExtractRawDataNoCopy(ABuffer: pointer);
 procedure TValueDataIntImpl.ExtractRawDataNoCopy(ABuffer: pointer);
 begin
 begin
-  system.move(FBuffer^,ABuffer^,FDataSize);
+  if FDataSize = 0 then
+    Exit;
+  if FIsCopy then
+    system.move(FBuffer^, ABuffer^, FDataSize)
+  else
+    System.Move(FBuffer{!}, ABuffer^, FDataSize);
 end;
 end;
 
 
 function TValueDataIntImpl.GetDataSize: integer;
 function TValueDataIntImpl.GetDataSize: integer;
@@ -451,7 +495,10 @@ end;
 
 
 function TValueDataIntImpl.GetReferenceToRawData: pointer;
 function TValueDataIntImpl.GetReferenceToRawData: pointer;
 begin
 begin
-  result := FBuffer;
+  if FIsCopy then
+    result := FBuffer
+  else
+    result := @FBuffer;
 end;
 end;
 
 
 { TRttiFloatType }
 { TRttiFloatType }
@@ -478,8 +525,8 @@ type
 begin
 begin
   result.FData.FTypeInfo:=ATypeInfo;
   result.FData.FTypeInfo:=ATypeInfo;
   case ATypeInfo^.Kind of
   case ATypeInfo^.Kind of
-    tkSString  : result.FData.FValueData := TValueDataIntImpl.Create(@PShortString(ABuffer)^[1],Length(PShortString(ABuffer)^));
-    tkAString  : result.FData.FValueData := TValueDataIntImpl.Create(@PAnsiString(ABuffer)^[1],length(PAnsiString(ABuffer)^));
+    tkSString  : result.FData.FValueData := TValueDataIntImpl.CreateCopy(ABuffer, Length(PShortString(ABuffer)^) + 1, ATypeInfo, True);
+    tkAString  : result.FData.FValueData := TValueDataIntImpl.CreateRef(ABuffer, ATypeInfo, True);
     tkClass    : result.FData.FAsObject := PPointer(ABuffer)^;
     tkClass    : result.FData.FAsObject := PPointer(ABuffer)^;
     tkClassRef : result.FData.FAsClass := PClass(ABuffer)^;
     tkClassRef : result.FData.FAsClass := PClass(ABuffer)^;
     tkInt64    : result.FData.FAsSInt64 := PInt64(ABuffer)^;
     tkInt64    : result.FData.FAsSInt64 := PInt64(ABuffer)^;
@@ -551,11 +598,10 @@ var
   s: string;
   s: string;
 begin
 begin
   case Kind of
   case Kind of
-    tkSString,
-    tkAString   : begin
-                    setlength(s,FData.FValueData.GetDataSize);
-                    system.move(FData.FValueData.GetReferenceToRawData^,s[1],FData.FValueData.GetDataSize);
-                  end;
+    tkSString:
+      s := PShortString(FData.FValueData.GetReferenceToRawData)^;
+    tkAString:
+      s := PAnsiString(FData.FValueData.GetReferenceToRawData)^;
   else
   else
     raise EInvalidCast.Create(SErrInvalidTypecast);
     raise EInvalidCast.Create(SErrInvalidTypecast);
   end;
   end;