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.
Completed
Push — develop ( 7ab88f...fff013 )
by Baptiste
07:46
created

src/Map/DoubleIndex.php (15 issues)

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
    Exception\LogicException,
15
    Exception\ElementNotFound,
16
    Exception\CannotGroupEmptyStructure,
17
};
18
use function Innmind\Immutable\unwrap;
19
20
/**
21
 * @template T
22
 * @template S
23
 */
24
final class DoubleIndex implements Implementation
25
{
26
    private string $keyType;
27
    private string $valueType;
28
    private ValidateArgument $validateKey;
29
    private ValidateArgument $validateValue;
30
    /** @var Sequence<T> */
31
    private Sequence $keys;
32
    /** @var Sequence<S> */
33
    private Sequence $values;
34
    /** @var Sequence<Pair<T, S>> */
35
    private Sequence $pairs;
36
37 78
    public function __construct(string $keyType, string $valueType)
38
    {
39 78
        $this->validateKey = Type::of($keyType);
40 78
        $this->validateValue = Type::of($valueType);
41 78
        $this->keyType = $keyType;
42 78
        $this->valueType = $valueType;
43 78
        $this->keys = Sequence::of($keyType);
44 78
        $this->values = Sequence::of($valueType);
45
        /** @var Sequence<Pair<T, S>> */
46 78
        $this->pairs = Sequence::of(Pair::class);
0 ignored issues
show
The property pairs does not seem to exist on Innmind\Immutable\Sequence.
Loading history...
47 78
    }
48
49 16
    public function keyType(): string
50
    {
51 16
        return $this->keyType;
52
    }
53
54 16
    public function valueType(): string
55
    {
56 16
        return $this->valueType;
57
    }
58
59 4
    public function size(): int
60
    {
61 4
        return $this->keys->size();
62
    }
63
64 4
    public function count(): int
65
    {
66 4
        return $this->keys->count();
67
    }
68
69
    /**
70
     * @param T $key
71
     * @param S $value
72
     *
73
     * @return self<T, S>
74
     */
75 33
    public function put($key, $value): self
76
    {
77 33
        ($this->validateKey)($key, 1);
78 32
        ($this->validateValue)($value, 2);
79
80 31
        $map = clone $this;
81
82 31
        if ($this->keys->contains($key)) {
83 3
            $index = $this->keys->indexOf($key);
84 3
            $map->values = $this->values->take($index)
85 3
                ->add($value)
86 3
                ->append($this->values->drop($index + 1));
87
            /** @var Sequence<Pair<T, S>> */
88 3
            $map->pairs = $this->pairs->take($index)
0 ignored issues
show
The property pairs does not seem to exist on Innmind\Immutable\Sequence.
Loading history...
89 3
                ->add(new Pair($key, $value))
90 3
                ->append($this->pairs->drop($index + 1));
91
        } else {
92
            /** @var Sequence<T> */
93 31
            $map->keys = ($this->keys)($key);
0 ignored issues
show
The property keys does not seem to exist on Innmind\Immutable\Sequence.
Loading history...
94 31
            $map->values = ($this->values)($value);
95
            /** @var Sequence<Pair<T, S>> */
96 31
            $map->pairs = ($this->pairs)(new Pair($key, $value));
97
        }
98
99 31
        return $map;
100
    }
101
102
    /**
103
     * @param T $key
104
     *
105
     * @throws ElementNotFound
106
     *
107
     * @return S
108
     */
109 16
    public function get($key)
110
    {
111 16
        if (!$this->keys->contains($key)) {
112 1
            throw new ElementNotFound($key);
113
        }
114
115 15
        return $this->values->get(
116 15
            $this->keys->indexOf($key)
117
        );
118
    }
119
120
    /**
121
     * @param T $key
122
     */
123 3
    public function contains($key): bool
124
    {
125 3
        return $this->keys->contains($key);
126
    }
127
128
    /**
129
     * @return self<T, S>
130
     */
131 5
    public function clear(): self
132
    {
133 5
        $map = clone $this;
134 5
        $map->keys = $this->keys->clear();
135 5
        $map->values = $this->values->clear();
136 5
        $map->pairs = $this->pairs->clear();
137
138 5
        return $map;
139
    }
140
141
    /**
142
     * @param Implementation<T, S> $map
143
     */
144 2
    public function equals(Implementation $map): bool
145
    {
146 2
        if (!$map->keys()->equals($this->keys())) {
147 1
            return false;
148
        }
149
150 2
        foreach (unwrap($this->pairs) as $pair) {
0 ignored issues
show
$this->pairs of type Innmind\Immutable\Sequence is incompatible with the type Innmind\Immutable\Set expected by parameter $structure of Innmind\Immutable\unwrap(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

150
        foreach (unwrap(/** @scrutinizer ignore-type */ $this->pairs) as $pair) {
Loading history...
151 2
            if ($map->get($pair->key()) !== $pair->value()) {
152 2
                return false;
153
            }
154
        }
155
156 1
        return true;
157
    }
158
159
    /**
160
     * @param callable(T, S): bool $predicate
161
     *
162
     * @return self<T, S>
163
     */
164 1
    public function filter(callable $predicate): self
165
    {
166 1
        $map = $this->clear();
167
168 1
        foreach (unwrap($this->pairs) as $pair) {
0 ignored issues
show
$this->pairs of type Innmind\Immutable\Sequence is incompatible with the type Innmind\Immutable\Set expected by parameter $structure of Innmind\Immutable\unwrap(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

168
        foreach (unwrap(/** @scrutinizer ignore-type */ $this->pairs) as $pair) {
Loading history...
169 1
            if ($predicate($pair->key(), $pair->value()) === true) {
170
                /** @psalm-suppress MixedArgumentTypeCoercion */
171 1
                $map->keys = ($map->keys)($pair->key());
172
                /** @psalm-suppress MixedArgumentTypeCoercion */
173 1
                $map->values = ($map->values)($pair->value());
174
                /**
175
                 * @psalm-suppress MixedArgumentTypeCoercion
176
                 * @var Sequence<Pair<T, S>>
177
                 */
178 1
                $map->pairs = ($map->pairs)($pair);
179
            }
180
        }
181
182 1
        return $map;
183
    }
184
185
    /**
186
     * @param callable(T, S): void $function
187
     */
188 1
    public function foreach(callable $function): void
189
    {
190 1
        foreach (unwrap($this->pairs) as $pair) {
0 ignored issues
show
$this->pairs of type Innmind\Immutable\Sequence is incompatible with the type Innmind\Immutable\Set expected by parameter $structure of Innmind\Immutable\unwrap(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

190
        foreach (unwrap(/** @scrutinizer ignore-type */ $this->pairs) as $pair) {
Loading history...
191 1
            $function($pair->key(), $pair->value());
192
        }
193 1
    }
194
195
    /**
196
     * @template D
197
     * @param callable(T, S): D $discriminator
198
     *
199
     * @throws CannotGroupEmptyStructure
200
     *
201
     * @return Map<D, Map<T, S>>
202
     */
203 2
    public function groupBy(callable $discriminator): Map
204
    {
205 2
        if ($this->empty()) {
206 1
            throw new CannotGroupEmptyStructure;
207
        }
208
209 1
        $groups = null;
210
211 1
        foreach (unwrap($this->pairs) as $pair) {
0 ignored issues
show
$this->pairs of type Innmind\Immutable\Sequence is incompatible with the type Innmind\Immutable\Set expected by parameter $structure of Innmind\Immutable\unwrap(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

211
        foreach (unwrap(/** @scrutinizer ignore-type */ $this->pairs) as $pair) {
Loading history...
212 1
            $key = $discriminator($pair->key(), $pair->value());
213
214 1
            if ($groups === null) {
215
                /** @var Map<D, Map<T, S>> */
216 1
                $groups = Map::of(
217 1
                    Type::determine($key),
218 1
                    Map::class,
219
                );
220
            }
221
222 1
            if ($groups->contains($key)) {
223
                /** @var Map<T, S> */
224 1
                $group = $groups->get($key);
225
                /** @var Map<T, S> */
226 1
                $group = ($group)($pair->key(), $pair->value());
227
228 1
                $groups = ($groups)($key, $group);
229
            } else {
230
                /** @var Map<T, S> */
231 1
                $group = $this->clearMap()($pair->key(), $pair->value());
232
233 1
                $groups = ($groups)($key, $group);
234
            }
235
        }
236
237
        /** @var Map<D, Map<T, S>> */
238 1
        return $groups;
239
    }
240
241
    /**
242
     * @return Set<T>
243
     */
244 10
    public function keys(): Set
245
    {
246 10
        return Set::of($this->keyType, ...unwrap($this->keys));
0 ignored issues
show
$this->keys of type Innmind\Immutable\Sequence is incompatible with the type Innmind\Immutable\Set expected by parameter $structure of Innmind\Immutable\unwrap(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

246
        return Set::of($this->keyType, ...unwrap(/** @scrutinizer ignore-type */ $this->keys));
Loading history...
247
    }
248
249
    /**
250
     * @return Sequence<S>
251
     */
252 5
    public function values(): Sequence
253
    {
254 5
        return $this->values;
255
    }
256
257
    /**
258
     * @param callable(T, S): (S|Pair<T, S>) $function
259
     *
260
     * @return self<T, S>
261
     */
262 3
    public function map(callable $function): self
263
    {
264 3
        $map = $this->clear();
265
266 3
        foreach (unwrap($this->pairs) as $pair) {
0 ignored issues
show
$this->pairs of type Innmind\Immutable\Sequence is incompatible with the type Innmind\Immutable\Set expected by parameter $structure of Innmind\Immutable\unwrap(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

266
        foreach (unwrap(/** @scrutinizer ignore-type */ $this->pairs) as $pair) {
Loading history...
267 3
            $return = $function($pair->key(), $pair->value());
268
269 3
            if ($return instanceof Pair) {
270
                /** @var T */
271 2
                $key = $return->key();
272
                /** @var S */
273 2
                $value = $return->value();
274
            } else {
275 2
                $key = $pair->key();
276 2
                $value = $return;
277
            }
278
279 3
            $map = $map->put($key, $value);
280
        }
281
282 1
        return $map;
283
    }
284
285
    /**
286
     * @param T $key
287
     *
288
     * @return self<T, S>
289
     */
290 1
    public function remove($key): Implementation
291
    {
292 1
        if (!$this->contains($key)) {
293 1
            return $this;
294
        }
295
296 1
        $index = $this->keys->indexOf($key);
297 1
        $map = clone $this;
298 1
        $map->keys = $this
299 1
            ->keys
300 1
            ->slice(0, $index)
301 1
            ->append($this->keys->slice($index + 1, $this->keys->size()));
302 1
        $map->values = $this
303 1
            ->values
304 1
            ->slice(0, $index)
305 1
            ->append($this->values->slice($index + 1, $this->values->size()));
306
        /** @var Sequence<Pair<T, S>> */
307 1
        $map->pairs = $this
0 ignored issues
show
The property pairs does not seem to exist on Innmind\Immutable\Sequence.
Loading history...
308 1
            ->pairs
309 1
            ->slice(0, $index)
310 1
            ->append($this->pairs->slice($index + 1, $this->pairs->size()));
311
312 1
        return $map;
313
    }
314
315
    /**
316
     * @param Implementation<T, S> $map
317
     *
318
     * @return self<T, S>
319
     */
320 1
    public function merge(Implementation $map): self
321
    {
322 1
        return $map->reduce(
323 1
            $this,
324
            function(self $carry, $key, $value): self {
325 1
                return $carry->put($key, $value);
326 1
            }
327
        );
328
    }
329
330
    /**
331
     * @param callable(T, S): bool $predicate
332
     *
333
     * @return Map<bool, Map<T, S>>
334
     */
335 1
    public function partition(callable $predicate): Map
336
    {
337 1
        $truthy = $this->clearMap();
338 1
        $falsy = $this->clearMap();
339
340 1
        foreach (unwrap($this->pairs) as $pair) {
0 ignored issues
show
$this->pairs of type Innmind\Immutable\Sequence is incompatible with the type Innmind\Immutable\Set expected by parameter $structure of Innmind\Immutable\unwrap(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

340
        foreach (unwrap(/** @scrutinizer ignore-type */ $this->pairs) as $pair) {
Loading history...
341 1
            $return = $predicate($pair->key(), $pair->value());
342
343 1
            if ($return === true) {
344 1
                $truthy = ($truthy)($pair->key(), $pair->value());
345
            } else {
346 1
                $falsy = ($falsy)($pair->key(), $pair->value());
347
            }
348
        }
349
350
        /**
351
         * @psalm-suppress InvalidScalarArgument
352
         * @psalm-suppress InvalidArgument
353
         */
354 1
        return Map::of('bool', Map::class)
355 1
            (true, $truthy)
356 1
            (false, $falsy);
357
    }
358
359
    /**
360
     * @template R
361
     * @param R $carry
362
     * @param callable(R, T, S): R $reducer
363
     *
364
     * @return R
365
     */
366 2
    public function reduce($carry, callable $reducer)
367
    {
368 2
        foreach (unwrap($this->pairs) as $pair) {
0 ignored issues
show
$this->pairs of type Innmind\Immutable\Sequence is incompatible with the type Innmind\Immutable\Set expected by parameter $structure of Innmind\Immutable\unwrap(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

368
        foreach (unwrap(/** @scrutinizer ignore-type */ $this->pairs) as $pair) {
Loading history...
369 2
            $carry = $reducer($carry, $pair->key(), $pair->value());
370
        }
371
372 2
        return $carry;
373
    }
374
375 3
    public function empty(): bool
376
    {
377 3
        return $this->pairs->empty();
378
    }
379
380
    /**
381
     * @template ST
382
     *
383
     * @param callable(T, S): \Generator<ST> $mapper
384
     *
385
     * @return Sequence<ST>
386
     */
387 1
    public function toSequenceOf(string $type, callable $mapper): Sequence
388
    {
389
        /** @var Sequence<ST> */
390 1
        $sequence = Sequence::of($type);
391
392 1
        foreach (unwrap($this->pairs) as $pair) {
0 ignored issues
show
$this->pairs of type Innmind\Immutable\Sequence is incompatible with the type Innmind\Immutable\Set expected by parameter $structure of Innmind\Immutable\unwrap(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

392
        foreach (unwrap(/** @scrutinizer ignore-type */ $this->pairs) as $pair) {
Loading history...
393 1
            foreach ($mapper($pair->key(), $pair->value()) as $newValue) {
394 1
                $sequence = ($sequence)($newValue);
395
            }
396
        }
397
398 1
        return $sequence;
399
    }
400
401
    /**
402
     * @template ST
403
     *
404
     * @param callable(T, S): \Generator<ST> $mapper
405
     *
406
     * @return Set<ST>
407
     */
408 1
    public function toSetOf(string $type, callable $mapper): Set
409
    {
410
        /** @var Set<ST> */
411 1
        $set = Set::of($type);
412
413 1
        foreach (unwrap($this->pairs) as $pair) {
0 ignored issues
show
$this->pairs of type Innmind\Immutable\Sequence is incompatible with the type Innmind\Immutable\Set expected by parameter $structure of Innmind\Immutable\unwrap(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

413
        foreach (unwrap(/** @scrutinizer ignore-type */ $this->pairs) as $pair) {
Loading history...
414 1
            foreach ($mapper($pair->key(), $pair->value()) as $newValue) {
415 1
                $set = ($set)($newValue);
416
            }
417
        }
418
419 1
        return $set;
420
    }
421
422
    /**
423
     * @template MT
424
     * @template MS
425
     *
426
     * @param callable(T, S): \Generator<MT, MS> $mapper
427
     *
428
     * @return Map<MT, MS>
429
     */
430 1
    public function toMapOf(string $key, string $value, callable $mapper): Map
431
    {
432
        /** @var Map<MT, MS> */
433 1
        $map = Map::of($key, $value);
434
435 1
        foreach (unwrap($this->pairs) as $pair) {
0 ignored issues
show
$this->pairs of type Innmind\Immutable\Sequence is incompatible with the type Innmind\Immutable\Set expected by parameter $structure of Innmind\Immutable\unwrap(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

435
        foreach (unwrap(/** @scrutinizer ignore-type */ $this->pairs) as $pair) {
Loading history...
436 1
            foreach ($mapper($pair->key(), $pair->value()) as $newKey => $newValue) {
437 1
                $map = ($map)($newKey, $newValue);
438
            }
439
        }
440
441 1
        return $map;
442
    }
443
444
    /**
445
     * @return Map<T, S>
446
     */
447 2
    private function clearMap(): Map
448
    {
449 2
        return Map::of($this->keyType, $this->valueType);
450
    }
451
}
452