提问人:zeus 提问时间:8/25/2023 更新时间:8/25/2023 访问量:198
如何在 Delphi 中创建 TBitSet32 记录以实现高效的 32 位操作?
How can I create a TBitSet32 record in Delphi for efficient 32-bit operations?
问:
我正在做一个项目,我需要非常有效地操作一组 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;
对于值字段,我假设我需要一个 32 位整数类型。Integer 是正确的选择吗?如何实现 valueForBit、count 和 markBit 方法?
我将不胜感激此记录的任何见解或示例实现。
答:
7赞
Remy Lebeau
8/25/2023
#1
如果您正好需要 32 位,那么比 更有意义。其余的只是使用 、 和 / 运算符进行位操作的问题,例如:(U)Int32
Integer
and
or
shl
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;
也就是说,请考虑改用 a,让编译器为您处理位操作,因为 是使用位集实现的,例如:Set
Set
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;
评论
1赞
zeus
8/25/2023
谢谢,FSet:0..31 集;接缝最有前途的解决方案!
2赞
Old Skull
8/25/2023
@zeus,您还可以将 public 设置为私有并实现 public 。然后使用valueForBit
markBit
property Bits[index: integer]: Boolean read valueForBit write markBit
myBitSet.Bits[2] := true
评论
TBits
TBits
TBits
TBits
FBits
FSize
TBits