Skip to content

Commit a820036

Browse files
committed
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
1 parent cd5401f commit a820036

File tree

1 file changed

+26
-28
lines changed

1 file changed

+26
-28
lines changed

src/TrinaryLogic.php

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -14,31 +14,35 @@
1414
*/
1515
final class TrinaryLogic
1616
{
17+
private const YES = 3;
18+
private const MAYBE = 1;
19+
private const NO = 0;
1720

18-
private const YES = 1;
19-
private const MAYBE = 0;
20-
private const NO = -1;
2121

2222
/** @var self[] */
2323
private static array $registry = [];
2424

25+
private static self $YES;
26+
private static self $MAYBE;
27+
private static self $NO;
28+
2529
private function __construct(private int $value)
2630
{
2731
}
2832

2933
public static function createYes(): self
3034
{
31-
return self::$registry[self::YES] ??= new self(self::YES);
35+
return self::$YES ??= (self::$registry[self::YES] ??= new self(self::YES));
3236
}
3337

3438
public static function createNo(): self
3539
{
36-
return self::$registry[self::NO] ??= new self(self::NO);
40+
return self::$NO ??= (self::$registry[self::NO] ??= new self(self::NO));
3741
}
3842

3943
public static function createMaybe(): self
4044
{
41-
return self::$registry[self::MAYBE] ??= new self(self::MAYBE);
45+
return self::$MAYBE ??= (self::$registry[self::MAYBE] ??= new self(self::MAYBE));
4246
}
4347

4448
public static function createFromBoolean(bool $value): self
@@ -49,8 +53,7 @@ public static function createFromBoolean(bool $value): self
4953

5054
private static function create(int $value): self
5155
{
52-
self::$registry[$value] ??= new self($value);
53-
return self::$registry[$value];
56+
return self::$registry[$value] ??= new self($value);
5457
}
5558

5659
/**
@@ -89,17 +92,13 @@ public function toBooleanType(): BooleanType
8992
return new ConstantBooleanType($this->value === self::YES);
9093
}
9194

92-
public function and(self ...$operands): self
95+
public function and(self $operand, self ...$rest): self
9396
{
94-
$min = $this->value;
95-
foreach ($operands as $operand) {
96-
if ($operand->value >= $min) {
97-
continue;
98-
}
99-
100-
$min = $operand->value;
97+
$min = $this->value & $operand->value;
98+
foreach ($rest as $operand) {
99+
$min &= $operand->value;
101100
}
102-
return self::create($min);
101+
return self::$registry[$min] ??= new self($min);
103102
}
104103

105104
/**
@@ -129,17 +128,13 @@ public function lazyAnd(
129128
return $this->and(...$results);
130129
}
131130

132-
public function or(self ...$operands): self
131+
public function or(self $operand, self ...$rest): self
133132
{
134-
$max = $this->value;
135-
foreach ($operands as $operand) {
136-
if ($operand->value < $max) {
137-
continue;
138-
}
139-
140-
$max = $operand->value;
133+
$max = $this->value | $operand->value;
134+
foreach ($rest as $operand) {
135+
$max |= $operand->value;
141136
}
142-
return self::create($max);
137+
return self::$registry[$max] ??= new self($max);
143138
}
144139

145140
/**
@@ -217,7 +212,7 @@ public static function maxMin(self ...$operands): self
217212
throw new ShouldNotHappenException();
218213
}
219214
$operandValues = array_column($operands, 'value');
220-
return self::create(max($operandValues) > 0 ? 1 : min($operandValues));
215+
return self::create(max($operandValues) > self::MAYBE ? self::YES : min($operandValues));
221216
}
222217

223218
/**
@@ -245,7 +240,10 @@ public static function lazyMaxMin(
245240

246241
public function negate(): self
247242
{
248-
return self::create(-$this->value);
243+
// 0b11 >> 0 == 0b11 (3)
244+
// 0b11 >> 1 == 0b01 (1)
245+
// 0b11 >> 3 == 0b00 (0)
246+
return self::create(3 >> $this->value);
249247
}
250248

251249
public function equals(self $other): bool

0 commit comments

Comments
 (0)