Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Comment: | {3292} finalized binary serialization refactoring with FPC support enhanced |
---|---|
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
92667d06d46bad8503a40df4e7666ad7 |
User & Date: | ab 2016-12-27 09:34:54 |
2016-12-27
| ||
10:29 | {3293} ensure FPC binary serialized flow matches Delphi's check-in: 354d36be1c user: ab tags: trunk | |
09:34 | {3292} finalized binary serialization refactoring with FPC support enhanced check-in: 92667d06d4 user: ab tags: trunk | |
07:38 | {3291} fixed [fb6a92b7dc35] about missing "raise" check-in: 5bdf4a280c user: ab tags: trunk | |
Changes to SynCommons.pas.
20210 20211 20212 20213 20214 20215 20216 20217 20218 20219 20220 20221 20222 20223 20224 ..... 20347 20348 20349 20350 20351 20352 20353 20354 20355 20356 20357 20358 20359 20360 ..... 20496 20497 20498 20499 20500 20501 20502 20503 20504 20505 20506 20507 20508 20509 ..... 35353 35354 35355 35356 35357 35358 35359 35360 35361 35362 35363 35364 35365 35366 35367 35368 35369 35370 35371 35372 35373 35374 35375 35376 35377 35378 35379 35380 35381 35382 35383 35384 ..... 35463 35464 35465 35466 35467 35468 35469 35470 35471 35472 35473 35474 35475 35476 35477 ..... 35499 35500 35501 35502 35503 35504 35505 35506 35507 35508 35509 35510 35511 35512 35513 35514 35515 35516 35517 35518 35519 35520 35521 35522 35523 35524 35525 35526 35527 35528 35529 35530 35531 35532 35533 35534 35535 35536 35537 35538 35539 35540 ..... 35549 35550 35551 35552 35553 35554 35555 35556 35557 35558 35559 35560 35561 35562 35563 ..... 35578 35579 35580 35581 35582 35583 35584 35585 35586 35587 35588 35589 35590 35591 35592 35593 35594 35595 35596 35597 35598 35599 35600 35601 35602 35603 35604 35605 35606 35607 35608 35609 35610 35611 35612 35613 35614 35615 35616 35617 35618 35619 35620 35621 35622 35623 35624 35625 35626 35627 35628 35629 35630 35631 35632 35633 35634 35635 35636 35637 35638 35639 35640 35641 35642 35643 35644 35645 35646 35647 35648 35649 35650 35651 35652 35653 35654 35655 35656 35657 35658 35659 35660 35661 35662 35663 35664 35665 35666 35667 35668 ..... 35688 35689 35690 35691 35692 35693 35694 35695 35696 35697 35698 35699 35700 35701 35702 35703 35704 35705 35706 35707 35708 35709 35710 35711 35712 35713 35714 35715 35716 35717 35718 35719 35720 35721 35722 35723 35724 35725 35726 35727 35728 35729 35730 35731 35732 35733 35734 35735 ..... 35740 35741 35742 35743 35744 35745 35746 35747 35748 35749 35750 35751 35752 35753 35754 35755 35756 35757 35758 35759 35760 35761 35762 35763 35764 35765 35766 35767 35768 35769 35770 35771 35772 35773 35774 35775 35776 35777 35778 35779 35780 35781 35782 35783 35784 35785 35786 35787 35788 35789 35790 35791 35792 35793 35794 35795 35796 35797 35798 35799 35800 35801 35802 35803 35804 35805 35806 35807 35808 35809 35810 35811 35812 35813 35814 35815 35816 35817 35818 35819 35820 35821 35822 35823 35824 35825 35826 35827 35828 35829 35830 35831 35832 35833 35834 35835 35836 35837 35838 35839 35840 35841 35842 35843 35844 35845 35846 35847 35848 35849 35850 35851 35852 35853 35854 35855 35856 35857 35858 35859 35860 35861 ..... 35973 35974 35975 35976 35977 35978 35979 35980 35981 35982 35983 35984 35985 35986 35987 35988 35989 35990 ..... 35996 35997 35998 35999 36000 36001 36002 36003 36004 36005 36006 36007 36008 36009 36010 36011 36012 36013 36014 36015 36016 36017 36018 36019 36020 36021 36022 36023 36024 36025 36026 36027 36028 36029 36030 ..... 42996 42997 42998 42999 43000 43001 43002 43003 43004 43005 43006 43007 43008 43009 43010 43011 43012 43013 43014 43015 43016 43017 43018 43019 43020 43021 43022 43023 43024 43025 43026 43027 43028 ..... 43035 43036 43037 43038 43039 43040 43041 43042 43043 43044 43045 43046 43047 43048 43049 43050 43051 43052 43053 43054 43055 43056 43057 43058 43059 ..... 43645 43646 43647 43648 43649 43650 43651 43652 43653 43654 43655 43656 43657 43658 43659 ..... 43750 43751 43752 43753 43754 43755 43756 43757 43758 43759 43760 43761 43762 43763 43764 ..... 44091 44092 44093 44094 44095 44096 44097 44098 44099 44100 44101 44102 44103 44104 44105 44106 44107 44108 44109 44110 44111 44112 44113 44114 44115 44116 44117 44118 44119 44120 44121 44122 44123 44124 44125 ..... 44275 44276 44277 44278 44279 44280 44281 44282 44283 44284 44285 44286 44287 44288 44289 ..... 44300 44301 44302 44303 44304 44305 44306 44307 44308 44309 44310 44311 44312 44313 44314 ..... 45213 45214 45215 45216 45217 45218 45219 45220 45221 45222 45223 45224 45225 45226 45227 ..... 47348 47349 47350 47351 47352 47353 47354 47355 47356 47357 47358 47359 47360 47361 |
tkSet,tkMethod,tkSString,tkLStringOld,tkLString, tkWString,tkVariant,tkArray,tkRecord,tkInterface, tkClass,tkObject,tkWChar,tkBool,tkInt64,tkQWord, tkDynArray,tkInterfaceRaw,tkProcVar,tkUString,tkUChar, tkHelper,tkFile,tkClassRef,tkPointer); const // all potentially managed types tkManagedTypes = [tkLStringOld,tkLString,tkWstring,tkUstring,tkArray, tkObject,tkRecord,tkDynArray,tkInterface,tkVariant]; // maps record or object types tkRecordTypes = [tkObject,tkRecord]; tkRecordTypeOrSet = [tkObject,tkRecord]; type ................................................................................ TypeInfo: PTypeInfoStored; {$ifdef FPC} Offset: sizeint; {$else} Offset: PtrUInt; {$endif FPC} end; {$ifdef ISDELPHI2010} /// map the Delphi record field enhanced RTTI (available since Delphi 2010) TEnhancedFieldInfo = packed record TypeInfo: PTypeInfoStored; Offset: PtrUInt; Flags: Byte; NameLen: byte; // = Name[0] = length(Name) ................................................................................ // - used to calc the beginning of memory allocation of a string STRRECSIZE = SizeOf(TStrRec); function ToText(k: TTypeKind): PShortString; overload; begin result := GetEnumName(TypeInfo(TTypeKind),ord(k)); end; type TTypeInfoSaved = type TRawByteStringDynArray; function TypeInfoFind(const rttitypes: TTypeInfoSaved; const typename: RawUTF8): pointer; var i,len: integer; ................................................................................ { ************ low-level RTTI types and conversion routines } {$ifdef FPC} function RTTIManagedSize(typeInfo: Pointer): SizeInt; inline; begin case PTypeKind(typeInfo)^ of tkLString,tkLStringOld,tkWString,tkUString, tkInterface,tkDynarray: result := sizeof(Pointer); {$ifndef NOVARIANTS} tkVariant: result := sizeof(TVarData); {$endif} tkArray: with GetTypeInfo(typeInfo,tkArray)^ do result := arraySize; //result := (arraySize and $7FFFFFFF) * ElCount; // to be validated tkObject,tkRecord: result := GetTypeInfo(typeInfo,PTypeKind(typeInfo)^)^.recSize; else raise ESynException.CreateUTF8('RTTIManagedSize(%)',[PByte(typeInfo)^]); end; end; procedure RecordClear(var Dest; TypeInfo: pointer); [external name 'FPC_FINALIZE']; procedure RecordAddRef(var Data; TypeInfo : pointer); [external name 'FPC_ADDREF']; ................................................................................ var i: integer; itemtype: PTypeInfo; {$ifndef DELPHI5OROLDER} // do not know why Delphi 5 compiler does not like it DynA, DynB: TDynArray; {$endif} begin // info is expected to come from a DeRef() if retrieved from RTTI result := 0; // A^<>B^ case info^.Kind of tkLString{$ifdef FPC},tkLStringOld{$endif}: if PAnsiString(A)^=PAnsiString(B)^ then result := sizeof(pointer); tkWString: if PWideString(A)^=PWideString(B)^ then result := sizeof(pointer); {$ifdef HASVARUSTRING} ................................................................................ if PPointer(A)^=PPointer(B)^ then result := sizeof(pointer); tkArray: begin info := GetTypeInfo(info,tkArray); if (info=nil) or (info^.dimCount<>1) then result := -1 else begin itemtype := DeRef(info^.arrayType); if itemtype=nil then if CompareMem(A,B,info^.arraySize) then result := info^.arraySize else result := 0 else begin for i := 1 to info^.elCount do begin result := ManagedTypeCompare(A,B,itemtype); if result<=0 then exit; inc(A,result); inc(B,result); end; result := info^.arraySize; end; end; end; else result := -1; end; end; function ManagedTypeSaveLength(data: PAnsiChar; info: PTypeInfo; out len: integer): integer; var DynArray: TDynArray; itemtype: PTypeInfo; itemsize,size,i: integer; P: PPtrUInt absolute data; begin case info^.Kind of tkLString,tkWString{$ifdef FPC},tkLStringOld{$endif}: begin len := sizeof(pointer); // length stored within WideString is in bytes if P^=0 then result := 1 else result := ToVarUInt32LengthWithData(PStrRec(Pointer(P^-STRRECSIZE))^.length); end; {$ifdef HASVARUSTRING} ................................................................................ result := RecordSaveLength(data^,info,@len); tkArray: begin info := GetTypeInfo(info,tkArray); if (info=nil) or (info^.dimCount<>1) then result := 0 else begin len := info^.arraySize; itemtype := DeRef(info^.arrayType); if itemtype=nil then result := len else begin size := 0; for i := 1 to info^.elCount do begin inc(size,ManagedTypeSaveLength(data,itemtype,itemsize)); inc(data,itemsize); end; result := size; ................................................................................ else result := 0; // invalid/unhandled record content end; end; function ManagedTypeSave(data, dest: PAnsiChar; info: PTypeInfo; out len: integer): PAnsiChar; var DynArray: TDynArray; itemtype: PTypeInfo; itemsize,i: integer; P: PPtrUInt absolute data; begin case info^.Kind of tkDynArray: begin DynArray.Init(info,data^); result := DynArray.SaveTo(dest); len := sizeof(PtrUInt); // size of tkDynArray in record end; tkLString, tkWString {$ifdef HASVARUSTRING}, tkUString{$endif} {$ifdef FPC}, tkLStringOld{$endif}: begin if P^=0 then itemsize := 0 else itemsize := PStrRec(Pointer(P^-STRRECSIZE))^.length; {$ifdef HASVARUSTRING} // WideString has length in bytes, UnicodeString in WideChars if info^.Kind=tkUString then itemsize := itemsize*2; {$endif} result := pointer(ToVarUInt32(itemsize,pointer(dest))); if itemsize>0 then begin MoveFast(pointer(P^)^,result^,itemsize); inc(result,itemsize); end; len := sizeof(PtrUInt); // size of tkLString+tkWString+tkUString in record end; tkRecord{$ifdef FPC},tkObject{$endif}: result := RecordSave(data^,dest,info,len); tkArray: begin info := GetTypeInfo(info,tkArray); if (info=nil) or (info^.dimCount<>1) then result := nil else begin // supports single dimension static array only len := info^.arraySize; itemtype := DeRef(info^.arrayType); if itemtype=nil then begin MoveFast(data^,dest^,len); result := dest+len; end else begin for i := 1 to info^.elCount do begin dest := ManagedTypeSave(data,dest,itemtype,itemsize); if dest=nil then break; // invalid/unhandled content {$ifdef FPC} if itemsize=-1 then begin result := nil; exit; end; {$endif} inc(data,itemsize) end; result := dest; end; end; end; {$ifndef NOVARIANTS} tkVariant: begin result := VariantSave(PVariant(data)^,dest); len := sizeof(Variant); // size of tkVariant in record end; {$endif} else begin {$ifdef FPC} len := -1; // FPC generates RTTI for such unmanaged fields result := dest; {$else} result := nil; {$endif} end; end; end; function ManagedTypeLoad(data: PAnsiChar; var source: PAnsiChar; info: PTypeInfo): integer; var DynArray: TDynArray; itemtype: PTypeInfo; itemsize,i: integer; begin case info^.Kind of tkDynArray: begin DynArray.Init(info,data^); source := DynArray.LoadFrom(source); result := sizeof(PtrUInt); // size of tkDynArray in record end; tkLString, tkWString {$ifdef HASVARUSTRING}, tkUString{$endif} ................................................................................ inc(source,itemsize); result := sizeof(PtrUInt); // size of tkLString+tkWString+tkUString in record end; tkRecord{$ifdef FPC},tkObject{$endif}: source := RecordLoad(data^,source,info,@result); tkArray: begin info := GetTypeInfo(info,tkArray); if (info=nil) or (info^.dimCount<>1) then result := 0 else begin // supports single dimension static array only result := info^.arraySize; itemtype := DeRef(info^.arrayType); if itemtype=nil then begin MoveFast(source^,data^,result); inc(source,result); end else for i := 1 to info^.elCount do begin itemsize := ManagedTypeLoad(data,source,itemtype); if itemsize<=0 then begin result := 0; exit; end else inc(data,itemsize); end; end; end; {$ifndef NOVARIANTS} tkVariant: begin source := VariantLoad(PVariant(data)^,source,@JSON_OPTIONS[true]); result := sizeof(Variant); // size of tkVariant in record end; {$endif} else result := -1; end; end; function RecordEquals(const RecA, RecB; TypeInfo: pointer; PRecSize: PInteger): boolean; var info: PTypeInfo; F: integer; Field: ^TFieldInfo; Diff: cardinal; A, B: PAnsiChar; begin A := @RecA; B := @RecB; result := false; info := GetTypeInfo(TypeInfo,tkRecordTypeOrSet); ................................................................................ if A=B then begin // both nil or same pointer result := true; exit; end; Field := @info^.ManagedFields[0]; Diff := 0; for F := 1 to info^.ManagedCount do begin Diff := Field^.Offset-Diff; if Diff<>0 then begin if not CompareMem(A,B,Diff) then exit; // binary block not equal inc(A,Diff); inc(B,Diff); end; Diff := ManagedTypeCompare(A,B,DeRef(Field^.TypeInfo)); if integer(Diff)<=0 then if Diff=0 then // A^<>B^ exit else // Diff=-1 for unexpected type {$ifdef FPC} // FPC does include RTTI for unmanaged fields! :) if Field^.TypeInfo^.Kind in tkManagedTypes then raise ESynException.CreateUTF8('RecordEquals: % is managed', [ToText(Field^.TypeInfo^.Kind)^]) else begin if F=info^.ManagedCount then Diff := info^.recSize-Field^.Offset else Diff := info^.ManagedFields[F].Offset-Field^.Offset; if not CompareMem(A,B,Diff) then exit; // binary block not equal end; {$else} raise ESynException.CreateUTF8('RecordEquals: % not supported', [ToText(Field^.TypeInfo^.Kind)^]); {$endif} inc(A,Diff); inc(B,Diff); inc(Diff,Field^.Offset); inc(Field); end; if CompareMem(A,B,info^.recSize-Diff) then result := true; end; function RecordSaveLength(const Rec; TypeInfo: pointer; Len: PInteger): integer; var info: PTypeInfo; F, recsize,saved: integer; Field: ^TFieldInfo; R: PAnsiChar; begin R := @Rec; info := GetTypeInfo(TypeInfo,tkRecordTypeOrSet); if (R=nil) or (info=nil) then begin result := 0; // should have been checked before exit; end; Field := @info^.ManagedFields[0]; result := info^.recSize; if Len<>nil then Len^ := result; for F := 1 to info^.ManagedCount do begin saved := ManagedTypeSaveLength(R+Field^.Offset,Deref(Field^.TypeInfo),recsize); {$ifdef FPC} if saved>0 then // FPC has RTTI for unmanaged fields -> ignore inc(result,saved-recsize); {$else} if saved=0 then begin result := 0; // invalid type exit; end; inc(result,saved-recsize); {$endif} inc(Field); end; end; function RecordSave(const Rec; Dest: PAnsiChar; TypeInfo: pointer; out Len: integer): PAnsiChar; var info: PTypeInfo; F: integer; Diff: cardinal; Field: ^TFieldInfo; R: PAnsiChar; begin R := @Rec; info := GetTypeInfo(TypeInfo,tkRecordTypeOrSet); if (R=nil) or (info=nil) then begin result := nil; // should have been checked before exit; end; Len := info^.recSize; Field := @info^.ManagedFields[0]; Diff := 0; for F := 1 to info^.ManagedCount do begin Diff := Field^.Offset-Diff; if Diff<>0 then begin MoveFast(R^,Dest^,Diff); inc(R,Diff); inc(Dest,Diff); end; Dest := ManagedTypeSave(R,Dest,Deref(Field^.TypeInfo),integer(Diff)); if Dest=nil then begin result := nil; // invalid/unhandled record content exit; end; {$ifdef FPC} // FPC does include RTTI for unmanaged fields! :) if integer(Diff)=-1 then begin if info^.Kind in tkManagedTypes then raise ESynException.CreateUTF8('ManagedTypeSave: % not supported', [ToText(info^.Kind)^]) else begin if F=info^.ManagedCount then Diff := info^.recSize-Field^.Offset else Diff := info^.ManagedFields[F].Offset-Field^.Offset; MoveFast(R^,Dest^,Diff); inc(Dest,Diff); end; end; {$endif} inc(R,Diff); inc(Diff,Field.Offset); inc(Field); end; Diff := info^.recSize-Diff; if integer(Diff)<0 then raise ESynException.Create('RecordSave diff<0') else ................................................................................ jmp System.@FinalizeArray {$endif CPU64} end; {$endif FPC} function RecordLoad(var Rec; Source: PAnsiChar; TypeInfo: pointer; Len: PInteger): PAnsiChar; var info: PTypeInfo; F: integer; Diff: cardinal; Field: ^TFieldInfo; R: PAnsiChar; begin result := nil; // indicates error R := @Rec; info := GetTypeInfo(TypeInfo,tkRecordTypeOrSet); if (R=nil) or (info=nil) then // should have been checked before exit; ................................................................................ _Finalize(R+Field^.Offset,Deref(Field^.TypeInfo)); inc(Field); end; exit; end; Diff := 0; for F := 1 to info^.ManagedCount do begin Diff := Field^.Offset-Diff; if Diff<>0 then begin MoveFast(Source^,R^,Diff); inc(Source,Diff); inc(R,Diff); end; Diff := ManagedTypeLoad(R,Source,DeRef(Field^.TypeInfo)); {$ifdef FPC} // FPC does include RTTI for unmanaged fields! :) if integer(Diff)<0 then begin if Field^.TypeInfo^.Kind in tkManagedTypes then raise ESynException.CreateUTF8('RecordLoad: % is not supported', [ToText(Field^.TypeInfo^.Kind)^]) else begin if F=info^.ManagedCount then Diff := info^.recSize-Field^.Offset else Diff := info^.ManagedFields[F].Offset-Field^.Offset; MoveFast(Source^,R^,Diff); inc(Source,Diff); end; end else {$endif} if Diff=0 then exit; // error at loading inc(R,Diff); inc(Diff,Field^.Offset); inc(Field); end; Diff := info^.recSize-Diff; if integer(Diff)<0 then ................................................................................ result := Dest; exit; end; inc(Dest,sizeof(Cardinal)); // leave space for Hash32 checksum result := Dest; // store dynamic array elements content P := fValue^; if ElemType=nil then if GetIsObjArray then raise ESynException.CreateUTF8('TDynArray.SaveTo(%) is a T*ObjArray', [PShortString(@PTypeInfo(ArrayType).NameLen)^]) else begin // binary types: store as once n := n*integer(ElemSize); MoveFast(P^,Dest^,n); inc(Dest,n); end else for i := 1 to n do begin Dest := ManagedTypeSave(P,Dest,ElemType,LenBytes); if Dest=nil then break; {$ifdef FPC} if LenBytes=-1 then begin result := nil; exit; end; {$endif} inc(P,LenBytes); end; // store Hash32 checksum if Dest<>nil then // may be nil if RecordSave() failed PCardinal(result-sizeof(Cardinal))^ := Hash32(result,Dest-result); result := Dest; end; ................................................................................ result := 0; exit; // avoid GPF if void end; n := Count; result := ToVarUInt32Length(ElemSize)+ToVarUInt32Length(n)+1; if n=0 then exit; if ElemType=nil then if GetIsObjArray then raise ESynException.CreateUTF8('TDynArray.SaveToLength(%) is a T*ObjArray', [PShortString(@PTypeInfo(ArrayType).NameLen)^]) else inc(result,integer(ElemSize)*n) else begin P := fValue^; for i := 1 to n do begin L := ManagedTypeSaveLength(P,ElemType,size); assert(size=integer(ElemSize)); if L=0 then break; // invalid record type (wrong field type) inc(result,L); inc(P,size); end; end; inc(result,sizeof(Cardinal)); // Hash32 checksum end; ................................................................................ djRawByteString: if not Base64MagicCheckAndDecode(Val,ValLen,PRawByteStringArray(fValue^)^[i]) then SetString(RawUTF8(PPointerArray(fValue^)^[i]),Val,ValLen); djWinAnsi: WinAnsiConvert.UTF8BufferToAnsi(Val,ValLen,PRawByteStringArray(fValue^)^[i]); djString: UTF8DecodeToString(Val,ValLen,string(PPointerArray(fValue^)^[i])); djWideString: UTF8ToWideString(Val,ValLen,WideString(PPointerArray(fValue^)^[i])); djSynUnicode: UTF8ToSynUnicode(Val,ValLen,SynUnicode(PPointerArray(fValue^)^[i])); djInterface: raise ESynException.Create('djInterface not readable'); end; end; end; end; end; if aEndOfObject<>nil then aEndOfObject^ := EndOfObject; ................................................................................ exit; end; // retrieve security checksum Hash := pointer(Source); inc(Source,sizeof(cardinal)); // retrieve dynamic array elements content P := fValue^; if ElemType=nil then if GetIsObjArray then raise ESynException.CreateUTF8('TDynArray.LoadFrom(%) is a T*ObjArray', [PShortString(@PTypeInfo(ArrayType).NameLen)^]) else begin // binary type was stored directly n := n*integer(ElemSize); MoveFast(Source^,P^,n); inc(Source,n); ................................................................................ result := fCompare(A,B)=0 else if ElemType=nil then case ElemSize of // optimized versions for arrays of common types 1: result := byte(A)=byte(B); 2: result := word(A)=word(B); 4: result := cardinal(A)=cardinal(B); 8: result := Int64(A)=Int64(B); else result := CompareMem(@A,@B,ElemSize); // generic comparison end else case PTypeKind(ElemType)^ of tkRecord{$ifdef FPC},tkObject{$endif}: result := RecordEquals(A,B,ElemType); tkLString{$ifdef FPC},tkLStringOld{$endif}: result := AnsiString(A)=AnsiString(B); tkWString: result := WideString(A)=WideString(B); {$ifdef HASVARUSTRING} tkUString: result := UnicodeString(A)=UnicodeString(B); {$endif} tkInterface: result := pointer(A)=pointer(B); {$ifndef NOVARIANTS} tkVariant: result := Variant(A)=Variant(B); {$endif} else result := false; end; end; {$ifndef DELPHI5OROLDER} // do not know why Delphi 5 compiler does not like it function TDynArray.Equals(const B: TDynArray): boolean; var i, n: integer; P1,P2: PAnsiChar; A1: PPointerArray absolute P1; ................................................................................ fElemType := PTypeInfo(aTypeInfo)^.elType; if fElemType<>nil then begin {$ifndef HASDIRECTTYPEINFO} // FPC compatibility: if you have a GPF here at startup, your 3.1 trunk // revision seems older than June 2016 // -> enable HASDIRECTTYPEINFO conditional below $ifdef VER3_1 in Synopse.inc // or in your project's options fElemType := PPointer(fElemType)^; {$endif} {$ifdef FPC} if not (PTypeKind(fElemType)^ in tkManagedTypes) then fElemType := nil; // as with Delphi {$endif} end; fCountP := aCountPointer; ................................................................................ aCountPointer: PInteger=nil; aCaseInsensitive: boolean=false); var Comp: TDynArraySortCompare; begin Init(aTypeInfo,aValue,aCountPointer); Comp := DYNARRAY_SORTFIRSTFIELD[aCaseInsensitive,aKind]; if @Comp=nil then raise ESynException.CreateUTF8('TDynArray.InitSpecific(%) wrong aKind=%', [PShortString(@PTypeInfo(aTypeInfo)^.NameLen)^,ord(aKind)]); fCompare := Comp; fKnownType := aKind; fKnownSize := KNOWNTYPE_SIZE[aKind]; end; procedure TDynArray.UseExternalCount(var aCountPointer: Integer); begin ................................................................................ aKind: TDynArrayKind; aCountPointer: PInteger=nil; aCaseInsensitive: boolean=false); var Comp: TDynArraySortCompare; Hasher: TDynArrayHashOne; begin Comp := DYNARRAY_SORTFIRSTFIELD[aCaseInsensitive,aKind]; Hasher := DYNARRAY_HASHFIRSTFIELD[aCaseInsensitive,aKind]; if (@Hasher=nil) or (@Comp=nil) then raise ESynException.Create('TDynArrayHashed.InitSpecific wrong aKind'); Init(aTypeInfo,aValue,Hasher,Comp,nil,aCountPointer,aCaseInsensitive); {$ifdef UNDIRECTDYNARRAY}with InternalDynArray do{$endif} begin fKnownType := aKind; fKnownSize := KNOWNTYPE_SIZE[aKind]; end; end; ................................................................................ djWord: AddU(PWordArray(P)^[i]); djInteger: Add(PIntegerArray(P)^[i]); djCardinal: AddU(PCardinalArray(P)^[i]); djSingle: AddSingle(PSingleArray(P)^[i]); djInt64: Add(PInt64Array(P)^[i]); djDouble: AddDouble(PDoubleArray(P)^[i]); djCurrency: AddCurr64(PInt64Array(P)^[i]); end; Add(','); end; end; CancelLastComma; Add(']'); end; |
| > > > > > > | | < < | > > > > > > > > > > > > | | > | | > | | | > > | < < < < < | | | | | | | | | | | | | | | | | | | | | | | | | > | | | | | | | < < < < < < | | | | | | | | | | | | | < < > | > > | | < | | < > | | | > > | > | | < < < | > | > | | > > > > > > > | < < | < < < < < < < < < | < | | | | | | > > | > | < | | > > > > > > > | < < < < < < < < < < < < < | | > > > > > > > | | < < < < < < < < < < < < < | | < < < < < | < > | | | | < | < < < < < < < < < < < < < < < < > | | | > > |
20210 20211 20212 20213 20214 20215 20216 20217 20218 20219 20220 20221 20222 20223 20224 ..... 20347 20348 20349 20350 20351 20352 20353 20354 20355 20356 20357 20358 20359 20360 20361 ..... 20497 20498 20499 20500 20501 20502 20503 20504 20505 20506 20507 20508 20509 20510 20511 20512 20513 20514 20515 ..... 35359 35360 35361 35362 35363 35364 35365 35366 35367 35368 35369 35370 35371 35372 35373 35374 35375 35376 35377 35378 35379 35380 35381 35382 35383 35384 35385 35386 35387 35388 35389 35390 35391 35392 35393 35394 35395 35396 35397 35398 35399 35400 ..... 35479 35480 35481 35482 35483 35484 35485 35486 35487 35488 35489 35490 35491 35492 35493 ..... 35515 35516 35517 35518 35519 35520 35521 35522 35523 35524 35525 35526 35527 35528 35529 35530 35531 35532 35533 35534 35535 35536 35537 35538 35539 35540 35541 35542 35543 35544 35545 35546 35547 35548 35549 35550 35551 35552 35553 35554 35555 35556 35557 35558 ..... 35567 35568 35569 35570 35571 35572 35573 35574 35575 35576 35577 35578 35579 35580 35581 35582 ..... 35597 35598 35599 35600 35601 35602 35603 35604 35605 35606 35607 35608 35609 35610 35611 35612 35613 35614 35615 35616 35617 35618 35619 35620 35621 35622 35623 35624 35625 35626 35627 35628 35629 35630 35631 35632 35633 35634 35635 35636 35637 35638 35639 35640 35641 35642 35643 35644 35645 35646 35647 35648 35649 35650 35651 35652 35653 35654 35655 35656 35657 35658 35659 35660 35661 35662 35663 35664 35665 35666 35667 35668 35669 35670 35671 35672 35673 35674 35675 35676 35677 35678 ..... 35698 35699 35700 35701 35702 35703 35704 35705 35706 35707 35708 35709 35710 35711 35712 35713 35714 35715 35716 35717 35718 35719 35720 35721 35722 35723 35724 35725 35726 35727 35728 35729 35730 35731 35732 35733 35734 35735 35736 35737 35738 35739 35740 35741 35742 35743 35744 35745 35746 35747 ..... 35752 35753 35754 35755 35756 35757 35758 35759 35760 35761 35762 35763 35764 35765 35766 35767 35768 35769 35770 35771 35772 35773 35774 35775 35776 35777 35778 35779 35780 35781 35782 35783 35784 35785 35786 35787 35788 35789 35790 35791 35792 35793 35794 35795 35796 35797 35798 35799 35800 35801 35802 35803 35804 35805 35806 35807 35808 35809 35810 35811 35812 35813 35814 35815 35816 35817 35818 35819 35820 35821 35822 35823 35824 35825 35826 35827 35828 35829 35830 35831 35832 35833 35834 35835 35836 35837 35838 35839 35840 35841 35842 35843 35844 35845 35846 35847 35848 35849 35850 35851 35852 35853 35854 35855 35856 35857 35858 35859 35860 35861 35862 35863 35864 ..... 35976 35977 35978 35979 35980 35981 35982 35983 35984 35985 35986 35987 35988 35989 35990 35991 35992 35993 ..... 35999 36000 36001 36002 36003 36004 36005 36006 36007 36008 36009 36010 36011 36012 36013 36014 36015 36016 36017 36018 36019 36020 36021 36022 36023 36024 36025 36026 36027 ..... 42993 42994 42995 42996 42997 42998 42999 43000 43001 43002 43003 43004 43005 43006 43007 43008 43009 43010 43011 43012 43013 43014 43015 43016 43017 43018 43019 43020 ..... 43027 43028 43029 43030 43031 43032 43033 43034 43035 43036 43037 43038 43039 43040 43041 43042 43043 43044 43045 43046 43047 43048 43049 43050 43051 ..... 43637 43638 43639 43640 43641 43642 43643 43644 43645 43646 43647 43648 43649 43650 43651 ..... 43742 43743 43744 43745 43746 43747 43748 43749 43750 43751 43752 43753 43754 43755 43756 ..... 44083 44084 44085 44086 44087 44088 44089 44090 44091 44092 44093 44094 44095 44096 44097 44098 44099 44100 44101 ..... 44251 44252 44253 44254 44255 44256 44257 44258 44259 44260 44261 44262 44263 44264 44265 ..... 44276 44277 44278 44279 44280 44281 44282 44283 44284 44285 44286 44287 44288 44289 44290 ..... 45189 45190 45191 45192 45193 45194 45195 45196 45197 45198 45199 45200 45201 45202 45203 45204 ..... 47325 47326 47327 47328 47329 47330 47331 47332 47333 47334 47335 47336 47337 47338 47339 |
tkSet,tkMethod,tkSString,tkLStringOld,tkLString, tkWString,tkVariant,tkArray,tkRecord,tkInterface, tkClass,tkObject,tkWChar,tkBool,tkInt64,tkQWord, tkDynArray,tkInterfaceRaw,tkProcVar,tkUString,tkUChar, tkHelper,tkFile,tkClassRef,tkPointer); const // all potentially managed types - should match ManagedType*() functions tkManagedTypes = [tkLStringOld,tkLString,tkWstring,tkUstring,tkArray, tkObject,tkRecord,tkDynArray,tkInterface,tkVariant]; // maps record or object types tkRecordTypes = [tkObject,tkRecord]; tkRecordTypeOrSet = [tkObject,tkRecord]; type ................................................................................ TypeInfo: PTypeInfoStored; {$ifdef FPC} Offset: sizeint; {$else} Offset: PtrUInt; {$endif FPC} end; PFieldInfo = ^TFieldInfo; {$ifdef ISDELPHI2010} /// map the Delphi record field enhanced RTTI (available since Delphi 2010) TEnhancedFieldInfo = packed record TypeInfo: PTypeInfoStored; Offset: PtrUInt; Flags: Byte; NameLen: byte; // = Name[0] = length(Name) ................................................................................ // - used to calc the beginning of memory allocation of a string STRRECSIZE = SizeOf(TStrRec); function ToText(k: TTypeKind): PShortString; overload; begin result := GetEnumName(TypeInfo(TTypeKind),ord(k)); end; function ToText(k: TDynArrayKind): PShortString; overload; begin result := GetEnumName(TypeInfo(TDynArrayKind),ord(k)); end; type TTypeInfoSaved = type TRawByteStringDynArray; function TypeInfoFind(const rttitypes: TTypeInfoSaved; const typename: RawUTF8): pointer; var i,len: integer; ................................................................................ { ************ low-level RTTI types and conversion routines } {$ifdef FPC} function RTTIManagedSize(typeInfo: Pointer): SizeInt; inline; begin case PTypeKind(typeInfo)^ of // match tkManagedTypes tkLString,tkLStringOld,tkWString,tkUString, tkInterface,tkDynarray: result := sizeof(Pointer); {$ifndef NOVARIANTS} tkVariant: result := sizeof(TVarData); {$endif} tkArray: result := GetTypeInfo(typeInfo,tkArray)^.arraySize and $7fffffff; tkObject,tkRecord: result := GetTypeInfo(typeInfo,PTypeKind(typeInfo)^)^.recSize; else raise ESynException.CreateUTF8('RTTIManagedSize unhandled % (%)', [ToText(PTypeKind(typeInfo)^)^,PByte(typeInfo)^]); end; end; function RTTIUnmanagedFieldSize(Index: integer; Field: PFieldInfo; Info: PTypeInfo): integer; inline; begin if Info^.Kind in tkManagedTypes then raise ESynException.CreateUTF8('RTTIUnmanagedFieldSize: % not supported', [ToText(Info^.Kind)^]); if Index=Info^.ManagedCount then result := Info^.recSize-Field^.Offset else result := Info^.ManagedFields[Index].Offset-Field^.Offset; end; procedure RecordClear(var Dest; TypeInfo: pointer); [external name 'FPC_FINALIZE']; procedure RecordAddRef(var Data; TypeInfo : pointer); [external name 'FPC_ADDREF']; ................................................................................ var i: integer; itemtype: PTypeInfo; {$ifndef DELPHI5OROLDER} // do not know why Delphi 5 compiler does not like it DynA, DynB: TDynArray; {$endif} begin // info is expected to come from a DeRef() if retrieved from RTTI result := 0; // A^<>B^ case info^.Kind of // should match tkManagedTypes tkLString{$ifdef FPC},tkLStringOld{$endif}: if PAnsiString(A)^=PAnsiString(B)^ then result := sizeof(pointer); tkWString: if PWideString(A)^=PWideString(B)^ then result := sizeof(pointer); {$ifdef HASVARUSTRING} ................................................................................ if PPointer(A)^=PPointer(B)^ then result := sizeof(pointer); tkArray: begin info := GetTypeInfo(info,tkArray); if (info=nil) or (info^.dimCount<>1) then result := -1 else begin itemtype := DeRef(info^.arrayType); if (itemtype=nil) {$ifdef FPC}or not(itemtype^.Kind in tkManagedTypes){$endif} then if CompareMem(A,B,info^.arraySize) then result := info^.arraySize else result := 0 else begin for i := 1 to info^.elCount do begin result := ManagedTypeCompare(A,B,itemtype); if result<=0 then exit; // invalid (-1) or not equals (0) inc(A,result); inc(B,result); end; result := info^.arraySize; end; end; end; else result := -1; // Unhandled field end; end; function ManagedTypeSaveLength(data: PAnsiChar; info: PTypeInfo; out len: integer): integer; // returns 0 on error, or saved bytes + len=data^ length var DynArray: TDynArray; itemtype: PTypeInfo; itemsize,size,i: integer; P: PPtrUInt absolute data; begin // info is expected to come from a DeRef() if retrieved from RTTI case info^.Kind of // should match tkManagedTypes tkLString,tkWString{$ifdef FPC},tkLStringOld{$endif}: begin len := sizeof(pointer); // length stored within WideString is in bytes if P^=0 then result := 1 else result := ToVarUInt32LengthWithData(PStrRec(Pointer(P^-STRRECSIZE))^.length); end; {$ifdef HASVARUSTRING} ................................................................................ result := RecordSaveLength(data^,info,@len); tkArray: begin info := GetTypeInfo(info,tkArray); if (info=nil) or (info^.dimCount<>1) then result := 0 else begin len := info^.arraySize; itemtype := DeRef(info^.arrayType); if (itemtype=nil) {$ifdef FPC}or not(itemtype^.Kind in tkManagedTypes){$endif} then result := len else begin size := 0; for i := 1 to info^.elCount do begin inc(size,ManagedTypeSaveLength(data,itemtype,itemsize)); inc(data,itemsize); end; result := size; ................................................................................ else result := 0; // invalid/unhandled record content end; end; function ManagedTypeSave(data, dest: PAnsiChar; info: PTypeInfo; out len: integer): PAnsiChar; // returns nil on error, or final dest + len=data^ length var DynArray: TDynArray; itemtype: PTypeInfo; itemsize,i: integer; P: PPtrUInt absolute data; begin // info is expected to come from a DeRef() if retrieved from RTTI case info^.Kind of tkLString, tkWString {$ifdef HASVARUSTRING}, tkUString{$endif} {$ifdef FPC}, tkLStringOld{$endif}: begin if P^=0 then itemsize := 0 else itemsize := PStrRec(Pointer(P^-STRRECSIZE))^.length; {$ifdef HASVARUSTRING} // WideString has length in bytes, UnicodeString in WideChars if info^.Kind=tkUString then itemsize := itemsize*2; {$endif} result := pointer(ToVarUInt32(itemsize,pointer(dest))); if itemsize>0 then begin MoveFast(pointer(P^)^,result^,itemsize); inc(result,itemsize); end; len := sizeof(PtrUInt); // size of tkLString+tkWString+tkUString in record end; tkRecord{$ifdef FPC},tkObject{$endif}: result := RecordSave(data^,dest,info,len); tkArray: begin info := GetTypeInfo(info,tkArray); if (info=nil) or (info^.dimCount<>1) then result := nil else begin // supports single dimension static array only len := info^.arraySize; itemtype := DeRef(info^.arrayType); if (itemtype=nil) {$ifdef FPC}or not(itemtype^.Kind in tkManagedTypes){$endif} then begin MoveFast(data^,dest^,len); result := dest+len; end else begin for i := 1 to info^.elCount do begin dest := ManagedTypeSave(data,dest,itemtype,itemsize); if dest=nil then break; // invalid/unhandled content inc(data,itemsize) end; result := dest; end; end; end; {$ifndef NOVARIANTS} tkVariant: begin result := VariantSave(PVariant(data)^,dest); len := sizeof(Variant); // size of tkVariant in record end; {$endif} tkDynArray: begin DynArray.Init(info,data^); result := DynArray.SaveTo(dest); len := sizeof(PtrUInt); // size of tkDynArray in record end; else result := nil; // invalid/unhandled record content end; end; function ManagedTypeLoad(data: PAnsiChar; var source: PAnsiChar; info: PTypeInfo): integer; // returns source=nil on error, or final source + result=data^ length var DynArray: TDynArray; itemtype: PTypeInfo; itemsize,i: integer; begin // info is expected to come from a DeRef() if retrieved from RTTI case info^.Kind of tkDynArray: begin DynArray.Init(info,data^); source := DynArray.LoadFrom(source); result := sizeof(PtrUInt); // size of tkDynArray in record end; tkLString, tkWString {$ifdef HASVARUSTRING}, tkUString{$endif} ................................................................................ inc(source,itemsize); result := sizeof(PtrUInt); // size of tkLString+tkWString+tkUString in record end; tkRecord{$ifdef FPC},tkObject{$endif}: source := RecordLoad(data^,source,info,@result); tkArray: begin info := GetTypeInfo(info,tkArray); if (info=nil) or (info^.dimCount<>1) then begin source := nil; // supports single dimension static array only result := 0; end else begin result := info^.arraySize; itemtype := DeRef(info^.arrayType); if (itemtype=nil) {$ifdef FPC}or not(itemtype^.Kind in tkManagedTypes){$endif} then begin MoveFast(source^,data^,result); inc(source,result); end else for i := 1 to info^.elCount do begin inc(data,ManagedTypeLoad(data,source,itemtype)); if source=nil then exit; end; end; end; {$ifndef NOVARIANTS} tkVariant: begin source := VariantLoad(PVariant(data)^,source,@JSON_OPTIONS[true]); result := sizeof(Variant); // size of tkVariant in record end; {$endif} else begin source := nil; result := 0; end; end; end; function RecordEquals(const RecA, RecB; TypeInfo: pointer; PRecSize: PInteger): boolean; var info,fieldinfo: PTypeInfo; F: integer; Field: PFieldInfo; Diff: cardinal; A, B: PAnsiChar; begin A := @RecA; B := @RecB; result := false; info := GetTypeInfo(TypeInfo,tkRecordTypeOrSet); ................................................................................ if A=B then begin // both nil or same pointer result := true; exit; end; Field := @info^.ManagedFields[0]; Diff := 0; for F := 1 to info^.ManagedCount do begin fieldinfo := DeRef(Field^.TypeInfo); {$ifdef FPC} // FPC does include RTTI for unmanaged fields! :) if not (fieldinfo^.Kind in tkManagedTypes) then begin inc(Field); continue; end; {$endif}; Diff := Field^.Offset-Diff; if Diff<>0 then begin if not CompareMem(A,B,Diff) then exit; // binary block not equal inc(A,Diff); inc(B,Diff); end; Diff := ManagedTypeCompare(A,B,fieldinfo); if integer(Diff)<=0 then if Diff=0 then // A^<>B^ exit else // Diff=-1 for unexpected type raise ESynException.CreateUTF8('RecordEquals: unexpected %', [ToText(fieldinfo^.Kind)^]); inc(A,Diff); inc(B,Diff); inc(Diff,Field^.Offset); inc(Field); end; if CompareMem(A,B,info^.recSize-Diff) then result := true; end; function RecordSaveLength(const Rec; TypeInfo: pointer; Len: PInteger): integer; var info,fieldinfo: PTypeInfo; F, recsize,saved: integer; Field: PFieldInfo; R: PAnsiChar; begin R := @Rec; info := GetTypeInfo(TypeInfo,tkRecordTypeOrSet); if (R=nil) or (info=nil) then begin result := 0; // should have been checked before exit; end; Field := @info^.ManagedFields[0]; result := info^.recSize; if Len<>nil then Len^ := result; for F := 1 to info^.ManagedCount do begin fieldinfo := DeRef(Field^.TypeInfo); {$ifdef FPC} // FPC does include RTTI for unmanaged fields! :) if not (fieldinfo^.Kind in tkManagedTypes) then begin inc(Field); continue; end; {$endif}; saved := ManagedTypeSaveLength(R+Field^.Offset,fieldinfo,recsize); if saved=0 then begin result := 0; // invalid type exit; end; inc(result,saved-recsize); // extract recsize from info^.recSize inc(Field); end; end; function RecordSave(const Rec; Dest: PAnsiChar; TypeInfo: pointer; out Len: integer): PAnsiChar; var info,fieldinfo: PTypeInfo; F: integer; Diff: cardinal; Field: PFieldInfo; R: PAnsiChar; begin R := @Rec; info := GetTypeInfo(TypeInfo,tkRecordTypeOrSet); if (R=nil) or (info=nil) then begin result := nil; // should have been checked before exit; end; Len := info^.recSize; Field := @info^.ManagedFields[0]; Diff := 0; for F := 1 to info^.ManagedCount do begin fieldinfo := DeRef(Field^.TypeInfo); {$ifdef FPC} // FPC does include RTTI for unmanaged fields! :) if not (fieldinfo^.Kind in tkManagedTypes) then begin inc(Field); continue; end; {$endif}; Diff := Field^.Offset-Diff; if Diff<>0 then begin MoveFast(R^,Dest^,Diff); inc(R,Diff); inc(Dest,Diff); end; Dest := ManagedTypeSave(R,Dest,fieldinfo,integer(Diff)); if Dest=nil then begin result := nil; // invalid/unhandled record content exit; end; inc(R,Diff); inc(Diff,Field.Offset); inc(Field); end; Diff := info^.recSize-Diff; if integer(Diff)<0 then raise ESynException.Create('RecordSave diff<0') else ................................................................................ jmp System.@FinalizeArray {$endif CPU64} end; {$endif FPC} function RecordLoad(var Rec; Source: PAnsiChar; TypeInfo: pointer; Len: PInteger): PAnsiChar; var info,fieldinfo: PTypeInfo; F: integer; Diff: cardinal; Field: PFieldInfo; R: PAnsiChar; begin result := nil; // indicates error R := @Rec; info := GetTypeInfo(TypeInfo,tkRecordTypeOrSet); if (R=nil) or (info=nil) then // should have been checked before exit; ................................................................................ _Finalize(R+Field^.Offset,Deref(Field^.TypeInfo)); inc(Field); end; exit; end; Diff := 0; for F := 1 to info^.ManagedCount do begin fieldinfo := DeRef(Field^.TypeInfo); {$ifdef FPC} // FPC does include RTTI for unmanaged fields! :) if not (fieldinfo^.Kind in tkManagedTypes) then begin inc(Field); continue; end; {$endif}; Diff := Field^.Offset-Diff; if Diff<>0 then begin MoveFast(Source^,R^,Diff); inc(Source,Diff); inc(R,Diff); end; Diff := ManagedTypeLoad(R,Source,fieldinfo); if Source=nil then exit; // error at loading inc(R,Diff); inc(Diff,Field^.Offset); inc(Field); end; Diff := info^.recSize-Diff; if integer(Diff)<0 then ................................................................................ result := Dest; exit; end; inc(Dest,sizeof(Cardinal)); // leave space for Hash32 checksum result := Dest; // store dynamic array elements content P := fValue^; if ElemType=nil then // FPC: nil also if not Kind in tkManagedTypes if GetIsObjArray then raise ESynException.CreateUTF8('TDynArray.SaveTo(%) is a T*ObjArray', [PShortString(@PTypeInfo(ArrayType).NameLen)^]) else begin // binary types: store as once n := n*integer(ElemSize); MoveFast(P^,Dest^,n); inc(Dest,n); end else for i := 1 to n do begin Dest := ManagedTypeSave(P,Dest,ElemType,LenBytes); if Dest=nil then break; assert(LenBytes=integer(ElemSize)); inc(P,LenBytes); end; // store Hash32 checksum if Dest<>nil then // may be nil if RecordSave() failed PCardinal(result-sizeof(Cardinal))^ := Hash32(result,Dest-result); result := Dest; end; ................................................................................ result := 0; exit; // avoid GPF if void end; n := Count; result := ToVarUInt32Length(ElemSize)+ToVarUInt32Length(n)+1; if n=0 then exit; if ElemType=nil then // FPC: nil also if not Kind in tkManagedTypes if GetIsObjArray then raise ESynException.CreateUTF8('TDynArray.SaveToLength(%) is a T*ObjArray', [PShortString(@PTypeInfo(ArrayType).NameLen)^]) else inc(result,integer(ElemSize)*n) else begin P := fValue^; for i := 1 to n do begin L := ManagedTypeSaveLength(P,ElemType,size); if L=0 then break; // invalid record type (wrong field type) assert(size=integer(ElemSize)); inc(result,L); inc(P,size); end; end; inc(result,sizeof(Cardinal)); // Hash32 checksum end; ................................................................................ djRawByteString: if not Base64MagicCheckAndDecode(Val,ValLen,PRawByteStringArray(fValue^)^[i]) then SetString(RawUTF8(PPointerArray(fValue^)^[i]),Val,ValLen); djWinAnsi: WinAnsiConvert.UTF8BufferToAnsi(Val,ValLen,PRawByteStringArray(fValue^)^[i]); djString: UTF8DecodeToString(Val,ValLen,string(PPointerArray(fValue^)^[i])); djWideString: UTF8ToWideString(Val,ValLen,WideString(PPointerArray(fValue^)^[i])); djSynUnicode: UTF8ToSynUnicode(Val,ValLen,SynUnicode(PPointerArray(fValue^)^[i])); else raise ESynException.CreateUTF8('% not readable',[ToText(T)^]); end; end; end; end; end; if aEndOfObject<>nil then aEndOfObject^ := EndOfObject; ................................................................................ exit; end; // retrieve security checksum Hash := pointer(Source); inc(Source,sizeof(cardinal)); // retrieve dynamic array elements content P := fValue^; if ElemType=nil then // FPC: nil also if not Kind in tkManagedTypes if GetIsObjArray then raise ESynException.CreateUTF8('TDynArray.LoadFrom(%) is a T*ObjArray', [PShortString(@PTypeInfo(ArrayType).NameLen)^]) else begin // binary type was stored directly n := n*integer(ElemSize); MoveFast(Source^,P^,n); inc(Source,n); ................................................................................ result := fCompare(A,B)=0 else if ElemType=nil then case ElemSize of // optimized versions for arrays of common types 1: result := byte(A)=byte(B); 2: result := word(A)=word(B); 4: result := cardinal(A)=cardinal(B); 8: result := Int64(A)=Int64(B); else result := CompareMem(@A,@B,ElemSize); // binary comparison end else if PTypeKind(ElemType)^ in tkRecordTypes then // most likely result := RecordEquals(A,B,ElemType) else result := ManagedTypeCompare(@A,@B,ElemType)>0; // other complex types end; {$ifndef DELPHI5OROLDER} // do not know why Delphi 5 compiler does not like it function TDynArray.Equals(const B: TDynArray): boolean; var i, n: integer; P1,P2: PAnsiChar; A1: PPointerArray absolute P1; ................................................................................ fElemType := PTypeInfo(aTypeInfo)^.elType; if fElemType<>nil then begin {$ifndef HASDIRECTTYPEINFO} // FPC compatibility: if you have a GPF here at startup, your 3.1 trunk // revision seems older than June 2016 // -> enable HASDIRECTTYPEINFO conditional below $ifdef VER3_1 in Synopse.inc // or in your project's options fElemType := PPointer(fElemType)^; // inlined DeRef() {$endif} {$ifdef FPC} if not (PTypeKind(fElemType)^ in tkManagedTypes) then fElemType := nil; // as with Delphi {$endif} end; fCountP := aCountPointer; ................................................................................ aCountPointer: PInteger=nil; aCaseInsensitive: boolean=false); var Comp: TDynArraySortCompare; begin Init(aTypeInfo,aValue,aCountPointer); Comp := DYNARRAY_SORTFIRSTFIELD[aCaseInsensitive,aKind]; if @Comp=nil then raise ESynException.CreateUTF8('TDynArray.InitSpecific(%) wrong aKind=%', [PShortString(@PTypeInfo(aTypeInfo)^.NameLen)^,ToText(aKind)^]); fCompare := Comp; fKnownType := aKind; fKnownSize := KNOWNTYPE_SIZE[aKind]; end; procedure TDynArray.UseExternalCount(var aCountPointer: Integer); begin ................................................................................ aKind: TDynArrayKind; aCountPointer: PInteger=nil; aCaseInsensitive: boolean=false); var Comp: TDynArraySortCompare; Hasher: TDynArrayHashOne; begin Comp := DYNARRAY_SORTFIRSTFIELD[aCaseInsensitive,aKind]; Hasher := DYNARRAY_HASHFIRSTFIELD[aCaseInsensitive,aKind]; if (@Hasher=nil) or (@Comp=nil) then raise ESynException.CreateUTF8('TDynArrayHashed.InitSpecific unsupported %', [ToText(aKind)^]); Init(aTypeInfo,aValue,Hasher,Comp,nil,aCountPointer,aCaseInsensitive); {$ifdef UNDIRECTDYNARRAY}with InternalDynArray do{$endif} begin fKnownType := aKind; fKnownSize := KNOWNTYPE_SIZE[aKind]; end; end; ................................................................................ djWord: AddU(PWordArray(P)^[i]); djInteger: Add(PIntegerArray(P)^[i]); djCardinal: AddU(PCardinalArray(P)^[i]); djSingle: AddSingle(PSingleArray(P)^[i]); djInt64: Add(PInt64Array(P)^[i]); djDouble: AddDouble(PDoubleArray(P)^[i]); djCurrency: AddCurr64(PInt64Array(P)^[i]); else raise ESynException.CreateUTF8('AddDynArrayJSON unsupported %',[ToText(T)^]); end; Add(','); end; end; CancelLastComma; Add(']'); end; |
Changes to SynopseCommit.inc.
1 |
'1.18.3291'
|
| |
1 |
'1.18.3292'
|