hoist callback compilation out of transform closures
This commit is contained in:
parent
b48f28e9dc
commit
04c40087c2
@ -44,9 +44,9 @@ use function Kadet\Functional\compile;
|
||||
*/
|
||||
function map(callable $fn): \Closure
|
||||
{
|
||||
return static function (iterable $input) use ($fn): iterable {
|
||||
$fn = callback($fn);
|
||||
|
||||
return static function (iterable $input) use ($fn): iterable {
|
||||
return keyedLike($input, (static function () use ($input, $fn) {
|
||||
foreach ($input as $key => $value) {
|
||||
yield $key => $fn($value, $key);
|
||||
@ -69,9 +69,9 @@ function map(callable $fn): \Closure
|
||||
*/
|
||||
function filter(?callable $fn = null): \Closure
|
||||
{
|
||||
return static function (iterable $input) use ($fn): iterable {
|
||||
$fn = $fn === null ? static fn ($value) => $value : callback($fn);
|
||||
|
||||
return static function (iterable $input) use ($fn): iterable {
|
||||
return keyedLike($input, (static function () use ($input, $fn) {
|
||||
foreach ($input as $key => $value) {
|
||||
if ($fn($value, $key)) {
|
||||
@ -94,10 +94,16 @@ function filter(?callable $fn = null): \Closure
|
||||
*/
|
||||
function reject(callable $fn): \Closure
|
||||
{
|
||||
return static function (iterable $input) use ($fn): iterable {
|
||||
$fn = callback($fn);
|
||||
|
||||
return filter(static fn ($value, $key) => !$fn($value, $key))($input);
|
||||
return static function (iterable $input) use ($fn): iterable {
|
||||
return keyedLike($input, (static function () use ($input, $fn) {
|
||||
foreach ($input as $key => $value) {
|
||||
if (!$fn($value, $key)) {
|
||||
yield $key => $value;
|
||||
}
|
||||
}
|
||||
})());
|
||||
};
|
||||
}
|
||||
|
||||
@ -116,9 +122,9 @@ function reject(callable $fn): \Closure
|
||||
*/
|
||||
function flatMap(callable $fn): \Closure
|
||||
{
|
||||
return static function (iterable $input) use ($fn): iterable {
|
||||
$fn = callback($fn);
|
||||
|
||||
return static function (iterable $input) use ($fn): iterable {
|
||||
return listLike($input, (static function () use ($input, $fn) {
|
||||
foreach ($input as $key => $value) {
|
||||
$result = $fn($value, $key);
|
||||
@ -192,8 +198,9 @@ function unique(): \Closure
|
||||
*/
|
||||
function uniqueBy(callable $selector): \Closure
|
||||
{
|
||||
return static function (iterable $input) use ($selector): iterable {
|
||||
$selector = callback($selector);
|
||||
|
||||
return static function (iterable $input) use ($selector): iterable {
|
||||
$seen = seen();
|
||||
|
||||
return keyedLike($input, (static function () use ($input, $selector, $seen) {
|
||||
@ -219,10 +226,10 @@ function uniqueBy(callable $selector): \Closure
|
||||
*/
|
||||
function sort(?callable $comparator = null): \Closure
|
||||
{
|
||||
return static function (iterable $input) use ($comparator): iterable {
|
||||
// Comparators always take two values, so they are compiled without the ($value, $key) adaptation.
|
||||
$comparator = $comparator === null ? static fn ($a, $b) => $a <=> $b : compile($comparator);
|
||||
|
||||
return static function (iterable $input) use ($comparator): iterable {
|
||||
$entries = entries($input);
|
||||
usort($entries, static fn ($a, $b) => $comparator($a[1], $b[1]));
|
||||
|
||||
@ -245,9 +252,9 @@ function sort(?callable $comparator = null): \Closure
|
||||
*/
|
||||
function sortBy(callable $selector, bool $descending = false): \Closure
|
||||
{
|
||||
return static function (iterable $input) use ($selector, $descending): iterable {
|
||||
$selector = callback($selector);
|
||||
|
||||
return static function (iterable $input) use ($selector, $descending): iterable {
|
||||
$entries = [];
|
||||
foreach ($input as $key => $value) {
|
||||
$entries[] = [$key, $value, $selector($value, $key)];
|
||||
@ -304,6 +311,10 @@ function slice(int $offset, ?int $length = null): \Closure
|
||||
*/
|
||||
function take(int $n): \Closure
|
||||
{
|
||||
if ($n < 0) {
|
||||
throw new \InvalidArgumentException(sprintf('take(): count must be >= 0, got %d', $n));
|
||||
}
|
||||
|
||||
return slice(0, $n);
|
||||
}
|
||||
|
||||
@ -314,6 +325,10 @@ function take(int $n): \Closure
|
||||
*/
|
||||
function skip(int $n): \Closure
|
||||
{
|
||||
if ($n < 0) {
|
||||
throw new \InvalidArgumentException(sprintf('skip(): count must be >= 0, got %d', $n));
|
||||
}
|
||||
|
||||
return slice($n);
|
||||
}
|
||||
|
||||
@ -400,9 +415,9 @@ function merge(iterable $other): \Closure
|
||||
*/
|
||||
function each(callable $fn): \Closure
|
||||
{
|
||||
return static function (iterable $input) use ($fn): iterable {
|
||||
$fn = callback($fn);
|
||||
|
||||
return static function (iterable $input) use ($fn): iterable {
|
||||
$reusable = is_array($input) || $input instanceof \Ds\Seq || $input instanceof \Ds\Map || $input instanceof \Ds\Set;
|
||||
if ($reusable) {
|
||||
foreach ($input as $key => $value) {
|
||||
|
||||
@ -300,6 +300,22 @@ class TransformsTest extends \PHPUnit\Framework\TestCase
|
||||
$this->assertSeq([2, 3], c\skip(1)(self::gen([1, 2, 3])));
|
||||
}
|
||||
|
||||
public function testTakeRejectsNegativeCount()
|
||||
{
|
||||
$this->expectException(\InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('take(): count must be >= 0, got -1');
|
||||
|
||||
c\take(-1);
|
||||
}
|
||||
|
||||
public function testSkipRejectsNegativeCount()
|
||||
{
|
||||
$this->expectException(\InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('skip(): count must be >= 0, got -1');
|
||||
|
||||
c\skip(-1);
|
||||
}
|
||||
|
||||
// prepend / append / concat / merge
|
||||
|
||||
public function testPrepend()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user