|
5 | 5 |
|
6 | 6 | namespace DR\JBDiff\Util;
|
7 | 7 |
|
| 8 | +use InvalidArgumentException; |
8 | 9 | use Stringable;
|
9 | 10 |
|
10 | 11 | class BitSet implements Stringable
|
@@ -83,6 +84,71 @@ public function __unserialize(array $data): void
|
83 | 84 | $this->words = $data;
|
84 | 85 | }
|
85 | 86 |
|
| 87 | + /** |
| 88 | + * Convert the BitSet to binary string, which can be turned into BitSet again via @see BitSet::fromBinaryString. Note: this method |
| 89 | + * is not compatible between 32-bit and 64-bit systems. |
| 90 | + */ |
| 91 | + public function toBinaryString(): string |
| 92 | + { |
| 93 | + if (count($this->words) === 0) { |
| 94 | + return ''; |
| 95 | + } |
| 96 | + |
| 97 | + $words = []; |
| 98 | + |
| 99 | + // ensure all slots between 0 and maxKey have a value |
| 100 | + $maxKey = max(...array_keys($this->words)); |
| 101 | + for ($i = 0; $i <= $maxKey; $i++) { |
| 102 | + $words[$i] = $this->words[$i] ?? 0; |
| 103 | + } |
| 104 | + |
| 105 | + return pack(PHP_INT_SIZE === 4 ? 'N*' : 'J*', ...$words); |
| 106 | + } |
| 107 | + |
| 108 | + /** |
| 109 | + * Convert the BitSet to base64 encode binary string, which can be turned into BitSet again via @see BitSet::fromBase64String. Note: this method |
| 110 | + * is not compatible between 32-bit and 64-bit systems. |
| 111 | + */ |
| 112 | + public function toBase64String(): string |
| 113 | + { |
| 114 | + return base64_encode($this->toBinaryString()); |
| 115 | + } |
| 116 | + |
| 117 | + public static function fromBinaryString(string $data): BitSet |
| 118 | + { |
| 119 | + $bitSet = new BitSet(); |
| 120 | + |
| 121 | + if ($data === '') { |
| 122 | + return $bitSet; |
| 123 | + } |
| 124 | + |
| 125 | + $words = unpack(PHP_INT_SIZE === 4 ? 'N*' : 'J*', $data); |
| 126 | + if ($words === false || count($words) === 0) { |
| 127 | + throw new InvalidArgumentException('Unable to unpack from binary string: ' . base64_encode($data)); |
| 128 | + } |
| 129 | + |
| 130 | + // cleanup all keys where value = 0; |
| 131 | + $index = 0; |
| 132 | + foreach ($words as $value) { |
| 133 | + if ($value !== 0) { |
| 134 | + $bitSet->words[$index] = $value; |
| 135 | + } |
| 136 | + ++$index; |
| 137 | + } |
| 138 | + |
| 139 | + return $bitSet; |
| 140 | + } |
| 141 | + |
| 142 | + public static function fromBase64String(string $data): BitSet |
| 143 | + { |
| 144 | + $decoded = base64_decode($data, true); |
| 145 | + if ($decoded === false) { |
| 146 | + throw new InvalidArgumentException('Unable to decode base64 string: ' . $data); |
| 147 | + } |
| 148 | + |
| 149 | + return self::fromBinaryString($decoded); |
| 150 | + } |
| 151 | + |
86 | 152 | /**
|
87 | 153 | * @return array<int, int>
|
88 | 154 | */
|
|
0 commit comments