Skip to content

Commit 526e9b2

Browse files
kaja47staabm
authored andcommitted
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 47923ed commit 526e9b2

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
@@ -38,31 +38,35 @@
3838
*/
3939
final class TrinaryLogic
4040
{
41+
private const YES = 3;
42+
private const MAYBE = 1;
43+
private const NO = 0;
4144

42-
private const YES = 1;
43-
private const MAYBE = 0;
44-
private const NO = -1;
4545

4646
/** @var self[] */
4747
private static array $registry = [];
4848

49+
private static self $YES;
50+
private static self $MAYBE;
51+
private static self $NO;
52+
4953
private function __construct(private int $value)
5054
{
5155
}
5256

5357
public static function createYes(): self
5458
{
55-
return self::$registry[self::YES] ??= new self(self::YES);
59+
return self::$YES ??= (self::$registry[self::YES] ??= new self(self::YES));
5660
}
5761

5862
public static function createNo(): self
5963
{
60-
return self::$registry[self::NO] ??= new self(self::NO);
64+
return self::$NO ??= (self::$registry[self::NO] ??= new self(self::NO));
6165
}
6266

6367
public static function createMaybe(): self
6468
{
65-
return self::$registry[self::MAYBE] ??= new self(self::MAYBE);
69+
return self::$MAYBE ??= (self::$registry[self::MAYBE] ??= new self(self::MAYBE));
6670
}
6771

6872
public static function createFromBoolean(bool $value): self
@@ -73,8 +77,7 @@ public static function createFromBoolean(bool $value): self
7377

7478
private static function create(int $value): self
7579
{
76-
self::$registry[$value] ??= new self($value);
77-
return self::$registry[$value];
80+
return self::$registry[$value] ??= new self($value);
7881
}
7982

8083
/**
@@ -113,17 +116,13 @@ public function toBooleanType(): BooleanType
113116
return new ConstantBooleanType($this->value === self::YES);
114117
}
115118

116-
public function and(self ...$operands): self
119+
public function and(?self $operand = null, self ...$rest): self
117120
{
118-
$min = $this->value;
119-
foreach ($operands as $operand) {
120-
if ($operand->value >= $min) {
121-
continue;
122-
}
123-
124-
$min = $operand->value;
121+
$min = $this->value & ($operand !== null ? $operand->value : self::YES);
122+
foreach ($rest as $operand) {
123+
$min &= $operand->value;
125124
}
126-
return self::create($min);
125+
return self::$registry[$min] ??= new self($min);
127126
}
128127

129128
/**
@@ -153,17 +152,13 @@ public function lazyAnd(
153152
return $this->and(...$results);
154153
}
155154

156-
public function or(self ...$operands): self
155+
public function or(?self $operand = null, self ...$rest): self
157156
{
158-
$max = $this->value;
159-
foreach ($operands as $operand) {
160-
if ($operand->value < $max) {
161-
continue;
162-
}
163-
164-
$max = $operand->value;
157+
$max = $this->value | ($operand !== null ? $operand->value : self::NO);
158+
foreach ($rest as $operand) {
159+
$max |= $operand->value;
165160
}
166-
return self::create($max);
161+
return self::$registry[$max] ??= new self($max);
167162
}
168163

169164
/**
@@ -247,7 +242,7 @@ public static function maxMin(self ...$operands): self
247242
throw new ShouldNotHappenException();
248243
}
249244
$operandValues = array_column($operands, 'value');
250-
return self::create(max($operandValues) > 0 ? 1 : min($operandValues));
245+
return self::create(max($operandValues) > self::MAYBE ? self::YES : min($operandValues));
251246
}
252247

253248
/**
@@ -275,7 +270,10 @@ public static function lazyMaxMin(
275270

276271
public function negate(): self
277272
{
278-
return self::create(-$this->value);
273+
// 0b11 >> 0 == 0b11 (3)
274+
// 0b11 >> 1 == 0b01 (1)
275+
// 0b11 >> 3 == 0b00 (0)
276+
return self::create(3 >> $this->value);
279277
}
280278

281279
public function equals(self $other): bool

0 commit comments

Comments
 (0)