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

DoubleIndex::put()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 22
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 2

Importance

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