Skip to content

Commit

Permalink
added MemoizingIterator [WIP]
Browse files Browse the repository at this point in the history
  • Loading branch information
dg committed May 3, 2024
1 parent 97c8b55 commit b080db7
Show file tree
Hide file tree
Showing 2 changed files with 154 additions and 0 deletions.
77 changes: 77 additions & 0 deletions src/Iterators/MemoizingIterator.php
@@ -0,0 +1,77 @@
<?php

/**
* This file is part of the Nette Framework (https://nette.org)
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
*/

declare(strict_types=1);

namespace Nette\Iterators;


/**
* MemoizingIterator wraps around another iterator and caches its keys and values during iteration.
* This allows the data to be re-iterated multiple times.
* @template K
* @template V
* @implements \Iterator<K, V>
*/
class MemoizingIterator implements \Iterator
{
private array $cache = [];
private int $index = 0;


/**
* @param \Iterator<K, V> $inner
*/
public function __construct(
private readonly \Iterator $inner,

Check failure on line 30 in src/Iterators/MemoizingIterator.php

View workflow job for this annotation

GitHub Actions / PHPStan

Syntax error, unexpected T_NAME_FULLY_QUALIFIED, expecting T_VARIABLE on line 30
) {
}


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]);
}
}
77 changes: 77 additions & 0 deletions tests/Iterators/MemoizingIterator.phpt
@@ -0,0 +1,77 @@
<?php

/**
* Test: Nette\Iterators\MemoizingIterator
*/

declare(strict_types=1);

use Nette\Iterators\MemoizingIterator;
use Tester\Assert;

require __DIR__ . '/../bootstrap.php';


function iterator(): Generator
{
yield 'a' => '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,
);
});

0 comments on commit b080db7

Please sign in to comment.