* 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 -
This commit is contained in:
svenbarth 2017-08-20 18:19:31 +00:00
parent 6672e77222
commit 95523157e5

View File

@ -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 if Assigned(FBuffer) then begin
Freemem(FBuffer); 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)^)); tkSString : result.FData.FValueData := TValueDataIntImpl.CreateCopy(ABuffer, Length(PShortString(ABuffer)^) + 1, ATypeInfo, True);
tkAString : result.FData.FValueData := TValueDataIntImpl.Create(@PAnsiString(ABuffer)^[1],length(PAnsiString(ABuffer)^)); 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, tkSString:
tkAString : begin s := PShortString(FData.FValueData.GetReferenceToRawData)^;
setlength(s,FData.FValueData.GetDataSize); tkAString:
system.move(FData.FValueData.GetReferenceToRawData^,s[1],FData.FValueData.GetDataSize); s := PAnsiString(FData.FValueData.GetReferenceToRawData)^;
end;
else else
raise EInvalidCast.Create(SErrInvalidTypecast); raise EInvalidCast.Create(SErrInvalidTypecast);
end; end;