1 | <?php |
||
2 | declare(strict_types = 1); |
||
3 | |||
4 | namespace Innmind\Immutable\Map; |
||
5 | |||
6 | use Innmind\Immutable\{ |
||
7 | Map, |
||
8 | Str, |
||
9 | Sequence, |
||
10 | Set, |
||
11 | Pair, |
||
12 | Maybe, |
||
13 | SideEffect, |
||
14 | }; |
||
15 | |||
16 | /** |
||
17 | * @template T |
||
18 | * @template S |
||
19 | * @psalm-immutable |
||
20 | */ |
||
21 | final class Primitive implements Implementation |
||
22 | { |
||
23 | /** @var array<T, S> */ |
||
24 | private array $values; |
||
25 | |||
26 | /** |
||
27 | * @param array<T, S> $values |
||
28 | */ |
||
29 | public function __construct(array $values = []) |
||
30 | { |
||
31 | $this->values = $values; |
||
32 | } |
||
33 | 76 | ||
34 | /** |
||
35 | 76 | * @param T $key |
|
0 ignored issues
–
show
|
|||
36 | * @param S $value |
||
0 ignored issues
–
show
The type
Innmind\Immutable\Map\S was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths ![]() |
|||
37 | 76 | * |
|
38 | 1 | * @return Implementation<T, S> |
|
39 | */ |
||
40 | public function __invoke($key, $value): Implementation |
||
41 | 75 | { |
|
42 | 75 | /** @psalm-suppress DocblockTypeContradiction */ |
|
43 | 75 | if (\is_string($key) && \is_numeric($key)) { |
|
0 ignored issues
–
show
|
|||
44 | 75 | // numeric-string keys are casted to ints by php, so when iterating |
|
45 | 75 | // over the array afterward the type is not conserved so we switch |
|
46 | 75 | // the implementation to DoubleIndex so keep the type |
|
47 | return (new DoubleIndex)->merge($this)($key, $value); |
||
48 | 23 | } |
|
49 | |||
50 | 23 | $values = $this->values; |
|
51 | $values[$key] = $value; |
||
52 | |||
53 | 20 | return new self($values); |
|
54 | } |
||
55 | 20 | ||
56 | /** |
||
57 | * @template A |
||
58 | 31 | * @template B |
|
59 | * |
||
60 | * @param A $key |
||
0 ignored issues
–
show
The type
Innmind\Immutable\Map\A was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths ![]() |
|||
61 | 31 | * @param B $value |
|
0 ignored issues
–
show
The type
Innmind\Immutable\Map\B was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths ![]() |
|||
62 | * |
||
63 | * @return Maybe<Implementation<A, B>> |
||
64 | */ |
||
65 | public static function of($key, $value): Maybe |
||
66 | { |
||
67 | 15 | /** @psalm-suppress DocblockTypeContradiction */ |
|
68 | if (\is_string($key) && \is_numeric($key)) { |
||
0 ignored issues
–
show
|
|||
69 | 15 | /** @var Maybe<Implementation<A, B>> */ |
|
70 | return Maybe::nothing(); |
||
71 | } |
||
72 | |||
73 | if (\is_string($key) || \is_int($key)) { |
||
0 ignored issues
–
show
|
|||
74 | /** @var self<A, B> */ |
||
75 | $self = new self; |
||
76 | |||
77 | return Maybe::just(($self)($key, $value)); |
||
78 | 62 | } |
|
79 | |||
80 | 62 | /** @var Maybe<Implementation<A, B>> */ |
|
81 | 61 | return Maybe::nothing(); |
|
82 | } |
||
83 | 60 | ||
84 | 60 | public function size(): int |
|
85 | 60 | { |
|
86 | /** @psalm-suppress MixedArgumentTypeCoercion */ |
||
87 | 60 | return \count($this->values); |
|
88 | } |
||
89 | |||
90 | public function count(): int |
||
91 | { |
||
92 | return $this->size(); |
||
93 | } |
||
94 | |||
95 | /** |
||
96 | * @param T $key |
||
97 | 34 | * |
|
98 | * @return Maybe<S> |
||
99 | 34 | */ |
|
100 | 2 | public function get($key): Maybe |
|
101 | { |
||
102 | if (!$this->contains($key)) { |
||
103 | 32 | return Maybe::nothing(); |
|
104 | } |
||
105 | |||
106 | return Maybe::just($this->values[$key]); |
||
107 | } |
||
108 | |||
109 | 39 | /** |
|
110 | * @param T $key |
||
111 | */ |
||
112 | 39 | public function contains($key): bool |
|
113 | { |
||
114 | /** @psalm-suppress MixedArgumentTypeCoercion */ |
||
115 | return \array_key_exists($key, $this->values); |
||
116 | } |
||
117 | |||
118 | 10 | /** |
|
119 | * @return self<T, S> |
||
120 | 10 | */ |
|
121 | 10 | public function clear(): self |
|
122 | 10 | { |
|
123 | return new self; |
||
124 | 10 | } |
|
125 | |||
126 | /** |
||
127 | * @param Implementation<T, S> $map |
||
128 | */ |
||
129 | public function equals(Implementation $map): bool |
||
130 | 7 | { |
|
131 | if (!$map->keys()->equals($this->keys())) { |
||
132 | 7 | return false; |
|
133 | 2 | } |
|
134 | |||
135 | foreach ($this->values as $k => $v) { |
||
136 | 7 | $equals = $map |
|
137 | 6 | ->get($k) |
|
138 | 2 | ->filter(static fn($value) => $value === $v) |
|
139 | ->match( |
||
140 | static fn() => true, |
||
141 | 6 | static fn() => false, |
|
142 | 3 | ); |
|
143 | |||
144 | if (!$equals) { |
||
145 | return false; |
||
146 | 6 | } |
|
147 | } |
||
148 | |||
149 | return true; |
||
150 | } |
||
151 | |||
152 | /** |
||
153 | * @param callable(T, S): bool $predicate |
||
154 | 2 | * |
|
155 | * @return self<T, S> |
||
156 | 2 | */ |
|
157 | public function filter(callable $predicate): self |
||
158 | 2 | { |
|
159 | 2 | /** @var array<T, S> */ |
|
160 | 2 | $values = []; |
|
161 | |||
162 | foreach ($this->values as $k => $v) { |
||
163 | if ($predicate($k, $v) === true) { |
||
164 | 2 | $values[$k] = $v; |
|
165 | } |
||
166 | } |
||
167 | |||
168 | return new self($values); |
||
169 | } |
||
170 | 3 | ||
171 | /** |
||
172 | 3 | * @param callable(T, S): void $function |
|
173 | 3 | */ |
|
174 | public function foreach(callable $function): SideEffect |
||
175 | 3 | { |
|
176 | foreach ($this->values as $k => $v) { |
||
177 | $function($k, $v); |
||
178 | } |
||
179 | |||
180 | return new SideEffect; |
||
181 | } |
||
182 | |||
183 | /** |
||
184 | * @template D |
||
185 | 4 | * |
|
186 | * @param callable(T, S): D $discriminator |
||
187 | 4 | * |
|
188 | 2 | * @return Map<D, Map<T, S>> |
|
189 | */ |
||
190 | public function groupBy(callable $discriminator): Map |
||
191 | 2 | { |
|
192 | /** @var Map<D, Map<T, S>> */ |
||
193 | 2 | $groups = Map::of(); |
|
194 | |||
195 | 2 | foreach ($this->values as $key => $value) { |
|
196 | $discriminant = $discriminator($key, $value); |
||
197 | 2 | ||
198 | 2 | $group = $groups->get($discriminant)->match( |
|
199 | static fn($group) => $group, |
||
200 | 2 | fn() => $this->clearMap(), |
|
201 | ); |
||
202 | 2 | $groups = ($groups)($discriminant, ($group)($key, $value)); |
|
203 | 2 | } |
|
204 | 2 | ||
205 | /** @var Map<D, Map<T, S>> */ |
||
206 | return $groups; |
||
207 | } |
||
208 | 2 | ||
209 | /** |
||
210 | 2 | * @return Set<T> |
|
211 | */ |
||
212 | 2 | public function keys(): Set |
|
213 | { |
||
214 | 2 | /** @psalm-suppress MixedArgumentTypeCoercion */ |
|
215 | $keys = \array_keys($this->values); |
||
216 | |||
217 | 2 | return Set::of(...$keys); |
|
218 | } |
||
219 | 2 | ||
220 | /** |
||
221 | * @return Sequence<S> |
||
222 | */ |
||
223 | public function values(): Sequence |
||
224 | 2 | { |
|
225 | /** @psalm-suppress MixedArgumentTypeCoercion */ |
||
226 | $values = \array_values($this->values); |
||
227 | |||
228 | return Sequence::of(...$values); |
||
229 | } |
||
230 | 14 | ||
231 | /** |
||
232 | * @template B |
||
233 | 14 | * |
|
234 | * @param callable(T, S): B $function |
||
235 | 14 | * |
|
236 | 14 | * @return self<T, B> |
|
237 | 14 | */ |
|
238 | public function map(callable $function): self |
||
239 | 14 | { |
|
240 | 14 | /** @var array<T, B> */ |
|
241 | 14 | $values = []; |
|
242 | |||
243 | foreach ($this->values as $k => $v) { |
||
244 | $values[$k] = $function($k, $v); |
||
245 | } |
||
246 | |||
247 | return new self($values); |
||
248 | } |
||
249 | 12 | ||
250 | /** |
||
251 | * @param T $key |
||
252 | 12 | * |
|
253 | * @return self<T, S> |
||
254 | 12 | */ |
|
255 | public function remove($key): self |
||
256 | { |
||
257 | if (!$this->contains($key)) { |
||
258 | return $this; |
||
259 | } |
||
260 | |||
261 | $values = $this->values; |
||
262 | 6 | /** @psalm-suppress MixedArrayTypeCoercion */ |
|
263 | unset($values[$key]); |
||
264 | 6 | ||
265 | return new self($values); |
||
266 | 6 | } |
|
267 | 6 | ||
268 | /** |
||
269 | 6 | * @param Implementation<T, S> $map |
|
270 | 4 | * |
|
271 | * @return Implementation<T, S> |
||
272 | */ |
||
273 | 2 | public function merge(Implementation $map): Implementation |
|
274 | { |
||
275 | 2 | return $map->reduce( |
|
276 | $this, |
||
277 | 4 | static fn(Implementation $carry, $key, $value): Implementation => ($carry)($key, $value), |
|
278 | 4 | ); |
|
279 | } |
||
280 | |||
281 | 4 | /** |
|
282 | * @param callable(T, S): bool $predicate |
||
283 | 2 | * |
|
284 | * @return Map<bool, Map<T, S>> |
||
285 | */ |
||
286 | 2 | public function partition(callable $predicate): Map |
|
287 | { |
||
288 | $truthy = $this->clearMap(); |
||
289 | $falsy = $this->clearMap(); |
||
290 | |||
291 | foreach ($this->values as $k => $v) { |
||
292 | $return = $predicate($k, $v); |
||
293 | |||
294 | 2 | if ($return === true) { |
|
295 | $truthy = ($truthy)($k, $v); |
||
296 | 2 | } else { |
|
297 | 2 | $falsy = ($falsy)($k, $v); |
|
298 | } |
||
299 | } |
||
300 | 2 | ||
301 | 2 | return Map::of([true, $truthy], [false, $falsy]); |
|
302 | } |
||
303 | 2 | ||
304 | /** |
||
305 | 2 | * @template R |
|
306 | * @param R $carry |
||
0 ignored issues
–
show
The type
Innmind\Immutable\Map\R was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths ![]() |
|||
307 | * @param callable(R, T, S): R $reducer |
||
308 | * |
||
309 | * @return R |
||
310 | */ |
||
311 | public function reduce($carry, callable $reducer) |
||
312 | { |
||
313 | 1 | foreach ($this->values as $k => $v) { |
|
314 | $carry = $reducer($carry, $k, $v); |
||
315 | } |
||
316 | 1 | ||
317 | 1 | return $carry; |
|
318 | } |
||
319 | 1 | ||
320 | 1 | public function empty(): bool |
|
321 | { |
||
322 | /** @psalm-suppress MixedArgumentTypeCoercion */ |
||
323 | 1 | \reset($this->values); |
|
324 | |||
325 | /** @psalm-suppress MixedArgumentTypeCoercion */ |
||
326 | return \is_null(\key($this->values)); |
||
327 | } |
||
328 | |||
329 | public function find(callable $predicate): Maybe |
||
330 | { |
||
331 | 2 | foreach ($this->values as $k => $v) { |
|
332 | if ($predicate($k, $v)) { |
||
333 | 2 | return Maybe::just(new Pair($k, $v)); |
|
334 | 2 | } |
|
335 | } |
||
336 | 2 | ||
337 | 2 | /** @var Maybe<Pair<T, S>> */ |
|
338 | return Maybe::nothing(); |
||
339 | 2 | } |
|
340 | 2 | ||
341 | /** |
||
342 | 2 | * @return Map<T, S> |
|
343 | */ |
||
344 | private function clearMap(): Map |
||
345 | { |
||
346 | return Map::of(); |
||
347 | } |
||
348 | } |
||
349 |
The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g.
excluded_paths: ["lib/*"]
, you can move it to the dependency path list as follows:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths