26    private const INT_BITS = PHP_INT_SIZE * 8;
 
   27    private const SHIFT = 7;
 
   33        private readonly 
int $length,
 
   34        private array $parts = []
 
   36        $expectedPartsCount = self::getExpectedPartsCount($length);
 
   37        $partsCount = count($parts);
 
   39        if($partsCount > $expectedPartsCount){
 
   40            throw new \InvalidArgumentException(
"Too many parts");
 
   41        }elseif($partsCount < $expectedPartsCount){
 
   42            $parts = array_pad($parts, $expectedPartsCount, 0);
 
   45        $this->parts = array_values($parts);
 
 
   48    public function get(
int $index) : bool{
 
   49        [$partIndex, $bitIndex] = $this->getPartIndex($index);
 
   51        return ($this->parts[$partIndex] & (1 << $bitIndex)) !== 0;
 
   54    public function set(
int $index, 
bool $value) : 
void{
 
   55        [$partIndex, $bitIndex] = $this->getPartIndex($index);
 
   58            $this->parts[$partIndex] |= 1 << $bitIndex;
 
   60            $this->parts[$partIndex] &= ~(1 << $bitIndex);
 
   69    private function getPartIndex(
int $index) : array{
 
   70        if($index < 0 or $index >= $this->length){
 
   71            throw new \InvalidArgumentException(
"Index out of bounds");
 
   75            intdiv($index, self::INT_BITS),
 
   76            $index % self::INT_BITS
 
   83    public function getPartsCount() : int{
 
   84        return count($this->parts);
 
   87    private static function getExpectedPartsCount(
int $length) : int{
 
   88        return intdiv($length + self::INT_BITS - 1, self::INT_BITS);
 
   91    public static function read(ByteBufferReader $in, 
int $length) : self{
 
   97        for($i = 0; $i < $length; $i += self::SHIFT){
 
   98            $b = Byte::readUnsigned($in);
 
  101            $result[$currentIndex] |= $bits << $currentShift; 
 
  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;
 
  108            $currentShift = $nextShift;
 
  110            if(($b & 0x80) === 0){
 
  111                return new self($length, array_slice($result, 0, self::getExpectedPartsCount($length)));
 
  115        return new self($length, array_slice($result, 0, self::getExpectedPartsCount($length)));
 
  118    public function write(ByteBufferWriter $out) : void{
 
  119        $parts = $this->parts;
 
  120        $length = $this->length;
 
  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);
 
  132            $currentShift = $nextShift;
 
  134            $last = $i + self::SHIFT >= $length;
 
  135            $bits |= $last ? 0 : 0x80;
 
  137            Byte::writeUnsigned($out, $bits);
 
  144    public function getLength() : int{
 
  145        return $this->length;
 
  148    public function equals(BitSet $that) : bool{
 
  149        return $this->length === $that->length && $this->parts === $that->parts;