tests.rtti.util.pas 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. unit Tests.Rtti.Util;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Rtti;
  6. {$ifndef fpc}
  7. type
  8. CodePointer = Pointer;
  9. TValueHelper = record helper for TValue
  10. function AsUnicodeString: UnicodeString;
  11. function AsAnsiString: AnsiString;
  12. end;
  13. {$endif}
  14. function CopyValue({$ifdef fpc}constref{$else}const [ref]{$endif} aValue: TValue): TValue;
  15. function EqualValues({$ifdef fpc}constref{$else}const [ref]{$endif} aValue1, aValue2: TValue): Boolean;
  16. function TypeKindToStr(aTypeKind: TTypeKind): String; inline;
  17. function GetInstValue(aValue: TObject): TValue;
  18. function GetPointerValue(aValue: Pointer): TValue;
  19. function GetIntValue(aValue: SizeInt): TValue;
  20. function GetAnsiString(const aValue: AnsiString): TValue;
  21. function GetShortString(const aValue: ShortString): TValue;
  22. function GetSingleValue(aValue: Single): TValue;
  23. function GetDoubleValue(aValue: Double): TValue;
  24. function GetExtendedValue(aValue: Extended): TValue;
  25. function GetCompValue(aValue: Comp): TValue;
  26. function GetCurrencyValue(aValue: Currency): TValue;
  27. function GetArray(const aArg: array of SizeInt): TValue;
  28. implementation
  29. uses
  30. TypInfo, SysUtils;
  31. {$ifndef fpc}
  32. function TValueHelper.AsUnicodeString: UnicodeString;
  33. begin
  34. Result := UnicodeString(AsString);
  35. end;
  36. function TValueHelper.AsAnsiString: AnsiString;
  37. begin
  38. Result := AnsiString(AsString);
  39. end;
  40. {$endif}
  41. function CopyValue({$ifdef fpc}constref{$else}const [ref]{$endif} aValue: TValue): TValue;
  42. var
  43. arrptr: Pointer;
  44. len, i: SizeInt;
  45. begin
  46. if aValue.Kind = tkDynArray then begin
  47. { we need to decouple the source reference, so we're going to be a bit
  48. cheeky here }
  49. len := aValue.GetArrayLength;
  50. arrptr := Nil;
  51. DynArraySetLength(arrptr, aValue.TypeInfo, 1, @len);
  52. TValue.Make(@arrptr, aValue.TypeInfo, Result);
  53. for i := 0 to len - 1 do
  54. Result.SetArrayElement(i, aValue.GetArrayElement(i));
  55. end else
  56. TValue.Make(aValue.GetReferenceToRawData, aValue.TypeInfo, Result);
  57. end;
  58. function EqualValues({$ifdef fpc}constref{$else}const [ref]{$endif} aValue1, aValue2: TValue): Boolean;
  59. var
  60. td1, td2: PTypeData;
  61. i: SizeInt;
  62. begin
  63. {$ifdef debug}
  64. Writeln('Empty: ', aValue1.IsEmpty, ' ', aValue2.IsEmpty);
  65. Writeln('Kind: ', aValue1.Kind, ' ', aValue2.Kind);
  66. Writeln('Array: ', aValue1.IsArray, ' ', aValue2.IsArray);
  67. {$endif}
  68. if aValue1.IsEmpty and aValue2.IsEmpty then
  69. Result := True
  70. else if aValue1.IsEmpty and not aValue2.IsEmpty then
  71. Result := False
  72. else if not aValue1.IsEmpty and aValue2.IsEmpty then
  73. Result := False
  74. else if aValue1.IsArray and aValue2.IsArray then begin
  75. if aValue1.GetArrayLength = aValue2.GetArrayLength then begin
  76. Result := True;
  77. for i := 0 to aValue1.GetArrayLength - 1 do
  78. if not EqualValues(aValue1.GetArrayElement(i), aValue2.GetArrayElement(i)) then begin
  79. Writeln('Element ', i, ' differs: ', HexStr(aValue1.GetArrayElement(i).AsOrdinal, 4), ' ', HexStr(aValue2.GetArrayElement(i).AsOrdinal, 4));
  80. Result := False;
  81. Break;
  82. end;
  83. end else
  84. Result := False;
  85. end else if aValue1.Kind = aValue2.Kind then begin
  86. td1 := aValue1.TypeData;
  87. td2 := aValue2.TypeData;
  88. case aValue1.Kind of
  89. tkBool:
  90. Result := aValue1.AsBoolean xor not aValue2.AsBoolean;
  91. tkSet:
  92. if td1^.SetSize = td2^.SetSize then
  93. if td1^.SetSize < SizeOf(SizeInt) then
  94. Result := aValue1.AsOrdinal = aValue2.AsOrdinal
  95. else
  96. Result := CompareMem(aValue1.GetReferenceToRawData, aValue2.GetReferenceToRawData, td1^.SetSize)
  97. else
  98. Result := False;
  99. tkEnumeration,
  100. tkChar,
  101. tkWChar,
  102. tkUChar,
  103. tkInt64,
  104. tkInteger:
  105. Result := aValue1.AsOrdinal = aValue2.AsOrdinal;
  106. tkQWord:
  107. Result := aValue1.AsUInt64 = aValue2.AsUInt64;
  108. tkFloat:
  109. if td1^.FloatType <> td2^.FloatType then
  110. Result := False
  111. else begin
  112. case td1^.FloatType of
  113. ftSingle,
  114. ftDouble,
  115. ftExtended:
  116. Result := aValue1.AsExtended = aValue2.AsExtended;
  117. ftComp:
  118. Result := aValue1.AsInt64 = aValue2.AsInt64;
  119. ftCurr:
  120. Result := aValue1.AsCurrency = aValue2.AsCurrency;
  121. end;
  122. end;
  123. tkSString,
  124. tkUString,
  125. tkAString,
  126. tkWString:
  127. Result := aValue1.AsString = aValue2.AsString;
  128. tkDynArray,
  129. tkArray:
  130. if aValue1.GetArrayLength = aValue2.GetArrayLength then begin
  131. Result := True;
  132. for i := 0 to aValue1.GetArrayLength - 1 do
  133. if not EqualValues(aValue1.GetArrayElement(i), aValue2.GetArrayElement(i)) then begin
  134. Result := False;
  135. Break;
  136. end;
  137. end else
  138. Result := False;
  139. tkClass,
  140. tkClassRef,
  141. tkInterface,
  142. tkInterfaceRaw,
  143. tkPointer:
  144. Result := PPointer(aValue1.GetReferenceToRawData)^ = PPointer(aValue2.GetReferenceToRawData)^;
  145. tkProcVar:
  146. Result := PCodePointer(aValue1.GetReferenceToRawData)^ = PCodePointer(aValue2.GetReferenceToRawData)^;
  147. tkRecord,
  148. tkObject,
  149. tkMethod,
  150. tkVariant: begin
  151. if aValue1.DataSize = aValue2.DataSize then
  152. Result := CompareMem(aValue1.GetReferenceToRawData, aValue2.GetReferenceToRawData, aValue1.DataSize)
  153. else
  154. Result := False;
  155. end
  156. else
  157. Result := False;
  158. end;
  159. end else
  160. Result := False;
  161. end;
  162. function TypeKindToStr(aTypeKind: TTypeKind): String;
  163. begin
  164. {$ifdef fpc}
  165. Str(aTypeKind, Result);
  166. {$else}
  167. Result := GetEnumName(TypeInfo(TTypeKind), Ord(aTypeKind));
  168. {$endif}
  169. end;
  170. function GetInstValue(aValue: TObject): TValue;
  171. begin
  172. Result := TValue.{$ifdef fpc}specialize{$endif}From<TObject>(aValue);
  173. end;
  174. function GetPointerValue(aValue: Pointer): TValue;
  175. begin
  176. Result := TValue.{$ifdef fpc}specialize{$endif}From<Pointer>(aValue);
  177. end;
  178. function GetIntValue(aValue: SizeInt): TValue;
  179. begin
  180. Result := TValue.{$ifdef fpc}specialize{$endif}From<SizeInt>(aValue);
  181. end;
  182. function GetAnsiString(const aValue: AnsiString): TValue;
  183. begin
  184. Result := TValue.{$ifdef fpc}specialize{$endif}From<AnsiString>(aValue);
  185. end;
  186. function GetShortString(const aValue: ShortString): TValue;
  187. begin
  188. Result := TValue.{$ifdef fpc}specialize{$endif}From<ShortString>(aValue);
  189. end;
  190. function GetSingleValue(aValue: Single): TValue;
  191. begin
  192. Result := TValue.{$ifdef fpc}specialize{$endif}From<Single>(aValue);
  193. end;
  194. function GetDoubleValue(aValue: Double): TValue;
  195. begin
  196. Result := TValue.{$ifdef fpc}specialize{$endif}From<Double>(aValue);
  197. end;
  198. function GetExtendedValue(aValue: Extended): TValue;
  199. begin
  200. Result := TValue.{$ifdef fpc}specialize{$endif}From<Extended>(aValue);
  201. end;
  202. function GetCompValue(aValue: Comp): TValue;
  203. begin
  204. Result := TValue.{$ifdef fpc}specialize{$endif}From<Comp>(aValue);
  205. end;
  206. function GetCurrencyValue(aValue: Currency): TValue;
  207. begin
  208. Result := TValue.{$ifdef fpc}specialize{$endif}From<Currency>(aValue);
  209. end;
  210. {$ifdef fpc}
  211. function GetArray(const aArg: array of SizeInt): TValue;
  212. begin
  213. Result := specialize OpenArrayToDynArrayValue<SizeInt>(aArg);
  214. end;
  215. {$endif}
  216. end.