在一个字节中最多存储8个布尔值,在一个Integer中最多存储32个布尔值



我有这个需要,我需要在其中存储:

  1. 一个Byte中最多8个Boolean
  2. (U)Int32中最多32个Boolean
  3. (U)Int64中最多64个Boolean

对于8位,ByteChar更合适吗?

32/64位使用signed还是unsigned

是否有特定于Delphi的代码示例将Byte/Integer转换为Boolean的数组?并将第N项设置为真/假,例如:

SetItemBoolean(ItemNumber: Integer; Value: Boolean);

我发现了一些可以从Char转换为Booleans数组的东西,我只是想知道如何对Byte/Integer进行转换,这样我就可以支持更多的Boolean值。

https://ibeblog.com/2010/08/20/delphi-binary-data-storage/

Delphi为此提供了TIntegerSet,其大小为整数,因此可以对其进行强制转换。

var
Bits: TIntegerSet;
IntVal: Integer;
begin
if Value then
Include(Bits, ItemNumber)
else
Exclude(Bits, ItemNumber);
if ItemNumber in Bits then
{ Bit ItemNumber is set }
else
{ Bit ItemNumber is not set } 
{ cast to Integer as needed }
IntVal := Integer(Bits);
{ or from Integer }
Bits := TIntegerSet(IntVal);
end;

对于一个字节中的8位,您可以用类似的方式声明TByteSet

type 
TByteSet = set of 0..7;

并将其强制转换为Byte变量或从Byte变量强制转换。

此类型实现任意大小的位集。

type
TBitSet = record
private
FBitCount: Integer;
FSets: array of set of 0..255;
class function SetCount(BitCount: Integer): Integer; static;
procedure MakeUnique;
procedure GetSetIndexAndBitIndex(Bit: Integer; out SetIndex, BitIndex: Integer);
function GetIsEmpty: Boolean;
procedure SetBitCount(Value: Integer);
function GetSize: Integer;
public
class operator In(const Bit: Integer; const BitSet: TBitSet): Boolean;
class operator Equal(const bs1, bs2: TBitSet): Boolean;
class operator NotEqual(const bs1, bs2: TBitSet): Boolean;
class function SizeOfNativeSet(BitCount: Integer): Integer; static;
property BitCount: Integer read FBitCount write SetBitCount;
property Size: Integer read GetSize;
property IsEmpty: Boolean read GetIsEmpty;
procedure Clear;
procedure IncludeAll;
procedure Include(const Bit: Integer);
procedure Exclude(const Bit: Integer);
end;
{ TBitSet }
procedure TBitSet.MakeUnique;
begin
// this is used to implement copy-on-write so that the type behaves like a value
SetLength(FSets, Length(FSets));
end;
procedure TBitSet.GetSetIndexAndBitIndex(Bit: Integer; out SetIndex, BitIndex: Integer);
begin
Assert(InRange(Bit, 0, FBitCount-1));
SetIndex := Bit shr 8;   // shr 8   = div 256
BitIndex := Bit and 255; // and 255 = mod 256
end;
function TBitSet.GetIsEmpty: Boolean;
var
i: Integer;
begin
for i := 0 to High(FSets) do begin
if FSets[i]<>[] then begin
Result := False;
Exit;
end;
end;
Result := True;
end;
procedure TBitSet.SetBitCount(Value: Integer);
var
Bit, SetIndex, BitIndex: Integer;
begin
if (Value<>FBitCount) or not Assigned(FSets) then begin
Assert(Value>=0);
FBitCount := Value;
SetLength(FSets, SetCount(Value));
if Value>0 then begin
(* Ensure that unused bits are cleared, necessary give the CompareMem call in Equal. This also
means that state does not persist when we decrease and then increase BitCount. For instance,
consider this code:
var
bs: TBitSet;
...
bs.BitCount := 2;
bs.Include(1);
bs.BitCount := 1;
bs.BitCount := 2;
Assert(not (1 in bs)); *)
GetSetIndexAndBitIndex(Value - 1, SetIndex, BitIndex);
for Bit := BitIndex + 1 to 255 do begin
System.Exclude(FSets[SetIndex], Bit);
end;
end;
end;
end;
function TBitSet.GetSize: Integer;
begin
Result := Length(FSets)*SizeOf(FSets[0]);
end;
class function TBitSet.SetCount(BitCount: Integer): Integer;
begin
Result := (BitCount + 255) shr 8; // shr 8 = div 256
end;
class function TBitSet.SizeOfNativeSet(BitCount: Integer): Integer;
begin
Result := (BitCount + 7) shr 3; // shr 3 = div 8
end;
class operator TBitSet.In(const Bit: Integer; const BitSet: TBitSet): Boolean;
var
SetIndex, BitIndex: Integer;
begin
BitSet.GetSetIndexAndBitIndex(Bit, SetIndex, BitIndex);
Result := BitIndex in BitSet.FSets[SetIndex];
end;
class operator TBitSet.Equal(const bs1, bs2: TBitSet): Boolean;
begin
Result := (bs1.FBitCount=bs2.FBitCount)
and CompareMem(Pointer(bs1.FSets), Pointer(bs2.FSets), bs1.Size);
end;
class operator TBitSet.NotEqual(const bs1, bs2: TBitSet): Boolean;
begin
Result := not (bs1=bs2);
end;
procedure TBitSet.Clear;
var
i: Integer;
begin
MakeUnique;
for i := 0 to High(FSets) do begin
FSets[i] := [];
end;
end;
procedure TBitSet.IncludeAll;
var
i: Integer;
begin
for i := 0 to BitCount-1 do begin
Include(i);
end;
end;
procedure TBitSet.Include(const Bit: Integer);
var
SetIndex, BitIndex: Integer;
begin
MakeUnique;
GetSetIndexAndBitIndex(Bit, SetIndex, BitIndex);
System.Include(FSets[SetIndex], BitIndex);
end;
procedure TBitSet.Exclude(const Bit: Integer);
var
SetIndex, BitIndex: Integer;
begin
MakeUnique;
GetSetIndexAndBitIndex(Bit, SetIndex, BitIndex);
System.Exclude(FSets[SetIndex], BitIndex);
end;

这是一个简单的二进制逻辑。您可以以任何数字类型存储数据,但我建议使用无符号类型。这里是BYTE类型的示例,但您可以对任何(UInt16、UInt32、UInt64(执行相同的操作,只需更改AStorage参数的类型:

//for byte Index can be from 0 to 7
function GetByteBool(const AStorage : byte; AIndex : byte) : boolean;
begin
Result := (AStorage and (1 shl AIndex)) = (1 shl AIndex);
end;
procedure SetByteBool(var AStorage : byte; const AIndex : byte; const AValue : boolean);
begin
if AValue then begin
AStorage := AStorage or (1 shl AIndex);
end else begin
AStorage := AStorage xor (1 shl AIndex);
end;
end;
procedure TForm2.Button1Click(Sender: TObject);
begin
var b : byte := 17;
SetByteBool(b, 4, false);
if GetByteBool(b, 4) then
showmessage('true')
else
showmessage('false')
end;

在这种情况下,每1个布尔值只使用1个BIT。

最新更新