File: tests.rtti.util.pas

package info (click to toggle)
fpc 3.2.2%2Bdfsg-48
  • links: PTS, VCS
  • area: main
  • in suites: forky
  • size: 341,456 kB
  • sloc: pascal: 3,820,194; xml: 194,356; ansic: 9,637; asm: 8,482; java: 5,346; sh: 4,813; yacc: 3,956; makefile: 2,705; lex: 2,661; javascript: 2,454; sql: 929; php: 474; cpp: 145; perl: 136; sed: 132; csh: 34; tcl: 7
file content (277 lines) | stat: -rw-r--r-- 8,059 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
unit Tests.Rtti.Util;

{$mode objfpc}{$H+}

interface

uses
  TypInfo, Rtti;

{$ifndef fpc}
type
  CodePointer = Pointer;

  TValueHelper = record helper for TValue
    function AsUnicodeString: UnicodeString;
    function AsAnsiString: AnsiString;
    function AsChar: Char; inline;
    function AsAnsiChar: AnsiChar;
    function AsWideChar: WideChar;
  end;
{$endif}

const
{$if defined(cpui386) or defined(cpux86_64) or defined(cpum68k)}
  DefaultCC = ccReg;
{$else}
  DefaultCC = ccStdCall;
{$endif}

function CopyValue({$ifdef fpc}constref{$else}const [ref]{$endif} aValue: TValue): TValue;
function EqualValues({$ifdef fpc}constref{$else}const [ref]{$endif} aValue1, aValue2: TValue): Boolean;

function TypeKindToStr(aTypeKind: TTypeKind): String; inline;

function GetInstValue(aValue: TObject): TValue;
function GetPointerValue(aValue: Pointer): TValue;
function GetIntValue(aValue: SizeInt): TValue;
function GetAnsiString(const aValue: AnsiString): TValue;
function GetShortString(const aValue: ShortString): TValue;
function GetSingleValue(aValue: Single): TValue;
function GetDoubleValue(aValue: Double): TValue;
function GetExtendedValue(aValue: Extended): TValue;
function GetCompValue(aValue: Comp): TValue;
function GetCurrencyValue(aValue: Currency): TValue;
function GetArray(const aArg: array of SizeInt): TValue;

implementation

uses
  SysUtils, Math;

{$ifndef fpc}
function TValueHelper.AsUnicodeString: UnicodeString;
begin
  Result := UnicodeString(AsString);
end;

function TValueHelper.AsAnsiString: AnsiString;
begin
  Result := AnsiString(AsString);
end;

function TValue.AsWideChar: WideChar;
begin
  if Kind <> tkWideChar then
    raise EInvalidCast.Create('Invalid cast');
  Result := WideChar(Word(AsOrdinal));
end;

function TValue.AsAnsiChar: AnsiChar;
begin
  if Kind <> tkChar then
    raise EInvalidCast.Create('Invalid cast');
  Result := AnsiChar(Byte(AsOrdinal));
end;

function TValue.AsChar: Char;
begin
  Result := AsWideChar;
end;
{$endif}

function CopyValue({$ifdef fpc}constref{$else}const [ref]{$endif} aValue: TValue): TValue;
var
  arrptr: Pointer;
  len, i: SizeInt;
begin
  if aValue.Kind = tkDynArray then begin
    { we need to decouple the source reference, so we're going to be a bit
      cheeky here }
    len := aValue.GetArrayLength;
    arrptr := Nil;
    DynArraySetLength(arrptr, aValue.TypeInfo, 1, @len);
    TValue.Make(@arrptr, aValue.TypeInfo, Result);
    for i := 0 to len - 1 do
      Result.SetArrayElement(i, aValue.GetArrayElement(i));
  end else
    TValue.Make(aValue.GetReferenceToRawData, aValue.TypeInfo, Result);
end;

function EqualValues({$ifdef fpc}constref{$else}const [ref]{$endif} aValue1, aValue2: TValue): Boolean;
var
  td1, td2: PTypeData;
  i: SizeInt;
