xref: /plugin/combo/vendor/antlr/antlr4-php-runtime/src/Utils/Set.php (revision 37748cd8654635afbeca80942126742f0f4cc346)
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