Skip to content

Commit 09e135f

Browse files
author
Arnaud Bouchez
committed
some RTTI fixes and enhancements
- especially for better collections support
1 parent a79a4af commit 09e135f

File tree

6 files changed

+110
-19
lines changed

6 files changed

+110
-19
lines changed

src/core/mormot.core.data.pas

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6441,7 +6441,7 @@ function TDynArray.InitSpecific(aTypeInfo: PRttiInfo; var aValue;
64416441
if result = ptVariant then
64426442
raise EDynArray.CreateUtf8('TDynArray.InitSpecific(%): missing mormot.core.json',
64436443
[Info.Name, ToText(result)^])
6444-
else
6444+
else if aKind <> ptNone then
64456445
raise EDynArray.CreateUtf8('TDynArray.InitSpecific(%) unsupported %',
64466446
[Info.Name, ToText(result)^]);
64476447
end;

src/core/mormot.core.json.pas

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9488,6 +9488,7 @@ function TRttiJson.SetParserType(aParser: TRttiParserType;
94889488
aParserComplex: TRttiParserComplexType): TRttiCustom;
94899489
var
94909490
C: TClass;
9491+
n: integer;
94919492
begin
94929493
// set Name and Flags from Props[]
94939494
inherited SetParserType(aParser, aParserComplex);
@@ -9546,7 +9547,10 @@ function TRttiJson.SetParserType(aParser: TRttiParserType;
95469547
fClassNewInstance := @_New_ObjectWithCustomCreate;
95479548
// allow any kind of customization for TObjectWithCustomCreate children
95489549
// - is used e.g. by TOrm or TObjectWithID
9550+
n := Props.Count;
95499551
TCCHookClass(fValueClass).RttiCustomSetParser(self);
9552+
if n > Props.Count then
9553+
fFlags := fFlags + fProps.AdjustAfterAdded; // added a prop
95509554
end
95519555
else if C = TSynObjectList then
95529556
begin

src/core/mormot.core.rtti.delphi.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,7 @@ begin
498498
{$endif HASDYNARRAYTYPE}
499499
end;
500500
end;
501+
501502
function TRttiInfo.DynArrayItemType(out aDataSize: PtrInt): PRttiInfo;
502503
begin
503504
with GetTypeData(@self)^ do

src/core/mormot.core.rtti.pas

Lines changed: 63 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2275,8 +2275,9 @@ TRttiCustom = class
22752275
// - if rcfObjArray is defined in Flags, will release all nested TObject
22762276
procedure ValueFinalizeAndClear(Data: pointer);
22772277
{$ifdef HASINLINE}inline;{$endif}
2278-
/// efficiently copy a stored value of this type
2279-
function ValueCopy(Dest, Source: pointer): PtrInt;
2278+
/// efficiently copy of a stored value of this type
2279+
// - same behavior as Dest := Source for all types
2280+
procedure ValueCopy(Dest, Source: pointer);
22802281
{$ifdef HASINLINE}inline;{$endif}
22812282
/// return TRUE if the Value is 0 / nil / '' / null
22822283
function ValueIsVoid(Data: PAnsiChar): boolean;
@@ -5794,6 +5795,42 @@ function _VariantCopy(Dest, Source: PVarData; Info: PRttiInfo): PtrInt;
57945795
result := SizeOf(Source^);
57955796
end;
57965797

5798+
function _Per1Copy(Dest, Source: PByte; Info: PRttiInfo): PtrInt;
5799+
begin
5800+
Dest^ := Source^;
5801+
result := 0; // called from TRttiCustom.ValueCopy which ignore this
5802+
end;
5803+
5804+
function _Per2Copy(Dest, Source: PWord; Info: PRttiInfo): PtrInt;
5805+
begin
5806+
Dest^ := Source^;
5807+
result := 0; // ignored
5808+
end;
5809+
5810+
function _Per4Copy(Dest, Source: PInteger; Info: PRttiInfo): PtrInt;
5811+
begin
5812+
Dest^ := Source^;
5813+
result := 0; // ignored
5814+
end;
5815+
5816+
function _Per8Copy(Dest, Source: PInt64; Info: PRttiInfo): PtrInt;
5817+
begin
5818+
Dest^ := Source^;
5819+
result := 0; // ignored
5820+
end;
5821+
5822+
function _Per16Copy(Dest, Source: PHash128; Info: PRttiInfo): PtrInt;
5823+
begin
5824+
Dest^ := Source^;
5825+
result := 0; // ignored
5826+
end;
5827+
5828+
function _Per32Copy(Dest, Source: PHash256; Info: PRttiInfo): PtrInt;
5829+
begin
5830+
Dest^ := Source^;
5831+
result := 0; // ignored
5832+
end;
5833+
57975834
function _InterfaceCopy(Dest, Source: PInterface; Info: PRttiInfo): PtrInt;
57985835
begin
57995836
Dest^ := Source^;
@@ -7027,21 +7064,12 @@ procedure TRttiCustomProps.FinalizeAndClearPublishedProperties(Instance: TObject
70277064
end;
70287065

70297066
// TRttiCustom method defined here for proper inlining
7030-
function TRttiCustom.ValueCopy(Dest, Source: pointer): PtrInt;
7067+
procedure TRttiCustom.ValueCopy(Dest, Source: pointer);
70317068
begin
7032-
if not Assigned(fCopy) then
7033-
begin
7034-
if rcfHasNestedProperties in fFlags then
7035-
if fCache.Kind = rkClass then
7036-
fProps.CopyProperties(Dest, Source)
7037-
else
7038-
fProps.CopyRecord(Dest, Source)
7039-
else
7040-
MoveFast(Source^, Dest^, fCache.Size);
7041-
result := fCache.Size;
7042-
end
7069+
if Assigned(fCopy) then
7070+
fCopy(Dest, Source, fCache.Info)
70437071
else
7044-
result := fCopy(Dest, Source, fCache.Info);
7072+
MoveFast(Source^, Dest^, fCache.Size);
70457073
end;
70467074

70477075
procedure TRttiCustomProps.CopyRecord(Dest, Source: PAnsiChar);
@@ -7063,7 +7091,8 @@ procedure TRttiCustomProps.CopyRecord(Dest, Source: PAnsiChar);
70637091
inc(Source, offset);
70647092
inc(Dest, offset);
70657093
end;
7066-
offset := pp^.Value.ValueCopy(Dest, Source); // copy managed field
7094+
pp^.Value.ValueCopy(Dest, Source); // copy managed field
7095+
offset := pp^.Value.Size;
70677096
inc(Source, offset);
70687097
inc(Dest, offset);
70697098
inc(offset, pp^.OffsetGet);
@@ -7095,6 +7124,9 @@ procedure TRttiCustomProps.CopyProperties(Dest, Source: PAnsiChar);
70957124
GetValue(Source, v);
70967125
SetValue(Dest, v, {andclear=}true);
70977126
end
7127+
else if Value.Kind = rkClass then
7128+
// explicit copy of nested instances properties
7129+
Value.Props.CopyProperties(Dest + OffsetSet, Source + OffsetGet)
70987130
else
70997131
// direct content copy from the fields memory buffers
71007132
Value.ValueCopy(Dest + OffsetSet, Source + OffsetGet);
@@ -7220,6 +7252,21 @@ constructor TRttiCustom.Create(aInfo: PRttiInfo);
72207252
// initialize processing callbacks
72217253
fFinalize := RTTI_FINALIZE[fCache.Kind];
72227254
fCopy := RTTI_MANAGEDCOPY[fCache.Kind];
7255+
if not Assigned(fCopy) then
7256+
case fCache.Size of // direct copy of most sizes, including class/pointer
7257+
1:
7258+
fCopy := @_Per1Copy;
7259+
2:
7260+
fCopy := @_Per2Copy;
7261+
4:
7262+
fCopy := @_Per4Copy;
7263+
8:
7264+
fCopy := @_Per8Copy;
7265+
16:
7266+
fCopy := @_Per16Copy;
7267+
32:
7268+
fCopy := @_Per32Copy;
7269+
end; // ItemCopy() will fallback to MoveFast() otherwise
72237270
pt := TypeInfoToStandardParserType(aInfo, {byname=}true, @pct);
72247271
SetParserType(pt, pct);
72257272
end;

src/core/mormot.core.threads.pas

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1402,8 +1402,8 @@ procedure TSynQueue.SaveToWriter(aWriter: TBufferWriter);
14021402
constructor TPendingTaskList.Create;
14031403
begin
14041404
inherited Create;
1405-
fTasks.InitSpecific(TypeInfo(TPendingTaskListItemDynArray),
1406-
fTask, ptInt64, @fCount); // sorted by Timestamp
1405+
fTasks.InitSpecific(TypeInfo(TPendingTaskListItemDynArray), fTask, ptInt64,
1406+
@fCount); // sorted by Timestamp
14071407
end;
14081408

14091409
function TPendingTaskList.GetTimestamp: Int64;

test/test.core.collections.pas

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,15 @@ procedure TTestCoreCollections.TestOne<T>;
163163
Check(li.Count = 0);
164164
end;
165165

166+
type
167+
TClassWithoutRtti = class
168+
private
169+
fSoup: RawUtf8;
170+
public
171+
property Soup: RawUtf8
172+
read fSoup write fSoup;
173+
end;
174+
166175
procedure TTestCoreCollections._IList;
167176
const
168177
MAX = 1000; // not too big since here we validate also brute force searches
@@ -172,11 +181,15 @@ procedure TTestCoreCollections._IList;
172181
li: IList<integer>;
173182
o: TObjectWithID;
174183
lo: IList<TObjectWithID>;
184+
s: TClassWithoutRtti;
185+
ls: IList<TClassWithoutRtti>;
175186
u: RawUtf8;
176187
pu: PRawUtf8;
177188
lu: IList<RawUtf8>;
178189
lh: IList<THash128>;
179190
h: THash128;
191+
r: TSynTestFailed;
192+
lr: IList<TSynTestFailed>;
180193
begin
181194
// manual IList<integer> validation
182195
li := Collections.NewList<integer>;
@@ -242,6 +255,18 @@ procedure TTestCoreCollections._IList;
242255
i := lo.Add(TObjectWithID.CreateWithID(100));
243256
Check(i = 0);
244257
CheckEqual(lo[i].IDValue, 100);
258+
// manual IList<TClassWithoutRtti> validation
259+
ls := Collections.NewList<TClassWithoutRtti>;
260+
ls.Capacity := MAX + 1;
261+
for i := 0 to MAX do
262+
begin
263+
s := TClassWithoutRtti.Create;
264+
s.Soup := UInt32ToUtf8(i);
265+
Check(ls.Add(s) = i);
266+
check(ls[i] <> nil);
267+
end;
268+
for i := 0 to ls.Count - 1 do
269+
Check(Utf8ToInteger(ls[i].Soup) = i);
245270
// manual IList<RawUtf8> validation
246271
lu := Collections.NewList<RawUtf8>;
247272
for u in lu do
@@ -292,6 +317,20 @@ procedure TTestCoreCollections._IList;
292317
lh.Add(h);
293318
lh.Sort;
294319
lh := nil;
320+
// manual IList<TSynTestFailed> validation
321+
lr := Collections.NewPlainList<TSynTestFailed>;
322+
lr.Capacity := MAX + 1;
323+
r.TestName := 'n';
324+
for i := 0 to MAX do
325+
begin
326+
r.Error := IntToStr(i);
327+
Check(lr.Add(r) = i);
328+
check(lr[i].Error = r.Error);
329+
end;
330+
for i := 0 to lr.Count - 1 do
331+
Check(lr[i].TestName = 'n');
332+
for i := 0 to lr.Count - 1 do
333+
Check(StrToInt(lr[i].Error) = i);
295334
// validate and benchmark all main types using a generic sub method
296335
TestOne<byte>();
297336
TestOne<word>();

0 commit comments

Comments
 (0)