Skip to content

Commit

Permalink
fix: update RandomIterableAggregate (#53)
Browse files Browse the repository at this point in the history
Remove recursivity
  • Loading branch information
drupol committed Feb 18, 2024
1 parent e5c9cee commit 16a4979
Show file tree
Hide file tree
Showing 6 changed files with 202 additions and 43 deletions.
16 changes: 16 additions & 0 deletions phpstan-baseline.neon
@@ -0,0 +1,16 @@
parameters:
ignoreErrors:
-
message: "#^While loop condition is always true\\.$#"
count: 1
path: src/RandomIntegerAggregate.php

-
message: "#^Parameter \\#1 \\$iterable of class loophp\\\\iterators\\\\UnpackIterableAggregate constructor expects iterable\\<\\(int\\|string\\), array\\{TKey, T\\}\\>, loophp\\\\iterators\\\\UnpackIterableAggregate\\<array\\{TKey, T\\}\\|int\\|null, array\\{TKey, T\\}\\|int\\|null\\> given\\.$#"
count: 1
path: src/RandomIterableAggregate.php

-
message: "#^Parameter \\#1 \\$iterable of class loophp\\\\iterators\\\\UnpackIterableAggregate constructor expects iterable\\<\\(int\\|string\\), array\\{array\\{TKey, T\\}\\|int\\|null, array\\{TKey, T\\}\\|int\\|null\\}\\>, loophp\\\\iterators\\\\SortIterableAggregate\\<array\\<int, int\\|null\\>, array\\<int, array\\{TKey, T\\}\\|int\\|null\\>\\> given\\.$#"
count: 1
path: src/RandomIterableAggregate.php
2 changes: 2 additions & 0 deletions phpstan.neon.dist
@@ -0,0 +1,2 @@
includes:
- phpstan-baseline.neon
36 changes: 36 additions & 0 deletions src/RandomIntegerAggregate.php
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

namespace loophp\iterators;

use Generator;
use IteratorAggregate;

use const PHP_INT_MAX;

/**
* @implements IteratorAggregate<int, int>
*/
final class RandomIntegerAggregate implements IteratorAggregate
{
public function __construct(
private readonly ?int $seed = null,
private readonly int $min = 0,
private readonly int $max = PHP_INT_MAX,
) {}

/**
* @return Generator<int, int>
*/
public function getIterator(): Generator
{
if (null !== $this->seed) {
mt_srand($this->seed);
}

while (true) {
yield mt_rand($this->min, $this->max);
}
}
}
53 changes: 17 additions & 36 deletions src/RandomIterableAggregate.php
Expand Up @@ -15,50 +15,31 @@
*/
final class RandomIterableAggregate implements IteratorAggregate
{
/**
* @var PackIterableAggregate<TKey, T>
*/
private PackIterableAggregate $iteratorAggregate;

/**
* @param iterable<TKey, T> $iterable
*/
public function __construct(iterable $iterable, private int $seed = 0)
{
$this->iteratorAggregate = new PackIterableAggregate($iterable);
}
public function __construct(
private readonly iterable $iterable,
private readonly ?int $seed = null
) {}

/**
* @return Generator<TKey, T>
*/
public function getIterator(): Generator
{
mt_srand($this->seed);

yield from $this->randomize($this->iteratorAggregate, $this->seed);
}

/**
* @param iterable<int, array{0: TKey, 1: T}> $iterable
*
* @return Generator<TKey, T>
* @psalm-suppress InvalidArgument
*/
private function randomize(iterable $iterable, int $seed): Generator
public function getIterator(): Generator
{
$queue = [];

foreach (new UnpackIterableAggregate($iterable) as $key => $value) {
if (0 === mt_rand(0, $seed)) {
yield $key => $value;

continue;
}

$queue[] = [$key, $value];
}

if ([] !== $queue) {
yield from $this->randomize($queue, $seed);
}
yield from new UnpackIterableAggregate(
new UnpackIterableAggregate(
new SortIterableAggregate(
new MultipleIterableAggregate([
new RandomIntegerAggregate($this->seed),
new PackIterableAggregate($this->iterable),
]),
static fn (array $a, array $b): int => $a[0] <=> $b[0]
)
)
);
}
}
5 changes: 4 additions & 1 deletion src/SortIterableAggregate.php
Expand Up @@ -21,7 +21,10 @@ final class SortIterableAggregate implements IteratorAggregate
* @param iterable<TKey, T> $iterable
* @param Closure(T, T, TKey, TKey): int $callback
*/
public function __construct(private readonly iterable $iterable, private readonly Closure $callback) {}
public function __construct(
private readonly iterable $iterable,
private readonly Closure $callback
) {}

/**
* @return Generator<TKey, T>
Expand Down
133 changes: 127 additions & 6 deletions tests/unit/RandomIterableAggregateTest.php
Expand Up @@ -15,35 +15,123 @@

use function count;

use const PHP_VERSION_ID;

/**
* @internal
*
* @coversDefaultClass \loophp\iterators
*/
final class RandomIterableAggregateTest extends TestCase
{
public function testSeed(): void
public function testSeedWithPHP81AndSmaller(): void
{
if (PHP_VERSION_ID >= 80200) {
self::markTestSkipped('This test is only for PHP 8.1 and smaller.');
}

$input = static function (): Generator {
yield from array_combine(range('a', 'z'), range('a', 'z'));
};

$iterator = (new RandomIterableAggregate($input()));
$iterator = (new RandomIterableAggregate($input(), 0));

$a = [];

foreach ($iterator as $key => $value) {
$a[$key] = $value;
}

$expected = array_combine(range('a', 'z'), range('a', 'z'));
$expected = [
'q' => 'q',
'l' => 'l',
'd' => 'd',
'a' => 'a',
'm' => 'm',
'o' => 'o',
'p' => 'p',
'c' => 'c',
'y' => 'y',
'z' => 'z',
'f' => 'f',
'b' => 'b',
's' => 's',
'x' => 'x',
'k' => 'k',
'v' => 'v',
'r' => 'r',
't' => 't',
'j' => 'j',
'h' => 'h',
'e' => 'e',
'n' => 'n',
'g' => 'g',
'w' => 'w',
'i' => 'i',
'u' => 'u',
];

self::assertSame(iterator_count($input()), count($expected));
self::assertSame($expected, $a);
}

public function testSimple(): void
public function testSeedWithPHP82AndGreater(): void
{
if (PHP_VERSION_ID < 80200) {
self::markTestSkipped('This test is only for PHP 8.1 and smaller.');
}

$input = static function (): Generator {
yield from array_combine(range('a', 'z'), range('a', 'z'));
};

$iterator = (new RandomIterableAggregate($input(), 0));

$a = [];

foreach ($iterator as $key => $value) {
$a[$key] = $value;
}

$expected = [
'w' => 'w',
'h' => 'h',
'z' => 'z',
'a' => 'a',
'e' => 'e',
's' => 's',
'p' => 'p',
'x' => 'x',
'y' => 'y',
'i' => 'i',
'g' => 'g',
'v' => 'v',
'k' => 'k',
'n' => 'n',
'o' => 'o',
'b' => 'b',
'd' => 'd',
'c' => 'c',
'q' => 'q',
't' => 't',
'f' => 'f',
'm' => 'm',
'r' => 'r',
'u' => 'u',
'j' => 'j',
'l' => 'l',
];

self::assertSame(iterator_count($input()), count($expected));
self::assertSame($expected, $a);
}

public function testSimpleWithPHP81AndSmaller(): void
{
if (PHP_VERSION_ID >= 80200) {
self::markTestSkipped('This test is only for PHP 8.1 and smaller.');
}

$input = static function (): Generator {
yield from array_combine(range('a', 'f'), range('a', 'f'));
};
Expand All @@ -59,12 +147,45 @@ public function testSimple(): void
}

$expected = [
['a', 'a'],
['b', 'b'],
['c', 'c'],
['f', 'f'],
['e', 'e'],
['d', 'd'],
['a', 'a'],
];

self::assertSame(iterator_count($input()), count($expected));
self::assertSame($expected, $a);
}

public function testSimpleWithPHP82AndGreater(): void
{
if (PHP_VERSION_ID < 80200) {
self::markTestSkipped('This test is only for PHP 8.2 and greater.');
}

$input = static function (): Generator {
yield from array_combine(range('a', 'f'), range('a', 'f'));
};

$seed = 2;

$iterator = (new RandomIterableAggregate($input(), $seed));

$a = [];

foreach ($iterator as $key => $value) {
$a[] = [$key, $value];
}

$expected = [
['f', 'f'],
['c', 'c'],
['a', 'a'],
['e', 'e'],
['b', 'b'],
['c', 'c'],
['d', 'd'],
];

self::assertSame(iterator_count($input()), count($expected));
Expand Down

0 comments on commit 16a4979

Please sign in to comment.