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

Primitive::indices()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

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