786 lines
24 KiB
ObjectPascal
786 lines
24 KiB
ObjectPascal
{******************************************************************************}
|
|
{ }
|
|
{ Library: Fundamentals 5.00 }
|
|
{ File name: flcBit32.pas }
|
|
{ File version: 5.03 }
|
|
{ Description: Bit function: 32 bit. }
|
|
{ }
|
|
{ Copyright: Copyright (c) 2001-2020, David J Butler }
|
|
{ All rights reserved. }
|
|
{ Redistribution and use in source and binary forms, with }
|
|
{ or without modification, are permitted provided that }
|
|
{ the following conditions are met: }
|
|
{ Redistributions of source code must retain the above }
|
|
{ copyright notice, this list of conditions and the }
|
|
{ following disclaimer. }
|
|
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
|
|
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
|
|
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
|
|
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
|
|
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
|
|
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
|
|
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
|
|
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
|
|
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
|
|
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
|
|
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
|
|
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
|
|
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
|
|
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
|
|
{ POSSIBILITY OF SUCH DAMAGE. }
|
|
{ }
|
|
{ Github: https://github.com/fundamentalslib }
|
|
{ E-mail: fundamentals.library at gmail.com }
|
|
{ }
|
|
{ Revision history: }
|
|
{ }
|
|
{ 2001/05/03 1.01 Improved bit functions. Added Pascal versions of }
|
|
{ assembly routines. }
|
|
{ 2015/06/07 4.02 Moved bit functions from cUtils to cBits32. }
|
|
{ 2016/01/09 5.03 Revised for Fundamentals 5. }
|
|
{ }
|
|
{ Supported compilers: }
|
|
{ }
|
|
{ Delphi XE7 Win32 5.03 2016/01/09 }
|
|
{ Delphi XE7 Win64 5.03 2016/01/09 }
|
|
{ Delphi 10 Win32 5.03 2016/01/09 }
|
|
{ Delphi 10 Win64 5.03 2016/01/09 }
|
|
{ }
|
|
{******************************************************************************}
|
|
|
|
{$INCLUDE ..\flcInclude.inc}
|
|
|
|
unit flcBits32;
|
|
|
|
interface
|
|
|
|
uses
|
|
{ Fundamentals }
|
|
flcStdTypes;
|
|
|
|
|
|
|
|
{ }
|
|
{ Bit functions }
|
|
{ }
|
|
function ClearBit32(const Value, BitIndex: Word32): Word32;
|
|
function SetBit32(const Value, BitIndex: Word32): Word32;
|
|
function IsBitSet32(const Value, BitIndex: Word32): Boolean;
|
|
function ToggleBit32(const Value, BitIndex: Word32): Word32;
|
|
function IsHighBitSet32(const Value: Word32): Boolean;
|
|
|
|
function SetBitScanForward32(const Value: Word32): Integer; overload;
|
|
function SetBitScanForward32(const Value, BitIndex: Word32): Integer; overload;
|
|
function SetBitScanReverse32(const Value: Word32): Integer; overload;
|
|
function SetBitScanReverse32(const Value, BitIndex: Word32): Integer; overload;
|
|
function ClearBitScanForward32(const Value: Word32): Integer; overload;
|
|
function ClearBitScanForward32(const Value, BitIndex: Word32): Integer; overload;
|
|
function ClearBitScanReverse32(const Value: Word32): Integer; overload;
|
|
function ClearBitScanReverse32(const Value, BitIndex: Word32): Integer; overload;
|
|
|
|
function ReverseBits32(const Value: Word32): Word32; overload;
|
|
function ReverseBits32(const Value: Word32; const BitCount: Integer): Word32; overload;
|
|
function SwapEndian32(const Value: Word32): Word32;
|
|
procedure SwapEndianBuf32(var Buf; const Count: Integer);
|
|
function TwosComplement32(const Value: Word32): Word32;
|
|
|
|
function RotateLeftBits16(const Value: Word; const Bits: Byte): Word;
|
|
function RotateLeftBits32(const Value: Word32; const Bits: Byte): Word32;
|
|
function RotateRightBits16(const Value: Word; const Bits: Byte): Word;
|
|
function RotateRightBits32(const Value: Word32; const Bits: Byte): Word32;
|
|
|
|
function BitCount32(const Value: Word32): Word32;
|
|
function IsPowerOfTwo32(const Value: Word32): Boolean;
|
|
|
|
function LowBitMask32(const HighBitIndex: Word32): Word32;
|
|
function HighBitMask32(const LowBitIndex: Word32): Word32;
|
|
function RangeBitMask32(const LowBitIndex, HighBitIndex: Word32): Word32;
|
|
|
|
function SetBitRange32(const Value: Word32;
|
|
const LowBitIndex, HighBitIndex: Word32): Word32;
|
|
function ClearBitRange32(const Value: Word32;
|
|
const LowBitIndex, HighBitIndex: Word32): Word32;
|
|
function ToggleBitRange32(const Value: Word32;
|
|
const LowBitIndex, HighBitIndex: Word32): Word32;
|
|
function IsBitRangeSet32(const Value: Word32;
|
|
const LowBitIndex, HighBitIndex: Word32): Boolean;
|
|
function IsBitRangeClear32(const Value: Word32;
|
|
const LowBitIndex, HighBitIndex: Word32): Boolean;
|
|
|
|
const
|
|
BitMaskTable32: array[0..31] of Word32 =
|
|
($00000001, $00000002, $00000004, $00000008,
|
|
$00000010, $00000020, $00000040, $00000080,
|
|
$00000100, $00000200, $00000400, $00000800,
|
|
$00001000, $00002000, $00004000, $00008000,
|
|
$00010000, $00020000, $00040000, $00080000,
|
|
$00100000, $00200000, $00400000, $00800000,
|
|
$01000000, $02000000, $04000000, $08000000,
|
|
$10000000, $20000000, $40000000, $80000000);
|
|
|
|
|
|
|
|
{ }
|
|
{ Test cases }
|
|
{ }
|
|
{$IFDEF DEBUG}
|
|
{$IFDEF TEST}
|
|
procedure Test;
|
|
{$ENDIF}
|
|
{$ENDIF}
|
|
|
|
|
|
|
|
implementation
|
|
|
|
|
|
|
|
{ }
|
|
{ Bit functions }
|
|
{ }
|
|
{$IFDEF ASM386_DELPHI}
|
|
function ReverseBits32(const Value: Word32): Word32; register; assembler;
|
|
asm
|
|
BSWAP EAX
|
|
MOV EDX, EAX
|
|
AND EAX, 0AAAAAAAAh
|
|
SHR EAX, 1
|
|
AND EDX, 055555555h
|
|
SHL EDX, 1
|
|
OR EAX, EDX
|
|
MOV EDX, EAX
|
|
AND EAX, 0CCCCCCCCh
|
|
SHR EAX, 2
|
|
AND EDX, 033333333h
|
|
SHL EDX, 2
|
|
OR EAX, EDX
|
|
MOV EDX, EAX
|
|
AND EAX, 0F0F0F0F0h
|
|
SHR EAX, 4
|
|
AND EDX, 00F0F0F0Fh
|
|
SHL EDX, 4
|
|
OR EAX, EDX
|
|
end;
|
|
{$ELSE}
|
|
function ReverseBits32(const Value: Word32): Word32;
|
|
var I : Byte;
|
|
begin
|
|
Result := 0;
|
|
for I := 0 to 31 do
|
|
if Value and BitMaskTable32[I] <> 0 then
|
|
Result := Result or BitMaskTable32[31 - I];
|
|
end;
|
|
{$ENDIF}
|
|
|
|
function ReverseBits32(const Value: Word32; const BitCount: Integer): Word32;
|
|
var I, C : Integer;
|
|
V : Word32;
|
|
begin
|
|
V := Value;
|
|
Result := 0;
|
|
C := BitCount;
|
|
if C > 32 then
|
|
C := 32;
|
|
for I := 0 to C - 1 do
|
|
begin
|
|
Result := (Result shl 1) or (V and 1);
|
|
V := V shr 1;
|
|
end;
|
|
end;
|
|
|
|
{$IFDEF ASM386_DELPHI}
|
|
function SwapEndian32(const Value: Word32): Word32; register; assembler;
|
|
asm
|
|
XCHG AH, AL
|
|
ROL EAX, 16
|
|
XCHG AH, AL
|
|
end;
|
|
{$ELSE}
|
|
function SwapEndian32(const Value: Word32): Word32;
|
|
begin
|
|
Result := ((Value and $000000FF) shl 24) or
|
|
((Value and $0000FF00) shl 8) or
|
|
((Value and $00FF0000) shr 8) or
|
|
((Value and $FF000000) shr 24);
|
|
end;
|
|
{$ENDIF}
|
|
|
|
procedure SwapEndianBuf32(var Buf; const Count: Integer);
|
|
var P : PWord32;
|
|
I : Integer;
|
|
begin
|
|
P := @Buf;
|
|
for I := 1 to Count do
|
|
begin
|
|
P^ := SwapEndian32(P^);
|
|
Inc(P);
|
|
end;
|
|
end;
|
|
|
|
{$IFDEF ASM386_DELPHI}
|
|
function TwosComplement32(const Value: Word32): Word32; register; assembler;
|
|
asm
|
|
NEG EAX
|
|
end;
|
|
{$ELSE}
|
|
function TwosComplement32(const Value: Word32): Word32;
|
|
begin
|
|
Result := Word32(not Value + 1);
|
|
end;
|
|
{$ENDIF}
|
|
|
|
{$IFDEF ASM386_DELPHI}
|
|
function RotateLeftBits16(const Value: Word; const Bits: Byte): Word;
|
|
asm
|
|
MOV CL, DL
|
|
ROL AX, CL
|
|
end;
|
|
{$ELSE}
|
|
function RotateLeftBits16(const Value: Word; const Bits: Byte): Word;
|
|
var I, B : Integer;
|
|
R : Word;
|
|
begin
|
|
R := Value;
|
|
if Bits >= 16 then
|
|
B := Bits mod 16
|
|
else
|
|
B := Bits;
|
|
for I := 1 to B do
|
|
if R and $8000 = 0 then
|
|
R := Word(R shl 1)
|
|
else
|
|
R := Word(R shl 1) or 1;
|
|
Result := R;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
{$IFDEF ASM386_DELPHI}
|
|
function RotateLeftBits32(const Value: Word32; const Bits: Byte): Word32;
|
|
asm
|
|
MOV CL, DL
|
|
ROL EAX, CL
|
|
end;
|
|
{$ELSE}
|
|
function RotateLeftBits32(const Value: Word32; const Bits: Byte): Word32;
|
|
var I, B : Integer;
|
|
R : Word32;
|
|
begin
|
|
R := Value;
|
|
if Bits >= 32 then
|
|
B := Bits mod 32
|
|
else
|
|
B := Bits;
|
|
for I := 1 to B do
|
|
if R and $80000000 = 0 then
|
|
R := Word32(R shl 1)
|
|
else
|
|
R := Word32(R shl 1) or 1;
|
|
Result := R;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
{$IFDEF ASM386_DELPHI}
|
|
function RotateRightBits16(const Value: Word; const Bits: Byte): Word;
|
|
asm
|
|
MOV CL, DL
|
|
ROR AX, CL
|
|
end;
|
|
{$ELSE}
|
|
function RotateRightBits16(const Value: Word; const Bits: Byte): Word;
|
|
var I, B : Integer;
|
|
R : Word;
|
|
begin
|
|
R := Value;
|
|
if Bits >= 16 then
|
|
B := Bits mod 16
|
|
else
|
|
B := Bits;
|
|
for I := 1 to B do
|
|
if R and 1 = 0 then
|
|
R := Word(R shr 1)
|
|
else
|
|
R := Word(R shr 1) or $8000;
|
|
Result := R;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
{$IFDEF ASM386_DELPHI}
|
|
function RotateRightBits32(const Value: Word32; const Bits: Byte): Word32;
|
|
asm
|
|
MOV CL, DL
|
|
ROR EAX, CL
|
|
end;
|
|
{$ELSE}
|
|
function RotateRightBits32(const Value: Word32; const Bits: Byte): Word32;
|
|
var I, B : Integer;
|
|
R : Word32;
|
|
begin
|
|
R := Value;
|
|
if Bits >= 32 then
|
|
B := Bits mod 32
|
|
else
|
|
B := Bits;
|
|
for I := 1 to B do
|
|
if R and 1 = 0 then
|
|
R := Word32(R shr 1)
|
|
else
|
|
R := Word32(R shr 1) or $80000000;
|
|
Result := R;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
{$IFDEF ___ASM386_DELPHI}
|
|
function SetBit32(const Value, BitIndex: Word32): Word32;
|
|
asm
|
|
{$IFOPT R+}
|
|
CMP BitIndex, 32
|
|
JB @RangeOk
|
|
JMP RaiseRangeCheckError
|
|
@RangeOk:
|
|
{$ENDIF}
|
|
OR EAX, DWORD PTR [BitIndex * 4 + BitMaskTable32]
|
|
end;
|
|
{$ELSE}
|
|
function SetBit32(const Value, BitIndex: Word32): Word32;
|
|
begin
|
|
Result := Value or BitMaskTable32[BitIndex];
|
|
end;
|
|
{$ENDIF}
|
|
|
|
{$IFDEF ___ASM386_DELPHI}
|
|
function ClearBit32(const Value, BitIndex: Word32): Word32;
|
|
asm
|
|
{$IFOPT R+}
|
|
CMP BitIndex, 32
|
|
JB @RangeOk
|
|
JMP RaiseRangeCheckError
|
|
@RangeOk:
|
|
{$ENDIF}
|
|
MOV ECX, DWORD PTR [BitIndex * 4 + BitMaskTable32]
|
|
NOT ECX
|
|
AND EAX, ECX
|
|
@Fin:
|
|
end;
|
|
{$ELSE}
|
|
function ClearBit32(const Value, BitIndex: Word32): Word32;
|
|
begin
|
|
Result := Value and not BitMaskTable32[BitIndex];
|
|
end;
|
|
{$ENDIF}
|
|
|
|
{$IFDEF ___ASM386_DELPHI}
|
|
function ToggleBit32(const Value, BitIndex: Word32): Word32;
|
|
asm
|
|
{$IFOPT R+}
|
|
CMP BitIndex, 32
|
|
JB @RangeOk
|
|
JMP RaiseRangeCheckError
|
|
@RangeOk:
|
|
{$ENDIF}
|
|
XOR EAX, DWORD PTR [BitIndex * 4 + BitMaskTable32]
|
|
end;
|
|
{$ELSE}
|
|
function ToggleBit32(const Value, BitIndex: Word32): Word32;
|
|
begin
|
|
Result := Value xor BitMaskTable32[BitIndex];
|
|
end;
|
|
{$ENDIF}
|
|
|
|
{$IFDEF ASM386_DELPHI}
|
|
function IsHighBitSet32(const Value: Word32): Boolean; register; assembler;
|
|
asm
|
|
TEST Value, $80000000
|
|
SETNZ AL
|
|
end;
|
|
{$ELSE}
|
|
function IsHighBitSet32(const Value: Word32): Boolean;
|
|
begin
|
|
Result := Value and $80000000 <> 0;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
{$IFDEF ___ASM386_DELPHI}
|
|
function IsBitSet32(const Value, BitIndex: Word32): Boolean;
|
|
asm
|
|
{$IFOPT R+}
|
|
CMP BitIndex, 32
|
|
JB @RangeOk
|
|
JMP RaiseRangeCheckError
|
|
@RangeOk:
|
|
{$ENDIF}
|
|
MOV ECX, DWORD PTR BitMaskTable32 [BitIndex * 4]
|
|
TEST Value, ECX
|
|
SETNZ AL
|
|
end;
|
|
{$ELSE}
|
|
function IsBitSet32(const Value, BitIndex: Word32): Boolean;
|
|
begin
|
|
Result := Value and BitMaskTable32[BitIndex] <> 0;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
{$IFDEF ASM386_DELPHI}
|
|
function SetBitScanForward32(const Value: Word32): Integer;
|
|
asm
|
|
OR EAX, EAX
|
|
JZ @NoBits
|
|
BSF EAX, EAX
|
|
RET
|
|
@NoBits:
|
|
MOV EAX, -1
|
|
end;
|
|
|
|
function SetBitScanForward32(const Value, BitIndex: Word32): Integer;
|
|
asm
|
|
CMP BitIndex, 32
|
|
JAE @NotFound
|
|
MOV ECX, BitIndex
|
|
MOV EDX, $FFFFFFFF
|
|
SHL EDX, CL
|
|
AND EDX, EAX
|
|
JE @NotFound
|
|
BSF EAX, EDX
|
|
RET
|
|
@NotFound:
|
|
MOV EAX, -1
|
|
end;
|
|
{$ELSE}
|
|
function SetBitScanForward32(const Value, BitIndex: Word32): Integer;
|
|
var I : Integer;
|
|
begin
|
|
if BitIndex < 32 then
|
|
for I := Integer(BitIndex) to 31 do
|
|
if Value and BitMaskTable32[I] <> 0 then
|
|
begin
|
|
Result := I;
|
|
exit;
|
|
end;
|
|
Result := -1;
|
|
end;
|
|
|
|
function SetBitScanForward32(const Value: Word32): Integer;
|
|
begin
|
|
Result := SetBitScanForward32(Value, 0);
|
|
end;
|
|
{$ENDIF}
|
|
|
|
{$IFDEF ASM386_DELPHI}
|
|
function SetBitScanReverse32(const Value: Word32): Integer;
|
|
asm
|
|
OR EAX, EAX
|
|
JZ @NoBits
|
|
BSR EAX, EAX
|
|
RET
|
|
@NoBits:
|
|
MOV EAX, -1
|
|
end;
|
|
|
|
function SetBitScanReverse32(const Value, BitIndex: Word32): Integer;
|
|
asm
|
|
CMP EDX, 32
|
|
JAE @NotFound
|
|
LEA ECX, [EDX - 31]
|
|
MOV EDX, $FFFFFFFF
|
|
NEG ECX
|
|
SHR EDX, CL
|
|
AND EDX, EAX
|
|
JE @NotFound
|
|
BSR EAX, EDX
|
|
RET
|
|
@NotFound:
|
|
MOV EAX, -1
|
|
end;
|
|
{$ELSE}
|
|
function SetBitScanReverse32(const Value, BitIndex: Word32): Integer;
|
|
var I : Integer;
|
|
begin
|
|
if BitIndex < 32 then
|
|
for I := Integer(BitIndex) downto 0 do
|
|
if Value and BitMaskTable32[I] <> 0 then
|
|
begin
|
|
Result := I;
|
|
exit;
|
|
end;
|
|
Result := -1;
|
|
end;
|
|
|
|
function SetBitScanReverse32(const Value: Word32): Integer;
|
|
begin
|
|
Result := SetBitScanReverse32(Value, 31);
|
|
end;
|
|
{$ENDIF}
|
|
|
|
{$IFDEF ASM386_DELPHI}
|
|
function ClearBitScanForward32(const Value: Word32): Integer;
|
|
asm
|
|
NOT EAX
|
|
OR EAX, EAX
|
|
JZ @NoBits
|
|
BSF EAX, EAX
|
|
RET
|
|
@NoBits:
|
|
MOV EAX, -1
|
|
end;
|
|
|
|
function ClearBitScanForward32(const Value, BitIndex: Word32): Integer;
|
|
asm
|
|
CMP EDX, 32
|
|
JAE @NotFound
|
|
MOV ECX, EDX
|
|
MOV EDX, $FFFFFFFF
|
|
NOT EAX
|
|
SHL EDX, CL
|
|
AND EDX, EAX
|
|
JE @NotFound
|
|
BSF EAX, EDX
|
|
RET
|
|
@NotFound:
|
|
MOV EAX, -1
|
|
end;
|
|
{$ELSE}
|
|
function ClearBitScanForward32(const Value, BitIndex: Word32): Integer;
|
|
var I : Integer;
|
|
begin
|
|
if BitIndex < 32 then
|
|
for I := Integer(BitIndex) to 31 do
|
|
if Value and BitMaskTable32[I] = 0 then
|
|
begin
|
|
Result := I;
|
|
exit;
|
|
end;
|
|
Result := -1;
|
|
end;
|
|
|
|
function ClearBitScanForward32(const Value: Word32): Integer;
|
|
begin
|
|
Result := ClearBitScanForward32(Value, 0);
|
|
end;
|
|
{$ENDIF}
|
|
|
|
{$IFDEF ASM386_DELPHI}
|
|
function ClearBitScanReverse32(const Value: Word32): Integer;
|
|
asm
|
|
NOT EAX
|
|
OR EAX, EAX
|
|
JZ @NoBits
|
|
BSR EAX, EAX
|
|
RET
|
|
@NoBits:
|
|
MOV EAX, -1
|
|
end;
|
|
|
|
function ClearBitScanReverse32(const Value, BitIndex: Word32): Integer;
|
|
asm
|
|
CMP EDX, 32
|
|
JAE @NotFound
|
|
LEA ECX, [EDX - 31]
|
|
MOV EDX, $FFFFFFFF
|
|
NEG ECX
|
|
NOT EAX
|
|
SHR EDX, CL
|
|
AND EDX, EAX
|
|
JE @NotFound
|
|
BSR EAX, EDX
|
|
RET
|
|
@NotFound:
|
|
MOV EAX, -1
|
|
end;
|
|
{$ELSE}
|
|
function ClearBitScanReverse32(const Value, BitIndex: Word32): Integer;
|
|
var I : Integer;
|
|
begin
|
|
if BitIndex < 32 then
|
|
for I := Integer(BitIndex) downto 0 do
|
|
if Value and BitMaskTable32[I] = 0 then
|
|
begin
|
|
Result := I;
|
|
exit;
|
|
end;
|
|
Result := -1;
|
|
end;
|
|
|
|
function ClearBitScanReverse32(const Value: Word32): Integer;
|
|
begin
|
|
Result := ClearBitScanReverse32(Value, 31);
|
|
end;
|
|
{$ENDIF}
|
|
|
|
const
|
|
BitCountTable32 : array[Byte] of Byte =
|
|
(0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
|
|
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
|
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
|
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
|
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
|
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
|
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
|
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
|
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
|
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
|
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
|
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
|
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
|
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
|
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
|
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8);
|
|
|
|
{$IFDEF ASM386_DELPHI}
|
|
function BitCount32(const Value: Word32): Word32; register; assembler;
|
|
asm
|
|
MOVZX EDX, AL
|
|
MOVZX EDX, BYTE PTR [EDX + BitCountTable32]
|
|
MOVZX ECX, AH
|
|
ADD DL, BYTE PTR [ECX + BitCountTable32]
|
|
SHR EAX, 16
|
|
MOVZX ECX, AH
|
|
ADD DL, BYTE PTR [ECX + BitCountTable32]
|
|
AND EAX, $FF
|
|
ADD DL, BYTE PTR [EAX + BitCountTable32]
|
|
MOV AL, DL
|
|
end;
|
|
{$ELSE}
|
|
function BitCount32(const Value: Word32): Word32;
|
|
begin
|
|
Result := BitCountTable32[(Value and $000000FF) ] +
|
|
BitCountTable32[(Value and $0000FF00) shr 8 ] +
|
|
BitCountTable32[(Value and $00FF0000) shr 16] +
|
|
BitCountTable32[(Value and $FF000000) shr 24];
|
|
end;
|
|
{$ENDIF}
|
|
|
|
function IsPowerOfTwo32(const Value: Word32): Boolean;
|
|
begin
|
|
Result := BitCount32(Value) = 1;
|
|
end;
|
|
|
|
function LowBitMask32(const HighBitIndex: Word32): Word32;
|
|
begin
|
|
if HighBitIndex >= 32 then
|
|
Result := 0
|
|
else
|
|
Result := BitMaskTable32[HighBitIndex] - 1;
|
|
end;
|
|
|
|
function HighBitMask32(const LowBitIndex: Word32): Word32;
|
|
begin
|
|
if LowBitIndex >= 32 then
|
|
Result := 0
|
|
else
|
|
Result := not BitMaskTable32[LowBitIndex] + 1;
|
|
end;
|
|
|
|
function RangeBitMask32(const LowBitIndex, HighBitIndex: Word32): Word32;
|
|
begin
|
|
if (LowBitIndex >= 32) and (HighBitIndex >= 32) then
|
|
begin
|
|
Result := 0;
|
|
exit;
|
|
end;
|
|
Result := $FFFFFFFF;
|
|
if LowBitIndex > 0 then
|
|
Result := Result xor (BitMaskTable32[LowBitIndex] - 1);
|
|
if HighBitIndex < 31 then
|
|
Result := Result xor (not BitMaskTable32[HighBitIndex + 1] + 1);
|
|
end;
|
|
|
|
function SetBitRange32(const Value: Word32; const LowBitIndex, HighBitIndex: Word32): Word32;
|
|
begin
|
|
Result := Value or RangeBitMask32(LowBitIndex, HighBitIndex);
|
|
end;
|
|
|
|
function ClearBitRange32(const Value: Word32; const LowBitIndex, HighBitIndex: Word32): Word32;
|
|
begin
|
|
Result := Value and not RangeBitMask32(LowBitIndex, HighBitIndex);
|
|
end;
|
|
|
|
function ToggleBitRange32(const Value: Word32; const LowBitIndex, HighBitIndex: Word32): Word32;
|
|
begin
|
|
Result := Value xor RangeBitMask32(LowBitIndex, HighBitIndex);
|
|
end;
|
|
|
|
function IsBitRangeSet32(const Value: Word32; const LowBitIndex, HighBitIndex: Word32): Boolean;
|
|
var M: Word32;
|
|
begin
|
|
M := RangeBitMask32(LowBitIndex, HighBitIndex);
|
|
Result := Value and M = M;
|
|
end;
|
|
|
|
function IsBitRangeClear32(const Value: Word32; const LowBitIndex, HighBitIndex: Word32): Boolean;
|
|
begin
|
|
Result := Value and RangeBitMask32(LowBitIndex, HighBitIndex) = 0;
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ Test cases }
|
|
{ }
|
|
{$IFDEF DEBUG}
|
|
{$IFDEF TEST}
|
|
{$ASSERTIONS ON}
|
|
procedure Test;
|
|
begin
|
|
Assert(SetBit32($100F, 5) = $102F, 'SetBit');
|
|
Assert(ClearBit32($102F, 5) = $100F, 'ClearBit');
|
|
Assert(ToggleBit32($102F, 5) = $100F, 'ToggleBit');
|
|
Assert(ToggleBit32($100F, 5) = $102F, 'ToggleBit');
|
|
Assert(IsBitSet32($102F, 5), 'IsBitSet');
|
|
Assert(not IsBitSet32($100F, 5), 'IsBitSet');
|
|
Assert(IsHighBitSet32($80000000), 'IsHighBitSet');
|
|
Assert(not IsHighBitSet32($00000001), 'IsHighBitSet');
|
|
Assert(not IsHighBitSet32($7FFFFFFF), 'IsHighBitSet');
|
|
|
|
Assert(SetBitScanForward32(0) = -1, 'SetBitScanForward');
|
|
Assert(SetBitScanForward32($1020) = 5, 'SetBitScanForward');
|
|
Assert(SetBitScanReverse32($1020) = 12, 'SetBitScanForward');
|
|
Assert(SetBitScanForward32($1020, 6) = 12, 'SetBitScanForward');
|
|
Assert(SetBitScanReverse32($1020, 11) = 5, 'SetBitScanForward');
|
|
Assert(ClearBitScanForward32($FFFFFFFF) = -1, 'ClearBitScanForward');
|
|
Assert(ClearBitScanForward32($1020) = 0, 'ClearBitScanForward');
|
|
Assert(ClearBitScanReverse32($1020) = 31, 'ClearBitScanForward');
|
|
Assert(ClearBitScanForward32($1020, 5) = 6, 'ClearBitScanForward');
|
|
Assert(ClearBitScanReverse32($1020, 12) = 11, 'ClearBitScanForward');
|
|
|
|
Assert(ReverseBits32($12345678) = $1E6A2C48, 'ReverseBits');
|
|
Assert(ReverseBits32($1) = $80000000, 'ReverseBits');
|
|
Assert(ReverseBits32($80000000) = $1, 'ReverseBits');
|
|
Assert(SwapEndian32($12345678) = $78563412, 'SwapEndian');
|
|
|
|
Assert(BitCount32($12341234) = 10, 'BitCount');
|
|
Assert(IsPowerOfTwo32(1), 'IsPowerOfTwo');
|
|
Assert(IsPowerOfTwo32(2), 'IsPowerOfTwo');
|
|
Assert(not IsPowerOfTwo32(3), 'IsPowerOfTwo');
|
|
|
|
Assert(RotateLeftBits32(0, 1) = 0, 'RotateLeftBits32');
|
|
Assert(RotateLeftBits32(1, 0) = 1, 'RotateLeftBits32');
|
|
Assert(RotateLeftBits32(1, 1) = 2, 'RotateLeftBits32');
|
|
Assert(RotateLeftBits32($80000000, 1) = 1, 'RotateLeftBits32');
|
|
Assert(RotateLeftBits32($80000001, 1) = 3, 'RotateLeftBits32');
|
|
Assert(RotateLeftBits32(1, 2) = 4, 'RotateLeftBits32');
|
|
Assert(RotateLeftBits32(1, 31) = $80000000, 'RotateLeftBits32');
|
|
Assert(RotateLeftBits32(5, 2) = 20, 'RotateLeftBits32');
|
|
Assert(RotateRightBits32(0, 1) = 0, 'RotateRightBits32');
|
|
Assert(RotateRightBits32(1, 0) = 1, 'RotateRightBits32');
|
|
Assert(RotateRightBits32(1, 1) = $80000000, 'RotateRightBits32');
|
|
Assert(RotateRightBits32(2, 1) = 1, 'RotateRightBits32');
|
|
Assert(RotateRightBits32(4, 2) = 1, 'RotateRightBits32');
|
|
|
|
Assert(LowBitMask32(10) = $3FF, 'LowBitMask');
|
|
Assert(HighBitMask32(28) = $F0000000, 'HighBitMask');
|
|
Assert(RangeBitMask32(2, 6) = $7C, 'RangeBitMask');
|
|
|
|
Assert(SetBitRange32($101, 2, 6) = $17D, 'SetBitRange');
|
|
Assert(ClearBitRange32($17D, 2, 6) = $101, 'ClearBitRange');
|
|
Assert(ToggleBitRange32($17D, 2, 6) = $101, 'ToggleBitRange');
|
|
Assert(IsBitRangeSet32($17D, 2, 6), 'IsBitRangeSet');
|
|
Assert(not IsBitRangeSet32($101, 2, 6), 'IsBitRangeSet');
|
|
Assert(not IsBitRangeClear32($17D, 2, 6), 'IsBitRangeClear');
|
|
Assert(IsBitRangeClear32($101, 2, 6), 'IsBitRangeClear');
|
|
end;
|
|
{$ENDIF}
|
|
{$ENDIF}
|
|
|
|
|
|
end.
|
|
|