From 526e9b2b3ebf825f4c7ef1dfc5930f1848a0d1f0 Mon Sep 17 00:00:00 2001 From: K Date: Thu, 29 Jan 2026 12:54:51 +0100 Subject: [PATCH 1/2] speed up TrinaryLogic - Split variadic arguments for and() and or(). Common case of single argument doesn't allocate an array. - Add static fields mirroring $registry to skip one level of indirection. - Numeric values chosen that & and | is the same as min and max. and()/or() optimized accordingly. - Inline trivial create() method. - Remove one unnecessary access to registry in method create(). this loop runs 1.8x faster (php 8.4.16, jit off) $t = TrinaryLogic::createYes(); for ($i = 10_000_000; $i--;) { $t = $t->and(TrinaryLogic::createYes()); } before: 1.125 s now: 0.616 s --- src/TrinaryLogic.php | 54 +++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/src/TrinaryLogic.php b/src/TrinaryLogic.php index e628893e96..ce6b99c63a 100644 --- a/src/TrinaryLogic.php +++ b/src/TrinaryLogic.php @@ -38,31 +38,35 @@ */ final class TrinaryLogic { + private const YES = 3; + private const MAYBE = 1; + private const NO = 0; - private const YES = 1; - private const MAYBE = 0; - private const NO = -1; /** @var self[] */ private static array $registry = []; + private static self $YES; + private static self $MAYBE; + private static self $NO; + private function __construct(private int $value) { } public static function createYes(): self { - return self::$registry[self::YES] ??= new self(self::YES); + return self::$YES ??= (self::$registry[self::YES] ??= new self(self::YES)); } public static function createNo(): self { - return self::$registry[self::NO] ??= new self(self::NO); + return self::$NO ??= (self::$registry[self::NO] ??= new self(self::NO)); } public static function createMaybe(): self { - return self::$registry[self::MAYBE] ??= new self(self::MAYBE); + return self::$MAYBE ??= (self::$registry[self::MAYBE] ??= new self(self::MAYBE)); } public static function createFromBoolean(bool $value): self @@ -73,8 +77,7 @@ public static function createFromBoolean(bool $value): self private static function create(int $value): self { - self::$registry[$value] ??= new self($value); - return self::$registry[$value]; + return self::$registry[$value] ??= new self($value); } /** @@ -113,17 +116,13 @@ public function toBooleanType(): BooleanType return new ConstantBooleanType($this->value === self::YES); } - public function and(self ...$operands): self + public function and(?self $operand = null, self ...$rest): self { - $min = $this->value; - foreach ($operands as $operand) { - if ($operand->value >= $min) { - continue; - } - - $min = $operand->value; + $min = $this->value & ($operand !== null ? $operand->value : self::YES); + foreach ($rest as $operand) { + $min &= $operand->value; } - return self::create($min); + return self::$registry[$min] ??= new self($min); } /** @@ -153,17 +152,13 @@ public function lazyAnd( return $this->and(...$results); } - public function or(self ...$operands): self + public function or(?self $operand = null, self ...$rest): self { - $max = $this->value; - foreach ($operands as $operand) { - if ($operand->value < $max) { - continue; - } - - $max = $operand->value; + $max = $this->value | ($operand !== null ? $operand->value : self::NO); + foreach ($rest as $operand) { + $max |= $operand->value; } - return self::create($max); + return self::$registry[$max] ??= new self($max); } /** @@ -247,7 +242,7 @@ public static function maxMin(self ...$operands): self throw new ShouldNotHappenException(); } $operandValues = array_column($operands, 'value'); - return self::create(max($operandValues) > 0 ? 1 : min($operandValues)); + return self::create(max($operandValues) > self::MAYBE ? self::YES : min($operandValues)); } /** @@ -275,7 +270,10 @@ public static function lazyMaxMin( public function negate(): self { - return self::create(-$this->value); + // 0b11 >> 0 == 0b11 (3) + // 0b11 >> 1 == 0b01 (1) + // 0b11 >> 3 == 0b00 (0) + return self::create(3 >> $this->value); } public function equals(self $other): bool From e2c3fa1172699e8beca2f2309ba69a4d77af86a1 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Mon, 16 Feb 2026 10:25:53 +0100 Subject: [PATCH 2/2] fix build --- src/TrinaryLogic.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/TrinaryLogic.php b/src/TrinaryLogic.php index ce6b99c63a..09c7989601 100644 --- a/src/TrinaryLogic.php +++ b/src/TrinaryLogic.php @@ -38,16 +38,18 @@ */ final class TrinaryLogic { + private const YES = 3; private const MAYBE = 1; private const NO = 0; - /** @var self[] */ private static array $registry = []; private static self $YES; + private static self $MAYBE; + private static self $NO; private function __construct(private int $value) @@ -119,8 +121,8 @@ public function toBooleanType(): BooleanType public function and(?self $operand = null, self ...$rest): self { $min = $this->value & ($operand !== null ? $operand->value : self::YES); - foreach ($rest as $operand) { - $min &= $operand->value; + foreach ($rest as $restOperand) { + $min &= $restOperand->value; } return self::$registry[$min] ??= new self($min); } @@ -155,8 +157,8 @@ public function lazyAnd( public function or(?self $operand = null, self ...$rest): self { $max = $this->value | ($operand !== null ? $operand->value : self::NO); - foreach ($rest as $operand) { - $max |= $operand->value; + foreach ($rest as $restOperand) { + $max |= $restOperand->value; } return self::$registry[$max] ??= new self($max); }