如何在 Delphi 中创建 TBitSet32 记录以实现高效的 32 位操作?

lok*_*oki 1 delphi pascal freepascal

我正在开发一个项目,需要非常有效地操作一组 32 位。内存效率至关重要,因此使用布尔数组(占用 32 个字节)不是一个选择(如果我可以有其他选择,速度是最重要的)。

这是我为 TBitSet32 设想的结构:

TBitSet32 = record 
    value: ?integer?; // I'm not sure about the datatype here. Should it be Integer or another type?

    // Gets the value associated with a particular bit index.
    function valueForBit(index: integer): boolean;

    // Returns the number of marked bits in the set.
    function count: integer;

    // Marks the specified bit.
    procedure markBit(value: boolean; index: integer);   
end;
Run Code Online (Sandbox Code Playgroud)

对于值字段,我认为我需要 32 位整数类型。Integer 这里的选择正确吗?如何实现 valueForBit、count 和 markBit 方法?

对于此记录的任何见解或示例实现,我将不胜感激。

Rem*_*eau 7

如果您正好需要 32 位,那么(U)Int32Integer. 剩下的只是使用andorshl/shr运算符进行位操作,例如:

type
  TBitSet32 = record 
    FSet: UInt32;

    // Gets the value associated with a particular bit index.
    function valueForBit(index: integer): boolean;

    // Returns the number of marked bits in the set.
    function count: integer;

    // Marks the specified bit.
    procedure markBit(value: boolean; index: integer);   
  end;

function TBitSet32.valueForBit(index: integer): boolean;
begin
  Result := (FSet and (1 shl index)) <> 0;
end;

function TBitSet32.count: integer;
var
  I: Integer;
  tmp: UInt32;
begin
  Result := 0;
  tmp := FSet;
  for I := 0 to 31 do begin
    Inc(Result, tmp and 1);
    tmp := tmp shr 1;
  end;
end;

procedure markBit(value: boolean; index: integer);
begin
  if value then
    FSet := FSet or (1 shl index)
  else
    FSet := FSet and not (1 shl index);
end;
Run Code Online (Sandbox Code Playgroud)

也就是说,考虑使用 aSet代替,并让编译器为您处理位操作,因为 aSet是使用位集实现的,例如:

type
  TBitSet32 = record 
    FSet: set of 0..31;

    // Gets the value associated with a particular bit index.
    function valueForBit(index: integer): boolean;

    // Returns the number of marked bits in the set.
    function count: integer;

    // Marks the specified bit.
    procedure markBit(value: boolean; index: integer);   
  end;

function TBitSet32.valueForBit(index: integer): boolean;
begin
  Result := index in FSet;
end;

function TBitSet32.count: integer;
var
  I: Integer;
begin
  Result := 0;
  for I := 0 to 31 do
    Inc(Result, Ord(I in FSet));
end;

procedure markBit(value: boolean; index: integer);
begin
  if value then
    Include(FSet, index)
  else
    Exclude(FSet, index);
end;
Run Code Online (Sandbox Code Playgroud)

  • @zeus,您还可以将`valueForBit`和`markBit`函数设置为私有,并实现公共`property Bits [index:integer]:Boolean read valueForBit write markBit`。然后使用`myBitSet.Bits[2] := true` (2认同)