diff --git a/CHANGELOG.md b/CHANGELOG.md index c825823..0842e6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 5.7.0 - 2024-06-25 + +### Added + +- `Innmind\Immutable\Sequence::prepend()` + ## 5.6.0 - 2024-06-15 ### Added diff --git a/docs/structures/sequence.md b/docs/structures/sequence.md index 5c2a196..b0ab69b 100644 --- a/docs/structures/sequence.md +++ b/docs/structures/sequence.md @@ -104,6 +104,15 @@ $sequence = Sequence::ints(1, 2)->append(Sequence::ints(3, 4)); $sequence->equals(Sequence::ints(1, 2, 3, 4)); // true ``` +### `->prepend()` + +This is similar to `->append()` except the order is switched. + +!!! success "" + The main advantage of this method is when using lazy sequences. If you want to add elements at the beginning of a sequence but the rest may be lazy then you need to create a lazy sequence with your values and then append the other lazy sequence; but this reveals the underlying lazyness of the call and you need to be aware that it could be lazy. + + Instead by using this method you no longer have to be aware that the other sequence is lazy or not. + ## Access values ### `->size()` :material-memory-arrow-down: diff --git a/proofs/sequence.php b/proofs/sequence.php index 4cb6b94..9f14d9c 100644 --- a/proofs/sequence.php +++ b/proofs/sequence.php @@ -2,6 +2,7 @@ declare(strict_types = 1); use Innmind\Immutable\Sequence; +use Innmind\BlackBox\Set; return static function() { yield test( @@ -15,4 +16,42 @@ static function($assert) { ); }, ); + + yield proof( + 'Sequence::prepend()', + given( + Set\Sequence::of(Set\Type::any()), + Set\Sequence::of(Set\Type::any()), + ), + static function($assert, $first, $second) { + $assert->same( + [...$first, ...$second], + Sequence::of(...$second) + ->prepend(Sequence::of(...$first)) + ->toList(), + ); + + $assert->same( + [...$first, ...$second], + Sequence::defer((static function() use ($second) { + yield from $second; + })()) + ->prepend(Sequence::defer((static function() use ($first) { + yield from $first; + })())) + ->toList(), + ); + + $assert->same( + [...$first, ...$second], + Sequence::lazy(static function() use ($second) { + yield from $second; + }) + ->prepend(Sequence::lazy(static function() use ($first) { + yield from $first; + })) + ->toList(), + ); + }, + ); }; diff --git a/src/Sequence.php b/src/Sequence.php index 55ff561..b01ffcf 100644 --- a/src/Sequence.php +++ b/src/Sequence.php @@ -489,6 +489,20 @@ public function append(self $sequence): self )); } + /** + * Prepend the given sequence to the current one + * + * @param self $sequence + * + * @return self + */ + public function prepend(self $sequence): self + { + return new self($this->implementation->prepend( + $sequence->implementation, + )); + } + /** * Return a sequence with all elements from the current one that exist * in the given one diff --git a/src/Sequence/Defer.php b/src/Sequence/Defer.php index 094bdbe..d478335 100644 --- a/src/Sequence/Defer.php +++ b/src/Sequence/Defer.php @@ -483,6 +483,29 @@ public function append(Implementation $sequence): Implementation ); } + /** + * @param Implementation $sequence + * + * @return Implementation + */ + public function prepend(Implementation $sequence): Implementation + { + /** @psalm-suppress ImpureFunctionCall */ + return new self( + (static function(\Iterator $values, Implementation $sequence): \Generator { + /** @var T $value */ + foreach ($sequence->iterator() as $value) { + yield $value; + } + + /** @var T $value */ + foreach ($values as $value) { + yield $value; + } + })($this->values, $sequence), + ); + } + /** * @param Implementation $sequence * diff --git a/src/Sequence/Implementation.php b/src/Sequence/Implementation.php index 7238474..60158b1 100644 --- a/src/Sequence/Implementation.php +++ b/src/Sequence/Implementation.php @@ -228,6 +228,15 @@ public function takeEnd(int $size): self; */ public function append(self $sequence): self; + /** + * Prepend the given sequence to the current one + * + * @param self $sequence + * + * @return self + */ + public function prepend(self $sequence): self; + /** * Return a sequence with all elements from the current one that exist * in the given one diff --git a/src/Sequence/Lazy.php b/src/Sequence/Lazy.php index e02654e..0cd3eff 100644 --- a/src/Sequence/Lazy.php +++ b/src/Sequence/Lazy.php @@ -517,6 +517,31 @@ static function(RegisterCleanup $registerCleanup) use ($values, $sequence): \Gen ); } + /** + * @param Implementation $sequence + * + * @return Implementation + */ + public function prepend(Implementation $sequence): Implementation + { + $values = $this->values; + + return new self( + static function(RegisterCleanup $registerCleanup) use ($values, $sequence): \Generator { + /** @var \Iterator */ + $generator = self::open($sequence, $registerCleanup); + + foreach ($generator as $value) { + yield $value; + } + + foreach ($values($registerCleanup) as $value) { + yield $value; + } + }, + ); + } + /** * @param Implementation $sequence * diff --git a/src/Sequence/Primitive.php b/src/Sequence/Primitive.php index 6af6821..6371a5c 100644 --- a/src/Sequence/Primitive.php +++ b/src/Sequence/Primitive.php @@ -363,6 +363,22 @@ public function append(Implementation $sequence): self return new self(\array_merge($this->values, $other)); } + /** + * @param Implementation $sequence + * + * @return self + */ + public function prepend(Implementation $sequence): self + { + $other = []; + + foreach ($sequence->iterator() as $value) { + $other[] = $value; + } + + return new self(\array_merge($other, $this->values)); + } + /** * @param Implementation $sequence *