-
Notifications
You must be signed in to change notification settings - Fork 6
/
Bits.php
121 lines (109 loc) · 3.31 KB
/
Bits.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
<?php
declare(strict_types=1);
namespace BitMask\Util;
use BitMask\Exception\NotSingleBitException;
use BitMask\Exception\OutOfRangeException;
final class Bits
{
/**
* get most significant bit position (right -> left, index)
* @example 10001 -> 4, 0010 -> 1, 00100010 -> 5
*/
public static function getMostSignificantBit(int $mask): int
{
return (int) log($mask, 2);
}
/**
* get array of set bits
* @example 10010 => [2, 16], 111 => [1, 2, 4]
* @return int[]
*/
public static function getSetBits(int $mask): array
{
$bits = [];
$scan = 1;
while ($mask >= $scan) {
if ($mask & $scan) {
$bits[] = $scan;
}
$scan <<= 1;
}
return $bits;
}
/**
* is given bit was single checked bit (msb === 1 && other === 0)
* @example 1000 => true, 010100 => false, 0000100 => true
* @see benchmarks/IsSingleBitBench.php
* ./vendor/bin/phpbench run benchmarks/IsSingleBitBench.php --report=default
*/
public static function isSingleBit(int $mask): bool
{
return 1 << Bits::getMostSignificantBit($mask) === $mask;
}
/**
* single bit to index (left > right)
* @throws NotSingleBitException
* @psalm-suppress PossiblyUnusedMethod
*/
public static function bitToIndex(int $mask): int
{
if (!self::isSingleBit($mask)) {
throw new NotSingleBitException('Argument must be a single bit');
}
return self::getMostSignificantBit($mask);
}
/**
* index to single bit
* @example 0 => 0b1 (1), 1 => 0b10 (2), 2 => 0b100 (4), ...
* @see benchmarks/IndexToBitBench.php
* ./vendor/bin/phpbench run benchmarks/IndexToBitBench.php --report=default
*
* @throws OutOfRangeException
*/
public static function indexToBit(int $index): int
{
if ($index < 0) {
throw new OutOfRangeException((string) $index);
}
return intval(abs(1 << $index));
}
/** @psalm-suppress PossiblyUnusedMethod */
public static function toString(int $mask): string
{
return decbin($mask);
}
/**
* @return int[]
* @see benchmarks/GetSetBitsIndexBench.php
* ./vendor/bin/phpbench run benchmarks/GetSetBitsIndexBench.php --report=default
* @psalm-suppress PossiblyUnusedMethod
*/
public static function getSetBitsIndexes(int $mask): array
{
$bitIndexes = [];
foreach (self::getSetBits($mask) as $index => $bit) {
$bitIndexes[$index] = self::getMostSignificantBit($bit);
}
return $bitIndexes;
}
/**
* Bitwise-based check if given number is even
* @see benchmarks/EvenOddBench.php
* ./vendor/bin/phpbench run benchmarks/EvenOddBench.php --report=default
* @psalm-suppress PossiblyUnusedMethod
*/
public static function isEvenNumber(int $number): bool
{
return ($number & 1) === 0;
}
/**
* Bitwise-based check if given number is odd
* @see benchmarks/EvenOddBench.php
* ./vendor/bin/phpbench run benchmarks/EvenOddBench.php --report=default
* @psalm-suppress PossiblyUnusedMethod
*/
public static function isOddNumber(int $number): bool
{
return ($number & 1) === 1;
}
}