1 | <?php |
||||
2 | declare(strict_types = 1); |
||||
3 | |||||
4 | namespace Innmind\Immutable; |
||||
5 | |||||
6 | use Innmind\Immutable\Exception\{ |
||||
7 | LogicException, |
||||
8 | CannotGroupEmptyStructure, |
||||
9 | ElementNotFound, |
||||
10 | OutOfBoundException, |
||||
11 | }; |
||||
12 | |||||
13 | /** |
||||
14 | * @template T |
||||
15 | */ |
||||
16 | final class Sequence implements \Countable |
||||
17 | { |
||||
18 | private string $type; |
||||
19 | private ValidateArgument $validate; |
||||
20 | private Sequence\Implementation $implementation; |
||||
21 | |||||
22 | 222 | private function __construct(string $type, Sequence\Implementation $implementation) |
|||
23 | { |
||||
24 | 222 | $this->type = $type; |
|||
25 | 222 | $this->validate = Type::of($type); |
|||
26 | 222 | $this->implementation = $implementation; |
|||
27 | 222 | } |
|||
28 | |||||
29 | /** |
||||
30 | * @param T $values |
||||
31 | * |
||||
32 | * @return self<T> |
||||
33 | */ |
||||
34 | 216 | public static function of(string $type, ...$values): self |
|||
35 | { |
||||
36 | 216 | $self = new self($type, new Sequence\Primitive($type, ...$values)); |
|||
37 | 216 | $self->implementation->reduce( |
|||
38 | 216 | 1, |
|||
39 | static function(int $position, $element) use ($self): int { |
||||
40 | 74 | ($self->validate)($element, $position); |
|||
41 | |||||
42 | 74 | return ++$position; |
|||
43 | 216 | } |
|||
44 | ); |
||||
45 | |||||
46 | 216 | return $self; |
|||
47 | } |
||||
48 | |||||
49 | /** |
||||
50 | * @param mixed $values |
||||
51 | * |
||||
52 | * @return self<mixed> |
||||
53 | */ |
||||
54 | 1 | public static function mixed(...$values): self |
|||
55 | { |
||||
56 | /** @var self<mixed> */ |
||||
57 | 1 | $self = new self('mixed', new Sequence\Primitive('mixed', ...$values)); |
|||
58 | |||||
59 | 1 | return $self; |
|||
60 | } |
||||
61 | |||||
62 | /** |
||||
63 | * @return self<int> |
||||
64 | */ |
||||
65 | 6 | public static function ints(int ...$values): self |
|||
66 | { |
||||
67 | /** @var self<int> */ |
||||
68 | 6 | $self = new self('int', new Sequence\Primitive('int', ...$values)); |
|||
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||||
69 | |||||
70 | 6 | return $self; |
|||
71 | } |
||||
72 | |||||
73 | /** |
||||
74 | * @return self<float> |
||||
75 | */ |
||||
76 | 1 | public static function floats(float ...$values): self |
|||
77 | { |
||||
78 | /** @var self<float> */ |
||||
79 | 1 | $self = new self('float', new Sequence\Primitive('float', ...$values)); |
|||
0 ignored issues
–
show
$values of type double is incompatible with the type Innmind\Immutable\Sequence\T expected by parameter $values of Innmind\Immutable\Sequen...rimitive::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
80 | |||||
81 | 1 | return $self; |
|||
82 | } |
||||
83 | |||||
84 | /** |
||||
85 | * @return self<string> |
||||
86 | */ |
||||
87 | 1 | public static function strings(string ...$values): self |
|||
88 | { |
||||
89 | /** @var self<string> */ |
||||
90 | 1 | $self = new self('string', new Sequence\Primitive('string', ...$values)); |
|||
0 ignored issues
–
show
$values of type string is incompatible with the type Innmind\Immutable\Sequence\T expected by parameter $values of Innmind\Immutable\Sequen...rimitive::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
91 | |||||
92 | 1 | return $self; |
|||
93 | } |
||||
94 | |||||
95 | /** |
||||
96 | * @return self<object> |
||||
97 | */ |
||||
98 | 1 | public static function objects(object ...$values): self |
|||
99 | { |
||||
100 | /** @var self<object> */ |
||||
101 | 1 | $self = new self('object', new Sequence\Primitive('object', ...$values)); |
|||
102 | |||||
103 | 1 | return $self; |
|||
104 | } |
||||
105 | |||||
106 | 41 | public function isOfType(string $type): bool |
|||
107 | { |
||||
108 | 41 | return $this->type === $type; |
|||
109 | } |
||||
110 | |||||
111 | /** |
||||
112 | * Type of the elements |
||||
113 | */ |
||||
114 | 39 | public function type(): string |
|||
115 | { |
||||
116 | 39 | return $this->type; |
|||
117 | } |
||||
118 | |||||
119 | 19 | public function size(): int |
|||
120 | { |
||||
121 | 19 | return $this->implementation->size(); |
|||
122 | } |
||||
123 | |||||
124 | /** |
||||
125 | * {@inheritdoc} |
||||
126 | */ |
||||
127 | 8 | public function count(): int |
|||
128 | { |
||||
129 | 8 | return $this->implementation->size(); |
|||
130 | } |
||||
131 | |||||
132 | /** |
||||
133 | * Return the element at the given index |
||||
134 | * |
||||
135 | * @throws OutOfBoundException |
||||
136 | * |
||||
137 | * @return T |
||||
138 | */ |
||||
139 | 24 | public function get(int $index) |
|||
140 | { |
||||
141 | /** @var T */ |
||||
142 | 24 | return $this->implementation->get($index); |
|||
143 | } |
||||
144 | |||||
145 | /** |
||||
146 | * Return the diff between this sequence and another |
||||
147 | * |
||||
148 | * @param self<T> $sequence |
||||
149 | * |
||||
150 | * @return self<T> |
||||
151 | */ |
||||
152 | 3 | public function diff(self $sequence): self |
|||
153 | { |
||||
154 | 3 | assertSequence($this->type, $sequence, 1); |
|||
155 | |||||
156 | 3 | $self = clone $this; |
|||
157 | 3 | $self->implementation = $this->implementation->diff( |
|||
158 | 3 | $sequence->implementation |
|||
159 | ); |
||||
160 | |||||
161 | 3 | return $self; |
|||
162 | } |
||||
163 | |||||
164 | /** |
||||
165 | * Remove all duplicates from the sequence |
||||
166 | * |
||||
167 | * @return self<T> |
||||
168 | */ |
||||
169 | 96 | public function distinct(): self |
|||
170 | { |
||||
171 | 96 | $self = clone $this; |
|||
172 | 96 | $self->implementation = $this->implementation->distinct(); |
|||
173 | |||||
174 | 96 | return $self; |
|||
175 | } |
||||
176 | |||||
177 | /** |
||||
178 | * Remove the n first elements |
||||
179 | * |
||||
180 | * @return self<T> |
||||
181 | */ |
||||
182 | 4 | public function drop(int $size): self |
|||
183 | { |
||||
184 | 4 | $self = clone $this; |
|||
185 | 4 | $self->implementation = $this->implementation->drop($size); |
|||
186 | |||||
187 | 4 | return $self; |
|||
188 | } |
||||
189 | |||||
190 | /** |
||||
191 | * Remove the n last elements |
||||
192 | * |
||||
193 | * @return self<T> |
||||
194 | */ |
||||
195 | 1 | public function dropEnd(int $size): self |
|||
196 | { |
||||
197 | 1 | $self = clone $this; |
|||
198 | 1 | $self->implementation = $this->implementation->dropEnd($size); |
|||
199 | |||||
200 | 1 | return $self; |
|||
201 | } |
||||
202 | |||||
203 | /** |
||||
204 | * Check if the two sequences are equal |
||||
205 | * |
||||
206 | * @param self<T> $sequence |
||||
207 | */ |
||||
208 | 7 | public function equals(self $sequence): bool |
|||
209 | { |
||||
210 | 7 | assertSequence($this->type, $sequence, 1); |
|||
211 | |||||
212 | 6 | return $this->implementation->equals( |
|||
213 | 6 | $sequence->implementation |
|||
214 | ); |
||||
215 | } |
||||
216 | |||||
217 | /** |
||||
218 | * Return all elements that satisfy the given predicate |
||||
219 | * |
||||
220 | * @param callable(T): bool $predicate |
||||
221 | * |
||||
222 | * @return self<T> |
||||
223 | */ |
||||
224 | 3 | public function filter(callable $predicate): self |
|||
225 | { |
||||
226 | 3 | $self = clone $this; |
|||
227 | 3 | $self->implementation = $this->implementation->filter($predicate); |
|||
228 | |||||
229 | 3 | return $self; |
|||
230 | } |
||||
231 | |||||
232 | /** |
||||
233 | * Apply the given function to all elements of the sequence |
||||
234 | * |
||||
235 | * @param callable(T): void $function |
||||
236 | */ |
||||
237 | 3 | public function foreach(callable $function): void |
|||
238 | { |
||||
239 | 3 | $this->implementation->foreach($function); |
|||
240 | 3 | } |
|||
241 | |||||
242 | /** |
||||
243 | * Return a new map of pairs grouped by keys determined with the given |
||||
244 | * discriminator function |
||||
245 | * |
||||
246 | * @template D |
||||
247 | * @param callable(T): D $discriminator |
||||
248 | * |
||||
249 | * @throws CannotGroupEmptyStructure |
||||
250 | * |
||||
251 | * @return Map<D, self<T>> |
||||
252 | */ |
||||
253 | 4 | public function groupBy(callable $discriminator): Map |
|||
254 | { |
||||
255 | 4 | return $this->implementation->groupBy($discriminator); |
|||
256 | } |
||||
257 | |||||
258 | /** |
||||
259 | * Return the first element |
||||
260 | * |
||||
261 | * @return T |
||||
262 | */ |
||||
263 | 3 | public function first() |
|||
264 | { |
||||
265 | /** @var T */ |
||||
266 | 3 | return $this->implementation->first(); |
|||
267 | } |
||||
268 | |||||
269 | /** |
||||
270 | * Return the last element |
||||
271 | * |
||||
272 | * @return T |
||||
273 | */ |
||||
274 | 3 | public function last() |
|||
275 | { |
||||
276 | /** @var T */ |
||||
277 | 3 | return $this->implementation->last(); |
|||
278 | } |
||||
279 | |||||
280 | /** |
||||
281 | * Check if the sequence contains the given element |
||||
282 | * |
||||
283 | * @param T $element |
||||
284 | */ |
||||
285 | 67 | public function contains($element): bool |
|||
286 | { |
||||
287 | 67 | ($this->validate)($element, 1); |
|||
288 | |||||
289 | 67 | return $this->implementation->contains($element); |
|||
290 | } |
||||
291 | |||||
292 | /** |
||||
293 | * Return the index for the given element |
||||
294 | * |
||||
295 | * @param T $element |
||||
296 | * |
||||
297 | * @throws ElementNotFound |
||||
298 | */ |
||||
299 | 19 | public function indexOf($element): int |
|||
300 | { |
||||
301 | 19 | ($this->validate)($element, 1); |
|||
302 | |||||
303 | 19 | return $this->implementation->indexOf($element); |
|||
304 | } |
||||
305 | |||||
306 | /** |
||||
307 | * Return the list of indices |
||||
308 | * |
||||
309 | * @return self<int> |
||||
310 | */ |
||||
311 | 2 | public function indices(): self |
|||
312 | { |
||||
313 | /** @var self<int> */ |
||||
314 | 2 | $self = new self('int', $this->implementation->indices()); |
|||
315 | |||||
316 | 2 | return $self; |
|||
317 | } |
||||
318 | |||||
319 | /** |
||||
320 | * Return a new sequence by applying the given function to all elements |
||||
321 | * |
||||
322 | * @param callable(T): T $function |
||||
323 | * |
||||
324 | * @return self<T> |
||||
325 | */ |
||||
326 | 3 | public function map(callable $function): self |
|||
327 | { |
||||
328 | 3 | $self = clone $this; |
|||
329 | 3 | $self->implementation = $this->implementation->map($function); |
|||
330 | |||||
331 | 2 | return $self; |
|||
332 | } |
||||
333 | |||||
334 | /** |
||||
335 | * Pad the sequence to a defined size with the given element |
||||
336 | * |
||||
337 | * @param T $element |
||||
338 | * |
||||
339 | * @return self<T> |
||||
340 | */ |
||||
341 | 2 | public function pad(int $size, $element): self |
|||
342 | { |
||||
343 | 2 | ($this->validate)($element, 2); |
|||
344 | |||||
345 | 1 | $self = clone $this; |
|||
346 | 1 | $self->implementation = $this->implementation->pad($size, $element); |
|||
347 | |||||
348 | 1 | return $self; |
|||
349 | } |
||||
350 | |||||
351 | /** |
||||
352 | * Return a sequence of 2 sequences partitioned according to the given predicate |
||||
353 | * |
||||
354 | * @param callable(T): bool $predicate |
||||
355 | * |
||||
356 | * @return Map<bool, self<T>> |
||||
357 | */ |
||||
358 | 3 | public function partition(callable $predicate): Map |
|||
359 | { |
||||
360 | 3 | return $this->implementation->partition($predicate); |
|||
361 | } |
||||
362 | |||||
363 | /** |
||||
364 | * Slice the sequence |
||||
365 | * |
||||
366 | * @return self<T> |
||||
367 | */ |
||||
368 | 4 | public function slice(int $from, int $until): self |
|||
369 | { |
||||
370 | 4 | $self = clone $this; |
|||
371 | 4 | $self->implementation = $this->implementation->slice($from, $until); |
|||
372 | |||||
373 | 4 | return $self; |
|||
374 | } |
||||
375 | |||||
376 | /** |
||||
377 | * Split the sequence in a sequence of 2 sequences splitted at the given position |
||||
378 | * |
||||
379 | * @throws OutOfBoundException |
||||
380 | * |
||||
381 | * @return self<self<T>> |
||||
382 | */ |
||||
383 | 1 | public function splitAt(int $position): self |
|||
384 | { |
||||
385 | 1 | return $this->implementation->splitAt($position); |
|||
386 | } |
||||
387 | |||||
388 | /** |
||||
389 | * Return a sequence with the n first elements |
||||
390 | * |
||||
391 | * @return self<T> |
||||
392 | */ |
||||
393 | 4 | public function take(int $size): self |
|||
394 | { |
||||
395 | 4 | $self = clone $this; |
|||
396 | 4 | $self->implementation = $this->implementation->take($size); |
|||
397 | |||||
398 | 4 | return $self; |
|||
399 | } |
||||
400 | |||||
401 | /** |
||||
402 | * Return a sequence with the n last elements |
||||
403 | * |
||||
404 | * @return self<T> |
||||
405 | */ |
||||
406 | 1 | public function takeEnd(int $size): self |
|||
407 | { |
||||
408 | 1 | $self = clone $this; |
|||
409 | 1 | $self->implementation = $this->implementation->takeEnd($size); |
|||
410 | |||||
411 | 1 | return $self; |
|||
412 | } |
||||
413 | |||||
414 | /** |
||||
415 | * Append the given sequence to the current one |
||||
416 | * |
||||
417 | * @param self<T> $sequence |
||||
418 | * |
||||
419 | * @return self<T> |
||||
420 | */ |
||||
421 | 8 | public function append(self $sequence): self |
|||
422 | { |
||||
423 | 8 | assertSequence($this->type, $sequence, 1); |
|||
424 | |||||
425 | 7 | $self = clone $this; |
|||
426 | 7 | $self->implementation = $this->implementation->append( |
|||
427 | 7 | $sequence->implementation |
|||
428 | ); |
||||
429 | |||||
430 | 7 | return $self; |
|||
431 | } |
||||
432 | |||||
433 | /** |
||||
434 | * Return a sequence with all elements from the current one that exist |
||||
435 | * in the given one |
||||
436 | * |
||||
437 | * @param self<T> $sequence |
||||
438 | * |
||||
439 | * @return self<T> |
||||
440 | */ |
||||
441 | 14 | public function intersect(self $sequence): self |
|||
442 | { |
||||
443 | 14 | assertSequence($this->type, $sequence, 1); |
|||
444 | |||||
445 | 13 | $self = clone $this; |
|||
446 | 13 | $self->implementation = $this->implementation->intersect( |
|||
447 | 13 | $sequence->implementation |
|||
448 | ); |
||||
449 | |||||
450 | 13 | return $self; |
|||
451 | } |
||||
452 | |||||
453 | /** |
||||
454 | * Add the given element at the end of the sequence |
||||
455 | * |
||||
456 | * @param T $element |
||||
457 | * |
||||
458 | * @return self<T> |
||||
459 | */ |
||||
460 | 119 | public function add($element): self |
|||
461 | { |
||||
462 | 119 | ($this->validate)($element, 1); |
|||
463 | |||||
464 | 118 | $self = clone $this; |
|||
465 | 118 | $self->implementation = $this->implementation->add($element); |
|||
466 | |||||
467 | 118 | return $self; |
|||
468 | } |
||||
469 | |||||
470 | /** |
||||
471 | * Alias for add method in order to have a syntax similar to a true tuple |
||||
472 | * when constructing the sequence |
||||
473 | * |
||||
474 | * Example: |
||||
475 | * <code> |
||||
476 | * Sequence::of('int')(1)(3) |
||||
477 | * </code> |
||||
478 | * |
||||
479 | * @param T $element |
||||
480 | * |
||||
481 | * @return self<T> |
||||
482 | */ |
||||
483 | 89 | public function __invoke($element): self |
|||
484 | { |
||||
485 | 89 | return $this->add($element); |
|||
486 | } |
||||
487 | |||||
488 | /** |
||||
489 | * Sort the sequence in a different order |
||||
490 | * |
||||
491 | * @param callable(T, T): int $function |
||||
492 | * |
||||
493 | * @return self<T> |
||||
494 | */ |
||||
495 | 3 | public function sort(callable $function): self |
|||
496 | { |
||||
497 | 3 | $self = clone $this; |
|||
498 | 3 | $self->implementation = $this->implementation->sort($function); |
|||
499 | |||||
500 | 3 | return $self; |
|||
501 | } |
||||
502 | |||||
503 | /** |
||||
504 | * Reduce the sequence to a single value |
||||
505 | * |
||||
506 | * @template R |
||||
507 | * @param R $carry |
||||
508 | * @param callable(R, T): R $reducer |
||||
509 | * |
||||
510 | * @return R |
||||
511 | */ |
||||
512 | 130 | public function reduce($carry, callable $reducer) |
|||
513 | { |
||||
514 | 130 | return $this->implementation->reduce($carry, $reducer); |
|||
515 | } |
||||
516 | |||||
517 | /** |
||||
518 | * Return a set of the same type but without any value |
||||
519 | * |
||||
520 | * @return self<T> |
||||
521 | */ |
||||
522 | 8 | public function clear(): self |
|||
523 | { |
||||
524 | 8 | $self = clone $this; |
|||
525 | 8 | $self->implementation = new Sequence\Primitive($this->type); |
|||
526 | |||||
527 | 8 | return $self; |
|||
528 | } |
||||
529 | |||||
530 | /** |
||||
531 | * Return the same sequence but in reverse order |
||||
532 | * |
||||
533 | * @return self<T> |
||||
534 | */ |
||||
535 | 3 | public function reverse(): self |
|||
536 | { |
||||
537 | 3 | $self = clone $this; |
|||
538 | 3 | $self->implementation = $this->implementation->reverse(); |
|||
539 | |||||
540 | 3 | return $self; |
|||
541 | } |
||||
542 | |||||
543 | 8 | public function empty(): bool |
|||
544 | { |
||||
545 | 8 | return $this->implementation->empty(); |
|||
546 | } |
||||
547 | |||||
548 | /** |
||||
549 | * @template ST |
||||
550 | * |
||||
551 | * @param callable(T): \Generator<ST> $mapper |
||||
552 | * |
||||
553 | * @return self<ST> |
||||
554 | */ |
||||
555 | 10 | public function toSequenceOf(string $type, callable $mapper): self |
|||
556 | { |
||||
557 | 10 | return $this->implementation->toSequenceOf($type, $mapper); |
|||
558 | } |
||||
559 | |||||
560 | /** |
||||
561 | * @template ST |
||||
562 | * |
||||
563 | * @param callable(T): \Generator<ST> $mapper |
||||
564 | * |
||||
565 | * @return Set<ST> |
||||
566 | */ |
||||
567 | 3 | public function toSetOf(string $type, callable $mapper): Set |
|||
568 | { |
||||
569 | 3 | return $this->implementation->toSetOf($type, $mapper); |
|||
570 | } |
||||
571 | |||||
572 | |||||
573 | |||||
574 | /** |
||||
575 | * @template MT |
||||
576 | * @template MS |
||||
577 | * |
||||
578 | * @param callable(T): \Generator<MT, MS> $mapper |
||||
579 | * |
||||
580 | * @return Map<MT, MS> |
||||
581 | */ |
||||
582 | 3 | public function toMapOf(string $key, string $value, callable $mapper): Map |
|||
583 | { |
||||
584 | 3 | return $this->implementation->toMapOf($key, $value, $mapper); |
|||
585 | } |
||||
586 | } |
||||
587 |