34 private int $value = 0;
35 private int $offset = 0;
37 public function __construct(
41 public function writeInt(
int $bits,
int $value) :
void{
42 if($this->offset + $bits > $this->maxBits){
43 throw new \InvalidArgumentException(
"Bit buffer cannot be larger than $this->maxBits bits (already have $this->offset bits)");
45 if(($value & (~0 << $bits)) !== 0){
46 throw new \InvalidArgumentException(
"Value $value does not fit into $bits bits");
49 $this->value |= ($value << $this->offset);
50 $this->offset += $bits;
53 public function int(
int $bits,
int &$value) :
void{
54 $this->writeInt($bits, $value);
57 private function writeBoundedIntAuto(
int $min,
int $max,
int $value) :
void{
58 if($value < $min || $value > $max){
59 throw new \InvalidArgumentException(
"Value $value is outside the range $min - $max");
61 $bits = ((int) log($max - $min, 2)) + 1;
62 $this->writeInt($bits, $value - $min);
66 $this->writeBoundedIntAuto($min, $max, $value);
69 protected function writeBool(
bool $value) : void{
70 $this->writeInt(1, $value ? 1 : 0);
73 public function bool(
bool &$value) : void{
74 $this->writeBool($value);
77 public function horizontalFacing(
int &$facing) : void{
78 $this->writeInt(2, match($facing){
83 default =>
throw new \InvalidArgumentException(
"Invalid horizontal facing $facing")
91 $uniqueFaces = array_flip($faces);
92 foreach(Facing::ALL as $facing){
93 $this->writeBool(isset($uniqueFaces[$facing]));
101 $uniqueFaces = array_flip($faces);
102 foreach(Facing::HORIZONTAL as $facing){
103 $this->writeBool(isset($uniqueFaces[$facing]));
107 public function facing(
int &$facing) : void{
108 $this->writeInt(3, match($facing){
115 default =>
throw new \InvalidArgumentException(
"Invalid facing $facing")
119 public function facingExcept(
int &$facing,
int $except) : void{
120 $this->facing($facing);
123 public function axis(
int &$axis) : void{
124 $this->writeInt(2, match($axis){
128 default =>
throw new \InvalidArgumentException(
"Invalid axis $axis")
132 public function horizontalAxis(
int &$axis) : void{
133 $this->writeInt(1, match($axis){
136 default =>
throw new \InvalidArgumentException(
"Invalid horizontal axis $axis")
147 foreach(Facing::HORIZONTAL as $facing){
148 $packed += match($connections[$facing] ??
null){
150 WallConnectionType::SHORT => 1,
151 WallConnectionType::TALL => 2,
155 $this->writeBoundedIntAuto(0, (3 ** 4) - 1, $packed);
158 public function railShape(
int &$railShape) : void{
159 $this->int(4, $railShape);
162 public function straightOnlyRailShape(
int &$railShape) : void{
163 $this->int(3, $railShape);
166 public function enum(\UnitEnum &$case) :
void{
167 $metadata = RuntimeEnumMetadata::from($case);
168 $this->writeInt($metadata->bits, $metadata->enumToInt($case));
171 public function enumSet(array &$set, array $allCases) : void{
172 foreach($allCases as $case){
173 $this->writeBool(isset($set[spl_object_id($case)]));
177 public function getValue() : int{ return $this->value; }
179 public function getOffset() : int{ return $this->offset; }