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 ( fff013...7af216 )
by Baptiste
05:28
created

src/Map/DoubleIndex.php (1 issue)

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