Advertisement
sglienke

Assign operator for records

Jan 10th, 2015
274
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. unit AssignOperator;
  2.  
  3. interface
  4.  
  5. uses
  6.   Generics.Collections,
  7.   TypInfo;
  8.  
  9. type
  10.   TAssignOperators = record
  11.   private
  12.     type
  13.       TCopyRecord = procedure (dest, source, typeInfo: Pointer);
  14.       TAssignOperator = procedure(left, right: Pointer);
  15.     class var fOperators: TDictionary<PTypeInfo,TAssignOperator>;
  16.     class var fCopyRecord: TCopyRecord;
  17.     class procedure CopyRecordIntercept(dest, source: Pointer; typeinfo: PTypeInfo); static;
  18.     class constructor Create;
  19.     class destructor Destroy;
  20.   public
  21.     class function GetOperator(typeInfo: PTypeInfo): TAssignOperator; static;
  22.   end;
  23.  
  24. implementation
  25.  
  26. uses
  27.   DDetours,
  28.   Rtti;
  29.  
  30. function GetCopyRecordAddress: Pointer;
  31. asm
  32. {$IFDEF CPUX64}
  33.   mov rax,offset System.@CopyRecord
  34. {$ELSE}
  35.   mov eax,offset System.@CopyRecord
  36. {$ENDIF}
  37. end;
  38.  
  39. class procedure TAssignOperators.CopyRecordIntercept(dest, source: Pointer;
  40.   typeinfo: PTypeInfo);
  41. var
  42.   assignOperator: TAssignOperator;
  43. begin
  44.   fCopyRecord(dest, source, typeInfo);
  45.   assignOperator := GetOperator(typeInfo);
  46.   if Assigned(assignOperator) then
  47.     assignOperator(dest, source)
  48. end;
  49.  
  50. class constructor TAssignOperators.Create;
  51. begin
  52.   fOperators := TDictionary<PTypeInfo,TAssignOperator>.Create;
  53.   fCopyRecord := InterceptCreate(GetCopyRecordAddress, @CopyRecordIntercept)
  54. end;
  55.  
  56. class destructor TAssignOperators.Destroy;
  57. begin
  58.   InterceptRemove(@fCopyRecord);
  59.   fOperators.Free;
  60. end;
  61.  
  62. class function TAssignOperators.GetOperator(
  63.   typeInfo: PTypeInfo): TAssignOperator;
  64. var
  65.   context: TRttiContext;
  66.   recordType: TRttiType;
  67.   method: TRttiMethod;
  68.   parameters: TArray<TRttiParameter>;
  69. begin
  70.   if not fOperators.TryGetValue(typeInfo, Result) then
  71.   begin
  72.     recordType := context.GetType(typeInfo);
  73.     for method in recordType.GetMethods do
  74.     begin
  75.       if (method.Name = 'Assign') and method.IsClassMethod then
  76.       begin
  77.         parameters := method.GetParameters;
  78.         if Length(parameters) = 2 then
  79.         begin
  80.           if (parameters[0].ParamType.Handle = typeInfo)
  81.             and (parameters[1].ParamType.Handle = typeInfo)
  82.             and (pfVar in parameters[0].Flags)
  83.             and (pfVar in parameters[1].Flags) then
  84.           begin
  85.             Result := method.CodeAddress;
  86.             fOperators.AddOrSetValue(typeInfo, Result);
  87.             Exit;
  88.           end;
  89.         end;
  90.       end;
  91.     end;
  92.   end;
  93. end;
  94.  
  95. initialization
  96.   // just make sure the class is used once the unit is used somewhere
  97.   if Assigned(TypeInfo(TAssignOperators)) then;
  98.  
  99. end.
Advertisement
RAW Paste Data Copied
Advertisement