检测编译类型的泛型类的具体类型

时间:2014-08-19 14:45:43

标签: delphi generics

关于这个问题的跟进:Conditional behaviour based on concrete type for generic class

我知道您可以使用RTTI检测泛型变量的类型。但是我想更进一步。有没有办法在编译时检测类型。

我有以下代码:

function TBPlusTree<K, V>.TLeaf.AddKey(const Key: K; const Value: V): boolean;
var
  i: integer;
begin
  i:= 0;
  while i < fCount do begin
    if Key = fKeys[i] then exit(false); // Key already exists
    //Todo: replace with binary search
    if Key < fKeys[i] then begin
      // Make space for the key
      Move(fKeys[i], fKeys[i+1], (fCount - i) * SizeOf(TKey));
      // If the key is a String or DynArray zero out the pointer
      if (SizeOf(K) = SizeOf(NativeInt)) then NativeInt((@fKeys[i])^):= 0;
      // If the value is a String or DynArray zero out the pointer
      Move(fValues[i], fValues[i+1], (fCount - i) * SizeOf(V));
      if (SizeOf(V) = SizeOf(NativeInt)) then NativeInt((@fValues[i])^):= 0;
      break;
    end;
    Inc(i);
  end; { while }
  Inc(fCount);
  //ClearKey(fKeys[i]);
  fKeys[i]:= Key;
  // if ValueType = tkUString then UniqueString(PString(@fValues[i])^);
  fValues[i]:= Value;
  Result:= true;
end;

如果树将字符串保存为K或V类型,则指针需要归零。 move击败COW机制,2个字符串将具有新值。

关于上述if then的好处是编译器消除了测试。

BPlusTrees.pas.454: if (SizeOf(K) = SizeOf(NativeInt)) then NativeInt((@fKeys[i])^):= 0;
0056BBC4 8B4610           mov eax,[esi+$10]  //Test is eliminated by compiler.
0056BBC7 8D0498           lea eax,[eax+ebx*4]
0056BBCA 33D2             xor edx,edx
0056BBCC 8910             mov [eax],edx

因为可以在编译时解析SizeOf,所以编译器可以看到测试总是解析为true(或者为false)并将消除它。

然而
上面的代码只需要运行引用计数类型,即:接口,字符串和dynarrays 现在它也运行整数,对象等。

TypeInfo的问题在于它生成的检查代码比我试图避免的实际代码花费的时间更长。

BPlusTrees.pas.454: if (SizeOf(K) = SizeOf(NativeInt)) and
          (PTypeInfo(TypeInfo(K))^.Kind <> tkInteger) 
          then NativeInt((@fKeys[i])^):= 0;
0056BBC4 A19C104000       mov eax,[$0040109c]
0056BBC9 803801           cmp byte ptr [eax],$01
0056BBCC 740A             jz $0056bbd8
0056BBCE 8B4610           mov eax,[esi+$10]
0056BBD1 8D0498           lea eax,[eax+ebx*4]
0056BBD4 33D2             xor edx,edx
0056BBD6 8910             mov [eax],edx

有没有办法缩小上面的测试范围,以便测试表达式仍然可以在编译时解析,以便它编译成与上面相同的代码但排除更多类型?

我已经了解了内在的惯例,但我看不到任何可以帮助我的事情:http://docwiki.embarcadero.com/RADStudio/XE4/en/Delphi_Intrinsic_Routines

1 个答案:

答案 0 :(得分:2)

在编译时,没有办法区分无约束的泛型类型。在编译时没有可以从非托管类型告知托管类型的运算符。

<强>更新

自XE7以来,有一个新的内在IsManagedType旨在满足您的需求。迄今为止,这种内在的无证。也许最好的参考是:http://delphisorcery.blogspot.co.uk/2014/10/new-language-feature-in-xe7.html?m=1