1*37748cd8SNickeau<?php 2*37748cd8SNickeau 3*37748cd8SNickeaudeclare(strict_types=1); 4*37748cd8SNickeau 5*37748cd8SNickeaunamespace Antlr\Antlr4\Runtime\Utils; 6*37748cd8SNickeau 7*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Comparison\DefaultEquivalence; 8*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Comparison\Equatable; 9*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Comparison\Equivalence; 10*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Comparison\Hashable; 11*37748cd8SNickeau 12*37748cd8SNickeaufinal class Set implements Equatable, \IteratorAggregate, \Countable 13*37748cd8SNickeau{ 14*37748cd8SNickeau /** @var array<int, array<mixed>> */ 15*37748cd8SNickeau private $table = []; 16*37748cd8SNickeau 17*37748cd8SNickeau /** @var int */ 18*37748cd8SNickeau private $size = 0; 19*37748cd8SNickeau 20*37748cd8SNickeau /** @var DefaultEquivalence|Equivalence */ 21*37748cd8SNickeau private $equivalence; 22*37748cd8SNickeau 23*37748cd8SNickeau public function __construct(?Equivalence $equivalence = null) 24*37748cd8SNickeau { 25*37748cd8SNickeau $this->equivalence = $equivalence ?? new DefaultEquivalence(); 26*37748cd8SNickeau } 27*37748cd8SNickeau 28*37748cd8SNickeau public function isEmpty() : bool 29*37748cd8SNickeau { 30*37748cd8SNickeau return $this->count() === 0; 31*37748cd8SNickeau } 32*37748cd8SNickeau 33*37748cd8SNickeau public function count() : int 34*37748cd8SNickeau { 35*37748cd8SNickeau return $this->size; 36*37748cd8SNickeau } 37*37748cd8SNickeau 38*37748cd8SNickeau public function contains($value) : bool 39*37748cd8SNickeau { 40*37748cd8SNickeau if (!$value instanceof Hashable) { 41*37748cd8SNickeau return false; 42*37748cd8SNickeau } 43*37748cd8SNickeau 44*37748cd8SNickeau $hash = $this->equivalence->hash($value); 45*37748cd8SNickeau 46*37748cd8SNickeau if (!isset($this->table[$hash])) { 47*37748cd8SNickeau return false; 48*37748cd8SNickeau } 49*37748cd8SNickeau 50*37748cd8SNickeau foreach ($this->table[$hash] as $entry) { 51*37748cd8SNickeau if ($this->equivalence->equivalent($value, $entry)) { 52*37748cd8SNickeau return true; 53*37748cd8SNickeau } 54*37748cd8SNickeau } 55*37748cd8SNickeau 56*37748cd8SNickeau return false; 57*37748cd8SNickeau } 58*37748cd8SNickeau 59*37748cd8SNickeau public function getOrAdd(Hashable $value) : Hashable 60*37748cd8SNickeau { 61*37748cd8SNickeau $hash = $this->equivalence->hash($value); 62*37748cd8SNickeau 63*37748cd8SNickeau if (!isset($this->table[$hash])) { 64*37748cd8SNickeau $this->table[$hash] = []; 65*37748cd8SNickeau } 66*37748cd8SNickeau 67*37748cd8SNickeau foreach ($this->table[$hash] as $index => $entry) { 68*37748cd8SNickeau if ($this->equivalence->equivalent($value, $entry)) { 69*37748cd8SNickeau return $entry; 70*37748cd8SNickeau } 71*37748cd8SNickeau } 72*37748cd8SNickeau 73*37748cd8SNickeau $this->table[$hash][] = $value; 74*37748cd8SNickeau 75*37748cd8SNickeau $this->size++; 76*37748cd8SNickeau 77*37748cd8SNickeau return $value; 78*37748cd8SNickeau } 79*37748cd8SNickeau 80*37748cd8SNickeau public function get(Hashable $value) : ?Hashable 81*37748cd8SNickeau { 82*37748cd8SNickeau $hash = $this->equivalence->hash($value); 83*37748cd8SNickeau 84*37748cd8SNickeau if (!isset($this->table[$hash])) { 85*37748cd8SNickeau return null; 86*37748cd8SNickeau } 87*37748cd8SNickeau 88*37748cd8SNickeau foreach ($this->table[$hash] as $index => $entry) { 89*37748cd8SNickeau if ($this->equivalence->equivalent($value, $entry)) { 90*37748cd8SNickeau return $entry; 91*37748cd8SNickeau } 92*37748cd8SNickeau } 93*37748cd8SNickeau 94*37748cd8SNickeau return null; 95*37748cd8SNickeau } 96*37748cd8SNickeau 97*37748cd8SNickeau /** 98*37748cd8SNickeau * @param iterable<Hashable> $values 99*37748cd8SNickeau */ 100*37748cd8SNickeau public function addAll(iterable $values) : void 101*37748cd8SNickeau { 102*37748cd8SNickeau foreach ($values as $value) { 103*37748cd8SNickeau $this->add($value); 104*37748cd8SNickeau } 105*37748cd8SNickeau } 106*37748cd8SNickeau 107*37748cd8SNickeau public function add(Hashable $value) : bool 108*37748cd8SNickeau { 109*37748cd8SNickeau $hash = $this->equivalence->hash($value); 110*37748cd8SNickeau 111*37748cd8SNickeau if (!isset($this->table[$hash])) { 112*37748cd8SNickeau $this->table[$hash] = []; 113*37748cd8SNickeau } 114*37748cd8SNickeau 115*37748cd8SNickeau foreach ($this->table[$hash] as $index => $entry) { 116*37748cd8SNickeau if ($this->equivalence->equivalent($value, $entry)) { 117*37748cd8SNickeau return false; 118*37748cd8SNickeau } 119*37748cd8SNickeau } 120*37748cd8SNickeau 121*37748cd8SNickeau $this->table[$hash][] = $value; 122*37748cd8SNickeau 123*37748cd8SNickeau $this->size++; 124*37748cd8SNickeau 125*37748cd8SNickeau return true; 126*37748cd8SNickeau } 127*37748cd8SNickeau 128*37748cd8SNickeau public function remove(Hashable $value) : void 129*37748cd8SNickeau { 130*37748cd8SNickeau $hash = $this->equivalence->hash($value); 131*37748cd8SNickeau 132*37748cd8SNickeau if (!isset($this->table[$hash])) { 133*37748cd8SNickeau return; 134*37748cd8SNickeau } 135*37748cd8SNickeau 136*37748cd8SNickeau foreach ($this->table[$hash] as $index => $entry) { 137*37748cd8SNickeau if ($this->equivalence->equivalent($value, $entry)) { 138*37748cd8SNickeau continue; 139*37748cd8SNickeau } 140*37748cd8SNickeau 141*37748cd8SNickeau unset($this->table[$hash][$index]); 142*37748cd8SNickeau 143*37748cd8SNickeau if (\count($this->table[$hash]) === 0) { 144*37748cd8SNickeau unset($this->table[$hash]); 145*37748cd8SNickeau } 146*37748cd8SNickeau 147*37748cd8SNickeau $this->size--; 148*37748cd8SNickeau 149*37748cd8SNickeau return; 150*37748cd8SNickeau } 151*37748cd8SNickeau } 152*37748cd8SNickeau 153*37748cd8SNickeau public function equals(object $other) : bool 154*37748cd8SNickeau { 155*37748cd8SNickeau if ($this === $other) { 156*37748cd8SNickeau return true; 157*37748cd8SNickeau } 158*37748cd8SNickeau 159*37748cd8SNickeau if (!$other instanceof self 160*37748cd8SNickeau || $this->size !== $other->size 161*37748cd8SNickeau || !$this->equivalence->equals($other)) { 162*37748cd8SNickeau return false; 163*37748cd8SNickeau } 164*37748cd8SNickeau 165*37748cd8SNickeau foreach ($this->table as $hash => $bucket) { 166*37748cd8SNickeau if (!isset($other->table[$hash]) || \count($bucket) !== \count($other->table[$hash])) { 167*37748cd8SNickeau return false; 168*37748cd8SNickeau } 169*37748cd8SNickeau 170*37748cd8SNickeau $otherBucket = $other->table[$hash]; 171*37748cd8SNickeau 172*37748cd8SNickeau foreach ($bucket as $index => $value) { 173*37748cd8SNickeau if (!$value->equals($otherBucket[$index])) { 174*37748cd8SNickeau return false; 175*37748cd8SNickeau } 176*37748cd8SNickeau } 177*37748cd8SNickeau } 178*37748cd8SNickeau 179*37748cd8SNickeau return true; 180*37748cd8SNickeau } 181*37748cd8SNickeau 182*37748cd8SNickeau /** 183*37748cd8SNickeau * @return array<mixed> 184*37748cd8SNickeau */ 185*37748cd8SNickeau public function getValues() : array 186*37748cd8SNickeau { 187*37748cd8SNickeau $values = []; 188*37748cd8SNickeau foreach ($this->table as $bucket) { 189*37748cd8SNickeau foreach ($bucket as $value) { 190*37748cd8SNickeau $values[] = $value; 191*37748cd8SNickeau } 192*37748cd8SNickeau } 193*37748cd8SNickeau 194*37748cd8SNickeau return $values; 195*37748cd8SNickeau } 196*37748cd8SNickeau 197*37748cd8SNickeau public function getIterator() : \Iterator 198*37748cd8SNickeau { 199*37748cd8SNickeau foreach ($this->table as $bucket) { 200*37748cd8SNickeau foreach ($bucket as $value) { 201*37748cd8SNickeau yield $value; 202*37748cd8SNickeau } 203*37748cd8SNickeau } 204*37748cd8SNickeau } 205*37748cd8SNickeau} 206