Skip to content

Commit

Permalink
feat: add MersenneTwisterRNGIteratorAggregate.
Browse files Browse the repository at this point in the history
  • Loading branch information
drupol committed Jun 13, 2022
1 parent 11c558a commit f487185
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 0 deletions.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ The missing PHP iterators.
* `InterruptableIterableAggregate`: `InterruptableIterableAggregate(iterable $iterable)`
* `IterableIterator`: `IterableIterator(iterable $iterable)`
* `IterableIteratorAggregate`: `IterableIteratorAggregate(iterable $iterable)`
* `MersenneTwisterRNGIteratorAggregate`
* `MultipleIterableAggregate`
* `PackIterableAggregate`
* `PausableIteratorAggregate`
Expand Down Expand Up @@ -99,6 +100,19 @@ foreach ($iterator as $generator => [$key, $value]) {
}
```

### MersenneTwisterRNGIteratorAggregate

```php
<?php

$rngGenerator = (new MersenneTwisterRNGIteratorAggregate())
->withMin(1)
->withMax(10)
->withSeed($seed);

foreach ($rngGenerator as $randomValue) {} // Random integers in [1, 10]
```

### PackIterableAggregate

```php
Expand Down
69 changes: 69 additions & 0 deletions src/MersenneTwisterRNGIteratorAggregate.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

/**
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/

declare(strict_types=1);

namespace loophp\iterators;

use Generator;
use IteratorAggregate;

use const PHP_INT_MAX;
use const PHP_INT_MIN;

/**
* @implements IteratorAggregate<int, int>
*/
final class MersenneTwisterRNGIteratorAggregate implements IteratorAggregate
{
private int $max = PHP_INT_MAX;

private int $min = PHP_INT_MIN;

private int $seed = 0;

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

// @phpstan-ignore-next-line
while (true) {
yield mt_rand($this->min, $this->max);
}
}

public function withMax(int $max): self
{
$clone = clone $this;
$clone->max = $max;

return $clone;
}

public function withMin(int $min): self
{
$clone = clone $this;
$clone->min = $min;

return $clone;
}

public function withSeed(int $seed): self
{
$clone = clone $this;
$clone->seed = $seed;

mt_srand($seed);

return $clone;
}
}
49 changes: 49 additions & 0 deletions tests/unit/MersenneTwisterRNGIteratorAggregatorTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

/**
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/

declare(strict_types=1);

namespace tests\loophp\iterators;

use LimitIterator;
use loophp\iterators\MersenneTwisterRNGIteratorAggregate;
use PHPUnit\Framework\TestCase;

/**
* @internal
* @coversDefaultClass \loophp\iterators
*/
final class MersenneTwisterRNGIteratorAggregatorTest extends TestCase
{
public function testBasic(): void
{
$iterator =
new LimitIterator(
(new MersenneTwisterRNGIteratorAggregate())->withMin(1)->withMax(100)->getIterator(),
0,
100
);

$expected = range(0, 100);
self::assertNotSame($expected, iterator_to_array($iterator));
}

public function testWithSeed(): void
{
$seed = 123;

$iterator =
new LimitIterator(
(new MersenneTwisterRNGIteratorAggregate())->withMin(1)->withMax(10)->withSeed($seed)->getIterator(),
0,
10
);

$expected = [3, 10, 3, 1, 1, 3, 7, 8, 10, 5];
self::assertSame($expected, iterator_to_array($iterator));
}
}

0 comments on commit f487185

Please sign in to comment.