begin
{$ifdef debug}
  Writeln('Empty: ', aValue1.IsEmpty, ' ', aValue2.IsEmpty);
  Writeln('Kind: ', aValue1.Kind, ' ', aValue2.Kind);
  Writeln('Array: ', aValue1.IsArray, ' ', aValue2.IsArray);
{$endif}
  if aValue1.IsEmpty and aValue2.IsEmpty then
    Result := True
  else if aValue1.IsEmpty and not aValue2.IsEmpty then
    Result := False
  else if not aValue1.IsEmpty and aValue2.IsEmpty then
    Result := False
  else if aValue1.IsArray and aValue2.IsArray then begin
    if aValue1.GetArrayLength = aValue2.GetArrayLength then begin
      Result := True;
      for i := 0 to aValue1.GetArrayLength - 1 do
        if not EqualValues(aValue1.GetArrayElement(i), aValue2.GetArrayElement(i)) then begin
{$ifdef debug}
          Writeln('Element ', i, ' differs: ', HexStr(aValue1.GetArrayElement(i).AsOrdinal, 4), ' ', HexStr(aValue2.GetArrayElement(i).AsOrdinal, 4));
{$endif}
          Result := False;
          Break;
        end;
    end else
      Result := False;
  end else if aValue1.Kind = aValue2.Kind then begin
    td1 := aValue1.TypeData;
    td2 := aValue2.TypeData;
    case aValue1.Kind of
      tkBool:
        Result := aValue1.AsBoolean xor not aValue2.AsBoolean;
      tkSet:
        if td1^.SetSize = td2^.SetSize then
          if td1^.SetSize < SizeOf(SizeInt) then
            Result := aValue1.AsOrdinal = aValue2.AsOrdinal
          else
            Result := CompareMem(aValue1.GetReferenceToRawData, aValue2.GetReferenceToRawData, td1^.SetSize)
        else
          Result := False;
      tkEnumeration,
      tkChar,
      tkWChar,
      tkUChar,
      tkInt64,
      tkInteger:
        Result := aValue1.AsOrdinal = aValue2.AsOrdinal;
      tkQWord:
        Result := aValue1.AsUInt64 = aValue2.AsUInt64;
      tkFloat:
        if td1^.FloatType <> td2^.FloatType then
          Result := False
        else begin
          case td1^.FloatType of
            ftSingle:
              Result := SameValue(Single(aValue1.AsExtended), Single(aValue2.AsExtended));
            ftDouble:
              Result := SameValue(Double(aValue1.AsExtended), Double(aValue2.AsExtended));
            ftExtended:
              Result := SameValue(aValue1.AsExtended, aValue2.AsExtended);
            ftComp:
              Result := aValue1.AsInt64 = aValue2.AsInt64;
            ftCurr:
              Result := aValue1.AsCurrency = aValue2.AsCurrency;
          end;
        end;
      tkSString,
      tkUString,
      tkAString,
      tkWString:
        Result := aValue1.AsString = aValue2.AsString;
      tkDynArray,
      tkArray:
        if aValue1.GetArrayLength = aValue2.GetArrayLength then begin
          Result := True;
          for i := 0 to aValue1.GetArrayLength - 1 do
            if not EqualValues(aValue1.GetArrayElement(i), aValue2.GetArrayElement(i)) then begin
              Result := False;
              Break;
            end;
        end else
          Result := False;
      tkClass,
      tkClassRef,
      tkInterface,
      tkInterfaceRaw,
      tkPointer:
        Result := PPointer(aValue1.GetReferenceToRawData)^ = PPointer(aValue2.GetReferenceToRawData)^;
      tkProcVar:
        Result := PCodePointer(aValue1.GetReferenceToRawData)^ = PCodePointer(aValue2.GetReferenceToRawData)^;
      tkRecord,
      tkObject,
      tkMethod,
      tkVariant: begin
        if aValue1.DataSize = aValue2.DataSize then
          Result := CompareMem(aValue1.GetReferenceToRawData, aValue2.GetReferenceToRawData, aValue1.DataSize)
        else
          Result := False;
      end
      else
        Result := False;
    end;
  end else
    Result := False;
end;

function TypeKindToStr(aTypeKind: TTypeKind): String;
begin
{$ifdef fpc}
  Str(aTypeKind, Result);
{$else}
  Result := GetEnumName(TypeInfo(TTypeKind), Ord(aTypeKind));
{$endif}
end;

function GetInstValue(aValue: TObject): TValue;
begin
  Result := TValue.{$ifdef fpc}specialize{$endif}From<TObject>(aValue);
end;

function GetPointerValue(aValue: Pointer): TValue;
begin
  Result := TValue.{$ifdef fpc}specialize{$endif}From<Pointer>(aValue);
end;

function GetIntValue(aValue: SizeInt): TValue;
begin
  Result := TValue.{$ifdef fpc}specialize{$endif}From<SizeInt>(aValue);
end;

function GetAnsiString(const aValue: AnsiString): TValue;
begin
  Result := TValue.{$ifdef fpc}specialize{$endif}From<AnsiString>(aValue);
end;

function GetShortString(const aValue: ShortString): TValue;
begin
  Result := TValue.{$ifdef fpc}specialize{$endif}From<ShortString>(aValue);
end;

function GetSingleValue(aValue: Single): TValue;
begin
  Result := TValue.{$ifdef fpc}specialize{$endif}From<Single>(aValue);
end;

function GetDoubleValue(aValue: Double): TValue;
begin
  Result := TValue.{$ifdef fpc}specialize{$endif}From<Double>(aValue);
end;

function GetExtendedValue(aValue: Extended): TValue;
begin
  Result := TValue.{$ifdef fpc}specialize{$endif}From<Extended>(aValue);
end;

function GetCompValue(aValue: Comp): TValue;
begin
  Result := TValue.{$ifdef fpc}specialize{$endif}From<Comp>(aValue);
end;

function GetCurrencyValue(aValue: Currency): TValue;
begin
  Result := TValue.{$ifdef fpc}specialize{$endif}From<Currency>(aValue);
end;

{$ifdef fpc}
function GetArray(const aArg: array of SizeInt): TValue;
begin
  Result := specialize OpenArrayToDynArrayValue<SizeInt>(aArg);
end;
{$endif}

end.