如何获取类型集的任何变量的元素数? [英] How can I get the number of elements of any variable of type set?

查看:73
本文介绍了如何获取类型集的任何变量的元素数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

AFAIK没有内置功能。在网络上搜索后,我发现此功能,它对我有用,但是我不愿使用它,因为它是汇编的,我不知道它在做什么。所以我写了这个也可以起作用的函数:

AFAIK there's no built-in function for that. Searching the web I found this function and it works for me, but I prefer not to use it since it's assembly and I can't understand what it is doing. So I wrote this function that also works:

function Cardinality(const PSet: PByteArray;
  const SizeOfSet(*in bytes*): Integer): Integer;
const
  Masks: array[0..7] of Byte = (1, 2, 4, 8, 16, 32, 64, 128);
var
  I, J: Integer;
begin
  Result := 0;
  for I := 0 to SizeOfSet - 1 do
    for J := 0 to 7 do
      if (PSet^[I] and Masks[J]) > 0 then
        Inc(Result);
end;

现在,我想知道我是否可以依靠此功能?也许在设置数据类型后面有一个窍门,这就是为什么delphi没有内置的方法。

Now, I want to know if I can rely on this function? Or maybe there's a trick behind the set data type and that's why delphi doesn't have a built-in method for that.

但是 if 我的函数很可靠然后如何将其改进为:

But if my function is reliable then how can I improve it to:


  1. 将常量传递给它

  2. 进行类型检查,确保将集合传递给函数

  3. 传递值而不是其值地址

  4. 摆脱 SizeOfSet 参数

  1. Pass constants to it
  2. Do a type check and make sure that a set is passed to the function
  3. Pass the value instead of its address
  4. Get rid of SizeOfSet parameter

我想用 Cardinality(AnySet)代替它,而不是 Cardinality(@AnySet,SizeOf(TAnySet))

I want to call it like Cardinality(AnySet) instead of Cardinality(@AnySet, SizeOf(TAnySet)).

顺便说一句,我需要在XE和XE5中都进行编译。

By the way, I need to compile this in both XE and XE5.

推荐答案

您可以使用泛型和RTTI来实现。像这样:

You can implement this with generics and RTTI. Like so:

uses
  SysUtils, TypInfo;

type
  ERuntimeTypeError = class(Exception);

  TSet<T> = class
  strict private
    class function TypeInfo: PTypeInfo; inline; static;
  public
    class function IsSet: Boolean; static;
    class function Cardinality(const Value: T): Integer; static;
  end;

const
  Masks: array[0..7] of Byte = (1, 2, 4, 8, 16, 32, 64, 128);

implementation

{ TSet<T> }

class function TSet<T>.TypeInfo: PTypeInfo;
begin
  Result := System.TypeInfo(T);
end;

class function TSet<T>.IsSet: Boolean;
begin
  Result := TypeInfo.Kind=tkSet;
end;

function GetCardinality(const PSet: PByteArray;
  const SizeOfSet(*in bytes*): Integer): Integer; inline;
var
  I, J: Integer;
begin
  Result := 0;
  for I := 0 to SizeOfSet - 1 do
    for J := 0 to 7 do
      if (PSet^[I] and Masks[J]) > 0 then
        Inc(Result);
end;

class function TSet<T>.Cardinality(const Value: T): Integer;
var
  EnumTypeData: PTypeData;
begin
  if not IsSet then
    raise ERuntimeTypeError.Create('Invalid type in TSet<T>, T must be a set');
  Result := GetCardinality(PByteArray(@Value), SizeOf(Value));
end;

用法:

Writeln(TSet<SomeSet>.Cardinality(Value));

这篇关于如何获取类型集的任何变量的元素数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