PocketMine-MP 5.35.1 git-e32e836dad793a3a3c8ddd8927c00e112b1e576a
Loading...
Searching...
No Matches
BitSet.php
1<?php
2
3/*
4 * This file is part of BedrockProtocol.
5 * Copyright (C) 2014-2022 PocketMine Team <https://github.com/pmmp/BedrockProtocol>
6 *
7 * BedrockProtocol is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 */
12
13declare(strict_types=1);
14
15namespace pocketmine\network\mcpe\protocol\serializer;
16
17use pmmp\encoding\Byte;
18use pmmp\encoding\ByteBufferReader;use pmmp\encoding\ByteBufferWriter;
19use function array_pad;
20use function array_slice;
21use function array_values;
22use function count;
23use function intdiv;
24
25class BitSet{
26 private const INT_BITS = PHP_INT_SIZE * 8;
27 private const SHIFT = 7;
28
32 public function __construct(
33 private readonly int $length,
34 private array $parts = []
35 ){
36 $expectedPartsCount = self::getExpectedPartsCount($length);
37 $partsCount = count($parts);
38
39 if($partsCount > $expectedPartsCount){
40 throw new \InvalidArgumentException("Too many parts");
41 }elseif($partsCount < $expectedPartsCount){
42 $parts = array_pad($parts, $expectedPartsCount, 0);
43 }
44
45 $this->parts = array_values($parts);
46 }
47
48 public function get(int $index) : bool{
49 [$partIndex, $bitIndex] = $this->getPartIndex($index);
50
51 return ($this->parts[$partIndex] & (1 << $bitIndex)) !== 0;
52 }
53
54 public function set(int $index, bool $value) : void{
55 [$partIndex, $bitIndex] = $this->getPartIndex($index);
56
57 if($value){
58 $this->parts[$partIndex] |= 1 << $bitIndex;
59 }else{
60 $this->parts[$partIndex] &= ~(1 << $bitIndex);
61 }
62 }
63
69 private function getPartIndex(int $index) : array{
70 if($index < 0 or $index >= $this->length){
71 throw new \InvalidArgumentException("Index out of bounds");
72 }
73
74 return [
75 intdiv($index, self::INT_BITS),
76 $index % self::INT_BITS
77 ];
78 }
79
83 public function getPartsCount() : int{
84 return count($this->parts);
85 }
86
87 private static function getExpectedPartsCount(int $length) : int{
88 return intdiv($length + self::INT_BITS - 1, self::INT_BITS);
89 }
90
91 public static function read(ByteBufferReader $in, int $length) : self{
92 $result = [0];
93
94 $currentIndex = 0;
95 $currentShift = 0;
96
97 for($i = 0; $i < $length; $i += self::SHIFT){
98 $b = Byte::readUnsigned($in);
99 $bits = $b & 0x7f;
100
101 $result[$currentIndex] |= $bits << $currentShift; //extra bits will be discarded
102 $nextShift = $currentShift + self::SHIFT;
103 if($nextShift >= self::INT_BITS){
104 $nextShift -= self::INT_BITS;
105 $rightShift = self::SHIFT - $nextShift;
106 $result[++$currentIndex] = $bits >> $rightShift;
107 }
108 $currentShift = $nextShift;
109
110 if(($b & 0x80) === 0){
111 return new self($length, array_slice($result, 0, self::getExpectedPartsCount($length)));
112 }
113 }
114
115 return new self($length, array_slice($result, 0, self::getExpectedPartsCount($length)));
116 }
117
118 public function write(ByteBufferWriter $out) : void{
119 $parts = $this->parts;
120 $length = $this->length;
121
122 $currentIndex = 0;
123 $currentShift = 0;
124
125 for($i = 0; $i < $length; $i += self::SHIFT){
126 $bits = $parts[$currentIndex] >> $currentShift;
127 $nextShift = $currentShift + self::SHIFT;
128 if($nextShift >= self::INT_BITS){
129 $nextShift -= self::INT_BITS;
130 $bits |= ($parts[++$currentIndex] ?? 0) << (self::SHIFT - $nextShift);
131 }
132 $currentShift = $nextShift;
133
134 $last = $i + self::SHIFT >= $length;
135 $bits |= $last ? 0 : 0x80;
136
137 Byte::writeUnsigned($out, $bits);
138 if($last){
139 break;
140 }
141 }
142 }
143
144 public function getLength() : int{
145 return $this->length;
146 }
147
148 public function equals(BitSet $that) : bool{
149 return $this->length === $that->length && $this->parts === $that->parts;
150 }
151}
__construct(private readonly int $length, private array $parts=[])
Definition BitSet.php:32