diff --git a/src/Iterators/MemoizingIterator.php b/src/Iterators/MemoizingIterator.php new file mode 100644 index 00000000..3d4f937d --- /dev/null +++ b/src/Iterators/MemoizingIterator.php @@ -0,0 +1,77 @@ + + */ +class MemoizingIterator implements \Iterator +{ + private array $cache = []; + private int $index = 0; + + + /** + * @param \Iterator $inner + */ + public function __construct( + private readonly \Iterator $inner, + ) { + } + + + public function rewind(): void + { + if (!$this->cache) { + $this->inner->rewind(); + } + $this->index = 0; + } + + + /** + * @return V + */ + public function current(): mixed + { + return $this->cache[$this->index][1] ?? null; + } + + + /** + * @return K + */ + public function key(): mixed + { + return $this->cache[$this->index][0] ?? null; + } + + + public function next(): void + { + if (!isset($this->cache[++$this->index])) { + $this->inner->next(); + } + } + + + public function valid(): bool + { + if (!isset($this->cache[$this->index]) && $this->inner->valid()) { + $this->cache[$this->index] = [$this->inner->key(), $this->inner->current()]; + } + return isset($this->cache[$this->index]); + } +} diff --git a/tests/Iterators/MemoizingIterator.phpt b/tests/Iterators/MemoizingIterator.phpt new file mode 100644 index 00000000..7e4e74a5 --- /dev/null +++ b/tests/Iterators/MemoizingIterator.phpt @@ -0,0 +1,77 @@ + 'apple'; + yield ['b'] => ['banana']; + yield 'c' => 'cherry'; +} + + +test('iteration', function () { + $iterator = new MemoizingIterator(iterator()); + + $pairs = []; + foreach ($iterator as $key => $value) { + $pairs[] = [$key, $value]; + } + Assert::same( + [ + ['a', 'apple'], + [['b'], ['banana']], + ['c', 'cherry'], + ], + $pairs, + ); +}); + + +test('re-iteration', function () { + $iterator = new MemoizingIterator(iterator()); + + foreach ($iterator as $value); + + $pairs = []; + foreach ($iterator as $key => $value) { + $pairs[] = [$key, $value]; + } + Assert::same( + [ + ['a', 'apple'], + [['b'], ['banana']], + ['c', 'cherry'], + ], + $pairs, + ); +}); + + +test('nested re-iteration', function () { // nefunguje + $iterator = new MemoizingIterator(iterator()); + + $pairs = []; + foreach ($iterator as $key => $value) { + $pairs[] = [$key, $value]; + foreach ($iterator as $value); + } + Assert::same( + [ + ['a', 'apple'], + [['b'], ['banana']], + ['c', 'cherry'], + ], + $pairs, + ); +});