GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Push — master ( fd060d...258593 )
by Baptiste
03:01 queued 10s
created

ObjectKeys::equals()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 19
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 5.025

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 9
c 1
b 0
f 0
nc 5
nop 1
dl 0
loc 19
ccs 9
cts 10
cp 0.9
crap 5.025
rs 9.6111
1
<?php
2
declare(strict_types = 1);
3
4
namespace Innmind\Immutable\Map;
5
6
use Innmind\Immutable\{
7
    Map,
8
    Type,
9
    Str,
10
    Sequence,
11
    Set,
12
    Pair,
13
    ValidateArgument,
14
    ValidateArgument\ClassType,
15
    Exception\LogicException,
16
    Exception\ElementNotFound,
17
    Exception\CannotGroupEmptyStructure,
18
};
19
20
/**
21
 * @template T
22
 * @template S
23
 */
24
final class ObjectKeys implements Implementation
25
{
26
    private string $keyType;
27
    private string $valueType;
28
    private ValidateArgument $validateKey;
29
    private ValidateArgument $validateValue;
30
    private \SplObjectStorage $values;
31
32
    public function __construct(string $keyType, string $valueType)
33
    {
34
        $this->validateKey = Type::of($keyType);
35
36
        if (!$this->validateKey instanceof ClassType && $keyType !== 'object') {
37 70
            throw new LogicException;
38
        }
39 70
40
        $this->validateValue = Type::of($valueType);
41 70
        $this->keyType = $keyType;
42 2
        $this->valueType = $valueType;
43
        $this->values = new \SplObjectStorage;
44
    }
45 68
46 68
    public function keyType(): string
47 68
    {
48 68
        return $this->keyType;
49 68
    }
50
51
    public function valueType(): string
52
    {
53
        return $this->valueType;
54 20
    }
55
56 20
    public function size(): int
57
    {
58
        return $this->values->count();
59
    }
60
61
    /**
62 16
     * {@inheritdoc}
63
     */
64 16
    public function count(): int
65
    {
66
        return $this->size();
67
    }
68
69
    /**
70 16
     * @param T $key
71
     * @param S $value
72 16
     *
73
     * @return self<T, S>
74
     */
75
    public function __invoke($key, $value): Implementation
76
    {
77
        ($this->validateKey)($key, 1);
78
        ($this->validateValue)($value, 2);
79
80
        $map = clone $this;
81
        $map->values = clone $this->values;
82
        /** @psalm-suppress MixedArgumentTypeCoercion */
83
        $map->values[$key] = $value;
84
85
        return $map;
86 2
    }
87
88 2
    /**
89
     * @param T $key
90
     *
91
     * @throws ElementNotFound
92
     *
93
     * @return S
94 2
     */
95
    public function get($key)
96 2
    {
97
        if (!$this->contains($key)) {
98
            throw new ElementNotFound($key);
99
        }
100
101
        /**
102 2
         * @psalm-suppress MixedArgumentTypeCoercion
103
         * @var S
104 2
         */
105 2
        return $this->values->offsetGet($key);
106
    }
107
108
    /**
109
     * @param T $key
110 48
     */
111
    public function contains($key): bool
112 48
    {
113 48
        if (!\is_object($key)) {
114
            return false;
115
        }
116
117
        /** @psalm-suppress MixedArgumentTypeCoercion */
118 4
        return $this->values->offsetExists($key);
119
    }
120 4
121
    /**
122
     * @return self<T, S>
123
     */
124
    public function clear(): self
125
    {
126 28
        $map = clone $this;
127
        $map->values = new \SplObjectStorage;
128 28
129 2
        return $map;
130
    }
131
132 28
    /**
133
     * @param Implementation<T, S> $map
134
     */
135
    public function equals(Implementation $map): bool
136
    {
137
        if ($map->size() !== $this->size()) {
138 6
            return false;
139
        }
140 6
141
        foreach ($this->values as $k) {
142
            /** @var T $key */
143
            $key = $k;
144
            /** @var S $v */
145
            $v = $this->values[$k];
146 2
147
            if (!$map->contains($key)) {
148 2
                return false;
149
            }
150
151
            if ($map->get($key) !== $v) {
152
                return false;
153
            }
154 2
        }
155
156 2
        return true;
157
    }
158
159
    /**
160
     * @param callable(T, S): bool $predicate
161
     *
162 54
     * @return self<T, S>
163
     */
164 54
    public function filter(callable $predicate): self
165 54
    {
166
        $map = $this->clear();
167 48
168 48
        foreach ($this->values as $k) {
169 48
            /** @var T $key */
170 48
            $key = $k;
171
            /** @var S $v */
172 48
            $v = $this->values[$k];
173
174
            if ($predicate($key, $v) === true) {
175
                $map->values[$k] = $v;
176
            }
177
        }
178 22
179
        return $map;
180 22
    }
181 4
182
    /**
183
     * @param callable(T, S): void $function
184 18
     */
185
    public function foreach(callable $function): void
186
    {
187
        foreach ($this->values as $k) {
188
            /** @var T $key */
189
            $key = $k;
190 12
            /** @var S $v */
191
            $v = $this->values[$k];
192 12
193
            $function($key, $v);
194
        }
195
    }
196
197
    /**
198 14
     * @template D
199
     * @param callable(T, S): D $discriminator
200 14
     *
201 14
     * @throws CannotGroupEmptyStructure
202
     *
203 14
     * @return Map<D, Map<T, S>>
204
     */
205
    public function groupBy(callable $discriminator): Map
206
    {
207
        if ($this->empty()) {
208
            throw new CannotGroupEmptyStructure;
209 6
        }
210
211 6
        $groups = null;
212 2
213
        foreach ($this->values as $k) {
214
            /** @var T $key */
215 6
            $key = $k;
216 6
            /** @var S $v */
217
            $v = $this->values[$k];
218 6
219
            $discriminant = $discriminator($key, $v);
220
221
            if ($groups === null) {
222 6
                /** @var Map<D, Map<T, S>> */
223 6
                $groups = Map::of(
224
                    Type::determine($discriminant),
225
                    Map::class,
226
                );
227 2
            }
228
229
            if ($groups->contains($discriminant)) {
230
                /** @var Map<T, S> */
231
                $group = $groups->get($discriminant);
232
                /** @var Map<T, S> */
233 2
                $group = ($group)($key, $v);
234
235 2
                $groups = ($groups)($discriminant, $group);
236
            } else {
237 2
                /** @var Map<T, S> */
238 2
                $group = $this->clearMap()($key, $v);
239
240 2
                $groups = ($groups)($discriminant, $group);
241 2
            }
242
        }
243
244
        /** @var Map<D, Map<T, S>> */
245 2
        return $groups;
246
    }
247 2
248
    /**
249
     * @return Set<T>
250
     */
251
    public function keys(): Set
252
    {
253 2
        return $this->reduce(
254
            Set::of($this->keyType),
255 2
            static fn(Set $keys, $key): Set => ($keys)($key),
0 ignored issues
show
Bug introduced by
A parse error occurred: Syntax error, unexpected T_FN, expecting T_PAAMAYIM_NEKUDOTAYIM on line 255 at column 19
Loading history...
256 2
        );
257
    }
258 2
259
    /**
260
     * @return Sequence<S>
261 2
     */
262
    public function values(): Sequence
263
    {
264
        return $this->reduce(
265
            Sequence::of($this->valueType),
266
            static fn(Sequence $values, $key, $value): Sequence => ($values)($value),
267 4
        );
268
    }
269 4
270 2
    /**
271
     * @param callable(T, S): (S|Pair<T, S>) $function
272
     *
273 2
     * @return self<T, S>
274
     */
275 2
    public function map(callable $function): self
276 2
    {
277
        $map = $this->clear();
278 2
279
        foreach ($this->values as $k) {
280 2
            /** @var T */
281 2
            $key = $k;
282 2
            /** @var S */
283 2
            $v = $this->values[$k];
284
285
            $return = $function($key, $v);
286
287 2
            if ($return instanceof Pair) {
288 2
                ($this->validateKey)($return->key(), 1);
289 2
290 2
                /** @var object */
291
                $key = $return->key();
292
                /** @var S */
293 2
                $value = $return->value();
294 2
            } else {
295 2
                $key = $k;
296
                $value = $return;
297
            }
298
299
            ($this->validateValue)($value, 2);
300 2
301
            $map->values[$key] = $value;
302
        }
303
304
        return $map;
305
    }
306 14
307
    /**
308 14
     * @param T $key
309 14
     *
310
     * @return self<T, S>
311 14
     */
312 14
    public function remove($key): self
313
    {
314
        if (!$this->contains($key)) {
315
            return $this;
316
        }
317
318
        $map = clone $this;
319 16
        $map->values = clone $this->values;
320
        /** @psalm-suppress MixedArgumentTypeCoercion */
321 16
        $map->values->detach($key);
322 16
        $map->values->rewind();
323
324 16
        return $map;
325 16
    }
326
327
    /**
328
     * @param Implementation<T, S> $map
329
     *
330
     * @return self<T, S>
331
     */
332 6
    public function merge(Implementation $map): self
333
    {
334 6
        return $map->reduce(
335
            $this,
336 6
            static fn(self $carry, $key, $value): self => ($carry)($key, $value),
337 6
        );
338
    }
339 6
340
    /**
341 6
     * @param callable(T, S): bool $predicate
342 4
     *
343
     * @return Map<bool, Map<T, S>>
344 2
     */
345 2
    public function partition(callable $predicate): Map
346
    {
347 4
        $truthy = $this->clearMap();
348 4
        $falsy = $this->clearMap();
349
350
        foreach ($this->values as $k) {
351 4
            /** @var T $key */
352
            $key = $k;
353 2
            /** @var S $v */
354
            $v = $this->values[$k];
355
356 2
            $return = $predicate($key, $v);
357
358 2
            if ($return === true) {
359
                $truthy = ($truthy)($key, $v);
360
            } else {
361
                $falsy = ($falsy)($key, $v);
362
            }
363
        }
364 2
365
        /**
366 2
         * @psalm-suppress InvalidScalarArgument
367
         * @psalm-suppress InvalidArgument
368
         * @var Map<bool, Map<T, S>>
369
         */
370
        return Map::of('bool', Map::class)
371
            (true, $truthy)
372 2
            (false, $falsy);
373
    }
374 2
375 2
    /**
376
     * @template R
377
     * @param R $carry
378 2
     * @param callable(R, T, S): R $reducer
379 2
     *
380 2
     * @return R
381 2
     */
382
    public function reduce($carry, callable $reducer)
383 2
    {
384
        foreach ($this->values as $k) {
385
            /** @var T $key */
386
            $key = $k;
387
            /** @var S $v */
388
            $v = $this->values[$k];
389 6
390
            $carry = $reducer($carry, $key, $v);
391
        }
392 6
393 6
        return $carry;
394
    }
395 2
396 2
    public function empty(): bool
397
    {
398
        $this->values->rewind();
399
400 4
        return !$this->values->valid();
401 4
    }
402
403 4
    /**
404 4
     * @template ST
405
     *
406
     * @param callable(T, S): \Generator<ST> $mapper
407
     *
408
     * @return Sequence<ST>
409
     */
410
    public function toSequenceOf(string $type, callable $mapper): Sequence
411 2
    {
412
        /** @var Sequence<ST> */
413 2
        $sequence = Sequence::of($type);
414 2
415
        foreach ($this->values as $k) {
416 2
            /** @var T $key */
417 2
            $key = $k;
418
            /** @var S $v */
419 2
            $v = $this->values[$k];
420
421 2
            foreach ($mapper($key, $v) as $newValue) {
422 2
                $sequence = ($sequence)($newValue);
423
            }
424 2
        }
425
426
        return $sequence;
427
    }
428 2
429 2
    /**
430
     * @template ST
431 2
     *
432 2
     * @param callable(T, S): \Generator<ST> $mapper
433 2
     *
434
     * @return Set<ST>
435
     */
436
    public function toSetOf(string $type, callable $mapper): Set
437
    {
438
        /** @var Set<ST> */
439 18
        $set = Set::of($type);
440
441 18
        foreach ($this->values as $k) {
442 18
            /** @var T $key */
443
            $key = $k;
444 18
            /** @var S $v */
445
            $v = $this->values[$k];
446
447 18
            foreach ($mapper($key, $v) as $newValue) {
448
                $set = ($set)($newValue);
449
            }
450 2
        }
451
452 2
        return $set;
453
    }
454 2
455
    /**
456
     * @template MT
457
     * @template MS
458
     *
459
     * @param null|callable(T, S): \Generator<MT, MS> $mapper
460
     *
461
     * @return Map<MT, MS>
462
     */
463
    public function toMapOf(string $key, string $value, callable $mapper = null): Map
464
    {
465
        /** @psalm-suppress MissingParamType */
466
        $mapper ??= static fn($k, $v): \Generator => yield $k => $v;
467
468
        /** @var Map<MT, MS> */
469
        $map = Map::of($key, $value);
470
471
        foreach ($this->values as $k) {
472
            /** @var T $key */
473
            $key = $k;
474
            /** @var S $v */
475
            $v = $this->values[$k];
476
477
            foreach ($mapper($key, $v) as $newKey => $newValue) {
478
                $map = ($map)($newKey, $newValue);
479
            }
480
        }
481
482
        return $map;
483
    }
484
485
    /**
486
     * @return Map<T, S>
487
     */
488
    private function clearMap(): Map
489
    {
490
        return Map::of($this->keyType, $this->valueType);
491
    }
492
}
493