24 private const INT_BITS = PHP_INT_SIZE * 8;
25 private const SHIFT = 7;
31 private readonly
int $length,
32 private array $parts = []
34 $expectedPartsCount = self::getExpectedPartsCount($length);
35 $partsCount = count($parts);
37 if($partsCount > $expectedPartsCount){
38 throw new \InvalidArgumentException(
"Too many parts");
39 }elseif($partsCount < $expectedPartsCount){
40 $parts = array_pad($parts, $expectedPartsCount, 0);
43 $this->parts = array_values($parts);
46 public function get(
int $index) : bool{
47 [$partIndex, $bitIndex] = $this->getPartIndex($index);
49 return ($this->parts[$partIndex] & (1 << $bitIndex)) !== 0;
52 public function set(
int $index,
bool $value) :
void{
53 [$partIndex, $bitIndex] = $this->getPartIndex($index);
56 $this->parts[$partIndex] |= 1 << $bitIndex;
58 $this->parts[$partIndex] &= ~(1 << $bitIndex);
67 private function getPartIndex(
int $index) : array{
68 if($index < 0 or $index >= $this->length){
69 throw new \InvalidArgumentException(
"Index out of bounds");
73 intdiv($index, self::INT_BITS),
74 $index % self::INT_BITS
81 public function getPartsCount() : int{
82 return count($this->parts);
85 private static function getExpectedPartsCount(
int $length) : int{
86 return intdiv($length + self::INT_BITS - 1, self::INT_BITS);
89 public static function read(PacketSerializer $in,
int $length) : self{
95 for($i = 0; $i < $length; $i += self::SHIFT){
99 $result[$currentIndex] |= $bits << $currentShift;
100 $nextShift = $currentShift + self::SHIFT;
101 if($nextShift >= self::INT_BITS){
102 $nextShift -= self::INT_BITS;
103 $rightShift = self::SHIFT - $nextShift;
104 $result[++$currentIndex] = $bits >> $rightShift;
106 $currentShift = $nextShift;
108 if(($b & 0x80) === 0){
109 return new self($length, array_slice($result, 0, self::getExpectedPartsCount($length)));
113 return new self($length, array_slice($result, 0, self::getExpectedPartsCount($length)));
116 public function write(PacketSerializer $out) : void{
117 $parts = $this->parts;
118 $length = $this->length;
123 for($i = 0; $i < $length; $i += self::SHIFT){
124 $bits = $parts[$currentIndex] >> $currentShift;
125 $nextShift = $currentShift + self::SHIFT;
126 if($nextShift >= self::INT_BITS){
127 $nextShift -= self::INT_BITS;
128 $bits |= ($parts[++$currentIndex] ?? 0) << (self::SHIFT - $nextShift);
130 $currentShift = $nextShift;
132 $last = $i + self::SHIFT >= $length;
133 $bits |= $last ? 0 : 0x80;
135 $out->putByte($bits);
142 public function getLength() : int{
143 return $this->length;