Type
TByteArray =
Array[0..0]
of Byte;
PByteArray = ^TByteArray;
TBits =
Class
Protected
_Data: PByteArray;
_Size, _Pos: Integer;
_Extern: Boolean;
Procedure SetSize ( Value: Integer);
Procedure SetBSize( Value: Integer);
//Inline;
Function GetBSize: Integer;
//Inline;
Procedure SetPos ( Value: Integer);
//Inline;
Procedure SetBPos ( Value: Integer);
//Inline;
Procedure SetABit ( Value: Boolean);
//Inline;
Function GetABit: Boolean;
//Inline;
Procedure SetABits( Length: Integer; Value: LongWord);
//Inline;
Function GetABits( Length: Integer): LongWord;
//Inline;
Procedure SetBit (
Index: Integer; Value: Boolean);
//Inline;
Function GetBit (
Index: Integer): Boolean;
//Inline;
Procedure SetBits (
Index: Integer; Length: Integer; Value: LongWord);
//Inline;
Function GetBits (
Index: Integer; Length: Integer): LongWord;
//Inline;
Procedure SetMask (
Index: Integer; Mask: LongWord; Value: LongWord);
Function GetMask (
Index: Integer; Mask: LongWord): LongWord;
Public
Destructor Destroy;
Override;
Procedure SetData(Data: Pointer =
nil; SizeInByte: Integer = -1);
Procedure Clear;
Function OpenBit: Integer;
Function CloseBit: Integer;
Property Size: Integer
Read _Size
Write SetSize;
Property ByteSize: Integer
Read GetBSize
Write SetBSize;
Property Position: Integer
Read _Pos
Write SetPos;
Property BytePos: Integer
Write SetBPos;
Property aBit: Boolean
Read GetABit
Write SetABit;
Property aBits[ Length: Integer]: LongWord
Read GetABits
Write SetABits;
Property Bit [
Index: Integer]: Boolean
Read GetBit
Write SetBit;
Default;
Property Bits [
Index: Integer; Length: Integer]: LongWord
Read GetBits
Write SetBits;
Property Mask [
Index: Integer; Mask: LongWord]: LongWord
Read GetMask
Write SetMask;
Procedure WriteBlock(
Index, Length: Integer; Data: Pointer);
Procedure ReadBlock (
Index, Length: Integer; Data: Pointer);
End;
Procedure TBits.SetSize(Value: Integer);
Begin
If _Extern
Then System.Error(reInvalidOp);
ReallocMem(_Data, (Value + 7)
div 8);
If Value > _Size
Then Begin
If _Size
mod 8 > 0
Then
_Data[_Size
div 8] := _Data[_Size
div 8]
and ($FF
shr (8 - _Size
mod 8));
ZeroMemory(@_Data[(_Size + 7)
div 8], ((Value + 7)
div 8) - ((_Size + 7)
div 8));
End;
_Size := Value;
End;
Procedure TBits.SetBSize(Value: Integer);
Begin
SetSize(Value * 8);
End;
Function TBits.GetBSize: Integer;
Begin
Result := (_Size + 7)
div 8;
End;
Procedure TBits.SetPos(Value: Integer);
Begin
_Pos := Value;
End;
Procedure TBits.SetBPos(Value: Integer);
Begin
SetPos(Value * 8);
End;
Procedure TBits.SetABit(Value: Boolean);
Begin
SetBit(_Pos, Value);
End;
Function TBits.GetABit: Boolean;
Begin
Result := GetBit(_Pos);
End;
Procedure TBits.SetABits(Length: Integer; Value: LongWord);
Begin
SetBits(_Pos, Length, Value);
End;
Function TBits.GetABits(Length: Integer): LongWord;
Begin
Result := GetBits(_Pos, Length);
End;
Procedure TBits.SetBit(
Index: Integer; Value: Boolean);
Const X:
Array[Boolean]
of LongWord = ($0, $1);
Begin
SetBits(
Index, 1, X[Value]);
End;
Function TBits.GetBit(
Index: Integer): Boolean;
Begin
Result := GetBits(
Index, 1) <> 0;
End;
Procedure TBits.SetBits(
Index: Integer; Length: Integer; Value: LongWord);
Begin
If Length = 0
Then Exit;
// to prevent the mistake by "shr 32"
SetMask(
Index, $FFFFFFFF
shr (32 - Length), Value);
End;
Function TBits.GetBits(
Index: Integer; Length: Integer): LongWord;
Begin
If Length = 0
Then Begin
// to prevent the mistake by "shr 32"
Result := 0;
Exit;
End;
Result := GetMask(
Index, $FFFFFFFF
shr (32 - Length));
End;
Procedure TBits.SetMask(
Index: Integer; Mask: LongWord; Value: LongWord);
Var i, i2: Integer;
Begin
_Pos :=
Index;
i := Mask;
While (i <> 0)
do Begin
Inc(_Pos);
i := i
shr 1;
End;
If (
Index < 0)
or (_Pos > _Size)
Then System.Error(reRangeError);
i2 :=
Index mod 8;
If i2 <> 0
Then Begin
i := 8 - i2;
_Data[
Index div 8] := (_Data[
Index div 8]
and not (Mask
shl i2))
or ((Value
and Mask)
shl i2);
Inc(
Index, i);
Mask := Mask
shr i;
Value := Value
shr i;
End;
While Mask <> 0
do Begin
_Data[
Index div 8] := (_Data[
Index div 8]
and not Mask)
or (Value
and Mask);
Inc(
Index, 8);
Mask := Mask
shr 8;
Value := Value
shr 8;
End;
End;
Function TBits.GetMask(
Index: Integer; Mask: LongWord): LongWord;
Var i, i2: Integer;
Begin
_Pos :=
Index;
i := Mask;
While (i <> 0)
do Begin
Inc(_Pos);
i := i
shr 1;
End;
If (
Index < 0)
or (_Pos > _Size)
Then System.Error(reRangeError);
i2 :=
Index mod 8;
If i2 <> 0
Then Begin
i := 8 - (i2);
Result := (_Data[
Index div 8]
shr i2)
and Mask;
Inc(
Index, i);
Mask := Mask
shr i;
End Else Begin
i := 0;
Result := 0;
End;
While Mask <> 0
do Begin
Result := Result
or ((_Data[
Index div 8]
and Mask)
shl i);
Inc(i, 8);
Inc(
Index, 8);
Mask := Mask
shr 8;
End;
End;
Destructor TBits.Destroy;
Begin
SetData(
nil, -1);
End;
Procedure TBits.SetData(Data: Pointer =
nil; SizeInByte: Integer = -1);
Begin
If not _Extern
Then FreeMem(_Data);
If SizeInByte >= 0
Then Begin
_Data := Data;
_Size := SizeInByte * 8;
End Else Begin
_Data :=
nil;
_Size := 0;
End;
_Extern := SizeInByte >= 0;
_Pos := 0;
End;
Procedure TBits.Clear;
Begin
ZeroMemory(_Data, (_Size + 7)
div 8);
End;
Function TBits.OpenBit: Integer;
Var i: Integer;
Begin
For i := 0
to _Size - 1
do
If GetBit(i)
Then Begin
Result := i;
Exit;
End;
Result := -1;
End;
Function TBits.CloseBit: Integer;
Var i: Integer;
Begin
For i := _Size - 1
downto 0
do
If GetBit(i)
Then Begin
Result := i;
Exit;
End;
Result := -1;
End;
Procedure TBits.WriteBlock(
Index, Length: Integer; Data: Pointer);
Begin
While Length >= 8
do Begin
SetBits(
Index, 8, PByte(Data)^);
Dec(Length, 8);
Inc(
Index, 8);
Inc(Integer(Data));
End;
If Length > 0
Then
SetBits(
Index, Length, PByte(Data)^);
End;
Procedure TBits.ReadBlock(
Index, Length: Integer; Data: Pointer);
Begin
While Length >= 8
do Begin
PByte(Data)^ := GetBits(
Index, 8);
Dec(Length, 8);
Inc(
Index, 8);
Inc(Integer(Data));
End;
If Length > 0
Then
PByte(Data)^ := GetBits(
Index, Length);
End;