You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

173 lines
6.9 KiB

  1. unit uutlVariantSet;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, variants,
  6. uutlGenerics;
  7. function VarSet: TVarType; inline;
  8. function VarIsSet(const aValue: Variant): Boolean; inline;
  9. function VarAsSet(const aValue: Variant): Variant; inline;
  10. function VarMakeSet(const aValue; const aSize: Integer): Variant;
  11. function VarMakeSet(const aValue; const aSize: Integer; const aHelper: TutlSetHelperBaseClass): Variant;
  12. function VarGetSetHelper(const aValue: Variant): TutlSetHelperBaseClass;
  13. implementation
  14. type
  15. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  16. PSetData = ^TSetData;
  17. TSetData = packed record
  18. Data: array[0..31] of Byte;
  19. Size: Integer;
  20. Helper: TutlSetHelperBaseClass;
  21. end;
  22. PSetVarData = ^TSetVarData;
  23. TSetVarData = packed record
  24. vType: TVarType;
  25. case Integer of
  26. 0: (vData: PSetData);
  27. 1: (vBytes: array[0..13] of Byte);
  28. end;
  29. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  30. TutlVariantSet = class(TCustomVariantType)
  31. public
  32. procedure Cast (var Dest: TVarData; const Source: TVarData); override;
  33. procedure CastTo(var Dest: TVarData; const Source: TVarData; const aVarType: TVarType); override;
  34. procedure Copy (var Dest: TVarData; const Source: TVarData; const Indirect: Boolean); override;
  35. procedure Clear (var V: TVarData); override;
  36. end;
  37. var
  38. VariantSet: TutlVariantSet;
  39. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  40. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  41. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  42. function VarSet: TVarType;
  43. begin
  44. result := VariantSet.VarType;
  45. end;
  46. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  47. function VarIsSet(const aValue: Variant): Boolean;
  48. begin
  49. result := (VarType(aValue) = VarSet);
  50. end;
  51. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  52. function VarAsSet(const aValue: Variant): Variant;
  53. begin
  54. if not VarIsSet(aValue)
  55. then VarCast(result, aValue, VarSet)
  56. else result := aValue;
  57. end;
  58. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  59. function VarMakeSet(const aValue; const aSize: Integer): Variant;
  60. begin
  61. result := VarMakeSet(aValue, aSize, nil);
  62. end;
  63. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  64. function VarMakeSet(const aValue; const aSize: Integer; const aHelper: TutlSetHelperBaseClass): Variant;
  65. begin
  66. with PSetVarData(@TVarData(result))^ do begin
  67. New (vData);
  68. FillByte(vData^.Data, SizeOf(vData^.Data), 0);
  69. Move (aValue, vData^.Data, aSize);
  70. vType := VarSet;
  71. vData^.Size := aSize;
  72. vData^.Helper := aHelper;
  73. end;
  74. end;
  75. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  76. function VarGetSetHelper(const aValue: Variant): TutlSetHelperBaseClass;
  77. begin
  78. if not VarIsSet(aValue) then
  79. VarBadTypeError;
  80. with PSetVarData(@TVarData(aValue))^ do begin
  81. if not Assigned(vData) then
  82. VarInvalidOp;
  83. result := vData^.Helper;
  84. end;
  85. end;
  86. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  87. //TutlVariantSet////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  88. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  89. procedure TutlVariantSet.Cast(var Dest: TVarData; const Source: TVarData);
  90. begin
  91. if (Dest.vType <> VariantSet.VarType) then
  92. RaiseCastError;
  93. with PSetVarData(@Dest)^ do begin
  94. if not Assigned(vData^.Helper) then
  95. RaiseCastError;
  96. if not vData^.Helper.TryToSet(Variant(Source), vData^.Data, vData^.Size) then
  97. RaiseCastError;
  98. end;
  99. end;
  100. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  101. procedure TutlVariantSet.CastTo(var Dest: TVarData; const Source: TVarData; const aVarType: TVarType);
  102. begin
  103. if (Source.vtype <> VarType) then
  104. RaiseCastError;
  105. with PSetVarData(@Source)^ do begin
  106. if not Assigned(vData^.Helper) then
  107. RaiseCastError;
  108. case aVarType of
  109. varolestr:
  110. VarDataFromOleStr(Dest, WideString(vData^.Helper.ToString(vData^.Data, vData^.Size)));
  111. varstring:
  112. VarDataFromStr(Dest, vData^.Helper.ToString(vData^.Data, vData^.Size));
  113. else
  114. RaiseCastError;
  115. end;
  116. end;
  117. end;
  118. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  119. procedure TutlVariantSet.Copy(var Dest: TVarData; const Source: TVarData; const Indirect: Boolean);
  120. var
  121. src, dst: PSetVarData;
  122. begin
  123. if (Dest.vtype <> varempty) and (Dest.vtype <> Source.vtype) then
  124. RaiseInvalidOp;
  125. src := PSetVarData(@Source);
  126. dst := PSetVarData(@Dest);
  127. dst^.vType := src^.vType;
  128. if not Assigned(dst^.vData) then
  129. new(dst^.vData);
  130. dst^.vData^ := src^.vData^;
  131. end;
  132. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  133. procedure TutlVariantSet.Clear(var V: TVarData);
  134. begin
  135. with PSetVarData(@V)^ do begin
  136. if Assigned(vData) then begin
  137. Dispose(vData);
  138. vData := nil;
  139. end;
  140. end;
  141. end;
  142. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  143. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  144. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  145. initialization
  146. VariantSet := TutlVariantSet.Create;
  147. finalization
  148. FreeAndNil(VariantSet);
  149. end.