Skip to content

Commit

Permalink
Use a CacheIterator iterator.
Browse files Browse the repository at this point in the history
  • Loading branch information
drupol committed Aug 4, 2020
1 parent 69e9683 commit 1dcd9eb
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 113 deletions.
91 changes: 17 additions & 74 deletions spec/loophp/collection/CollectionSpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@
use loophp\collection\Operation\AbstractOperation;
use OutOfRangeException;
use PhpSpec\ObjectBehavior;
use Psr\Cache\CacheItemInterface;
use Psr\Cache\CacheItemPoolInterface;
use stdClass;

class CollectionSpec extends ObjectBehavior
Expand Down Expand Up @@ -226,86 +224,31 @@ public function it_can_be_returned_as_an_array(): void
->shouldIterateAs(['1', '2', '3']);
}

public function it_can_cache(CacheItemPoolInterface $cache, CacheItemInterface $cacheItemFound0, CacheItemInterface $cacheItemNotFound1, CacheItemInterface $cacheItemNotFound2, CacheItemInterface $cacheItemNotFound3): void
public function it_can_cache(): void
{
$fhandle = fopen(__DIR__ . '/../../fixtures/sample.txt', 'rb');

$cache
->getItem('1')
->shouldBeCalledOnce();
$cache
->getItem('2')
->shouldBeCalledOnce();
$cache
->getItem('3')
->shouldBeCalledOnce();

$cache
->getItem('0')
->willReturn($cacheItemFound0);

$cache
->getItem('1')
->willReturn($cacheItemNotFound1);

$cache
->getItem('2')
->willReturn($cacheItemNotFound2);

$cache
->getItem('3')
->willReturn($cacheItemNotFound3);

$cacheItemFound0
->isHit()
->willReturn(true);

$cacheItemNotFound1
->isHit()
->willReturn(false);

$cacheItemNotFound2
->isHit()
->willReturn(false);

$cacheItemNotFound3
->isHit()
->willReturn(false);

$cacheItemNotFound1
->set([1, 'b'])
->shouldBeCalledOnce();

$cacheItemNotFound2
->set([2, 'c'])
->shouldBeCalledOnce();

$cache
->save($cacheItemNotFound1)
->shouldBeCalledOnce();

$cacheItemFound0
->get()
->willReturn([0, 'a']);

$cache
->save($cacheItemNotFound1)
->shouldBeCalled();
$this::fromResource($fhandle)
->window(2)
->shouldIterateAs([
[],
]);

$cacheItemNotFound1
->get()
->willReturn([1, 'b']);
$fhandle = fopen(__DIR__ . '/../../fixtures/sample.txt', 'rb');

$cache
->save($cacheItemNotFound2)
->shouldBeCalled();
$this::fromResource($fhandle)
->cache()
->window(2)
->shouldIterateAs([
[0 => 'a', 1 => 'b'],
[1 => 'b', 2 => 'c'],
[2 => 'c'],
]);

$cacheItemNotFound2
->get()
->willReturn([2, 'c']);
$fhandle = fopen(__DIR__ . '/../../fixtures/sample.txt', 'rb');

$this::fromResource($fhandle)
->cache($cache)
->cache()
->shouldIterateAs(['a', 'b', 'c']);

$fhandle = fopen(__DIR__ . '/../../fixtures/sample.txt', 'rb');
Expand Down
93 changes: 93 additions & 0 deletions src/Iterator/CacheIterator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<?php

declare(strict_types=1);

namespace loophp\collection\Iterator;

use Iterator;
use Psr\Cache\CacheItemInterface;
use Psr\Cache\CacheItemPoolInterface;

/**
* @psalm-template TKey
* @psalm-template TKey of array-key
* @psalm-template T
*
* @implements \Iterator<TKey, T>
*/
final class CacheIterator implements Iterator
{
/**
* @var CacheItemPoolInterface
*/
private $cache;

/**
* @var Iterator
* @psalm-var Iterator<TKey, T>
*/
private $inner;

/**
* @var int
*/
private $key;

/**
* @psalm-param \Iterator<TKey, T> $iterator
*/
public function __construct(Iterator $iterator, CacheItemPoolInterface $cache)
{
$this->inner = $iterator;
$this->cache = $cache;
$this->key = 0;
}

/**
* @psalm-return T
*/
public function current()
{
return $this->getItemOrSave((string) $this->key)->get()[1];
}

/**
* @psalm-return TKey
*/
public function key()
{
return $this->getItemOrSave((string) $this->key)->get()[0];
}

public function next(): void
{
++$this->key;
$this->inner->next();
}

public function rewind(): void
{
$this->key = 0;
}

public function valid(): bool
{
return $this->cache->hasItem((string) $this->key) || $this->inner->valid();
}

private function getItemOrSave(string $key): CacheItemInterface
{
$item = $this->cache->getItem($key);

if (false === $item->isHit()) {
$item->set([
$this->inner->key(),
$this->inner->current(),
]);

$this->cache->save($item);
}

return $item;
}
}
4 changes: 2 additions & 2 deletions src/Iterator/ClosureIterator.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ final class ClosureIterator extends ProxyIterator implements Iterator, OuterIter

/**
* @var callable
* @psalm-var callable(T...):(Generator<TKey, T>)
* @psalm-var callable(mixed...):(Generator<TKey, T>)
*/
private $callable;

Expand All @@ -39,7 +39,7 @@ final class ClosureIterator extends ProxyIterator implements Iterator, OuterIter
/**
* @param mixed ...$arguments
* @psalm-param T ...$arguments
* @psalm-param callable(T...):(Generator<TKey,T>) $callable
* @psalm-param callable(mixed...):(Generator<TKey,T>) $callable
*/
public function __construct(callable $callable, ...$arguments)
{
Expand Down
40 changes: 3 additions & 37 deletions src/Operation/Cache.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Generator;
use Iterator;
use loophp\collection\Contract\Operation;
use loophp\collection\Iterator\CacheIterator;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\Cache\Adapter\ArrayAdapter;

Expand All @@ -25,49 +26,14 @@ public function __construct(?CacheItemPoolInterface $cache = null)

public function __invoke(): Closure
{
$iteratorIndex = 0;

return
/**
* @psalm-param \Iterator<TKey, T> $iterator
*
* @psalm-return \Generator<TKey, T>
*/
static function (Iterator $iterator, CacheItemPoolInterface $cache) use (&$iteratorIndex): Generator {
for ($index = 0; true; ++$index) {
$item = $cache->getItem((string) $index);

if ($item->isHit()) {
/** @psalm-var array{TKey, T} $value */
$value = $item->get();

yield $value[0] => $value[1];

continue;
}

if ($iteratorIndex < $index) {
$iterator->next();

++$iteratorIndex;
}

if (!$iterator->valid()) {
break;
}

$item->set([
$iterator->key(),
$iterator->current(),
]);

$cache->save($item);

/** @psalm-var array{TKey, T} $value */
$value = $item->get();

yield $value[0] => $value[1];
}
static function (Iterator $iterator, CacheItemPoolInterface $cache): Generator {
return yield from new CacheIterator($iterator, $cache);
};
}
}

0 comments on commit 1dcd9eb

Please sign in to comment.