Skip to content
Permalink

Comparing changes

This is a direct comparison between two commits made in this repository or its related repositories. View the default comparison for this range or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: azjezz/psl
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: bb05a54ee78a4627c3724c7d961d3fa86fb8b7b9
Choose a base ref
..
head repository: azjezz/psl
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 903a56fa690607db37c294e6c468babec2513fa7
Choose a head ref
6 changes: 4 additions & 2 deletions src/Psl/Collection/Map.php
Original file line number Diff line number Diff line change
@@ -70,13 +70,15 @@ public static function fromArray(array $elements): Map
* @template Tsk of array-key
* @template Tsv
*
* @param array<Tsk, Tsv> $items
* @param iterable<Tsk, Tsv> $items
*
* @return Map<Tsk, Tsv>
*/
public static function fromItems(iterable $items): Map
{
return self::fromArray(iterator_to_array($items));
$items = $items instanceof \Traversable ? iterator_to_array($items) : $items;

return self::fromArray($items);
}

/**
6 changes: 4 additions & 2 deletions src/Psl/Collection/MutableMap.php
Original file line number Diff line number Diff line change
@@ -70,13 +70,15 @@ public static function fromArray(array $elements): MutableMap
* @template Tsk of array-key
* @template Tsv
*
* @param array<Tsk, Tsv> $items
* @param iterable<Tsk, Tsv> $items
*
* @return MutableMap<Tsk, Tsv>
*/
public static function fromItems(iterable $items): MutableMap
{
return self::fromArray(iterator_to_array($items));
$items = $items instanceof \Traversable ? iterator_to_array($items) : $items;

return self::fromArray($items);
}

/**
242 changes: 158 additions & 84 deletions tests/benchmark/Collection/AbstractMapBench.php
Original file line number Diff line number Diff line change
@@ -5,13 +5,12 @@
use PhpBench\Attributes\Groups;
use PhpBench\Attributes\ParamProviders;
use Psl\Collection\MapInterface;
use Psl\Collection\VectorInterface;
use function Psl\Vec\map;

#[Groups(["collection"])]
abstract class AbstractMapBench
{
/**
* @param iterable<array-key, mixed> $data
*/
public function benchFromArray(): void
{
map($this->getDataProviders(), fn ($value) => $this->createFromArray(iterator_to_array($value)));
@@ -22,17 +21,18 @@ public function benchFromIterable(): void
map($this->getDataProviders(), fn ($value) => $this->createFromIterable($value));
}

public function benchmarkValues(): void
public function benchmarkValues(): VectorInterface
{
$map = $this->createFromIterable($this->createAssociativeIterable());
$map->values();
return $this
->createFromIterable($this->createAssociativeIterable())
->values();
}

public function benchmarkKeys(): void
public function benchmarkKeys(): VectorInterface
{
$map = $this->createFromIterable($this->createAssociativeIterable());

$map->keys();
return $this
->createFromIterable($this->createAssociativeIterable())
->keys();
}

public function benchmarkFilter(): void
@@ -44,126 +44,202 @@ public function benchmarkFilter(): void
$map->filter(fn ($v) => $v === 'foo');
}

public function benchmarkMap(): void
public function benchmarkMap(): MapInterface
{
$map = $this->createFromIterable($this->createAssociativeIterable());

$map->map(fn ($v) => $v);
return $this
->createFromIterable($this->createAssociativeIterable())
->map(fn ($v) => $v);
}

public function benchmarkMapWithKey(): void
public function benchmarkMapWithKey(): MapInterface
{
$map = $this->createFromIterable($this->createAssociativeIterable());

$map->mapWithKey(fn ($k, $v) => [$k, $v]);
return $this
->createFromIterable($this->createAssociativeIterable())
->mapWithKey(fn ($k, $v) => [$k, $v]);
}

public function benchmarkFirst(): void
public function benchmarkFirst(): string|null
{
$map = $this->createFromIterable($this->createAssociativeIterable());

$map->first();
return $this
->createFromIterable($this->createAssociativeIterable())
->first();
}

public function benchmarkFirstKey(): void
public function benchmarkFirstKey(): string|null
{
$map = $this->createFromIterable($this->createAssociativeIterable());

$map->firstKey();
return $this
->createFromIterable($this->createAssociativeIterable())
->firstKey();
}

public function benchmarkLast(): void
public function benchmarkLast(): string|null
{
$map = $this->createFromIterable($this->createAssociativeIterable());

$map->last();
return $this
->createFromIterable($this->createAssociativeIterable())
->last();
}

public function benchmarkLastKey(): void
public function benchmarkLastKey(): string|null
{
$map = $this->createFromIterable($this->createAssociativeIterable());

$map->lastKey();
return $this
->createFromIterable($this->createAssociativeIterable())
->lastKey();
}

public function benchmarkLinearSearch(): void
/**
* @param array{value: string} $params
*/
#[ParamProviders('provideLinearSearch')]
public function benchmarkLinearSearch(array $params): string|null
{
$map = $this->createFromIterable($this->createAssociativeIterable());
return $this
->createFromIterable($this->createAssociativeIterable())
->linearSearch($params['value']);
}

$map->linearSearch('a');
$map->linearSearch('k');
$map->linearSearch('lol');
public function provideLinearSearch(): array
{
return [
['value' => 'a'],
['value' => 'k'],
['value' => 'lol'],
];
}

public function benchmarkZip(): void
#[ParamProviders('provideZip')]
public function benchmarkZip(array $data): MapInterface
{
$map = $this->createFromIterable($this->createAssociativeIterable());
return $this
->createFromIterable($this->createAssociativeIterable())
->zip($data);
}

$map->zip([]);
$map->zip(['z', 'y', 'x']);
public function provideZip(): array
{
return [
['value' => []],
['value' => ['z', 'y', 'x']],
];
}

public function benchmarkTake(): void
/**
* @param array{value: int<0, max>} $data
*/
#[ParamProviders('provideTake')]
public function benchmarkTake(array $data): MapInterface
{
$map = $this->createFromIterable($this->createAssociativeIterable());
return $this
->createFromIterable($this->createAssociativeIterable())
->take($data['value']);
}

$map->take(0);
$map->take(1);
$map->take(5);
$map->take(1000);
/**
* @return list<array{value: int<0, max>}>
*/
public function provideTake(): array
{
return [
['value' => 0],
['value' => 1],
['value' => 5],
['value' => 1000],
];
}

public function benchmarkTakeWhile(): void
{
$map = $this->createFromIterable($this->createAssociativeIterable());

$map->takeWhile(fn ($v) => 'a');
$map->takeWhile(fn ($v) => 'k');
$map->takeWhile(fn ($v) => 'rolf');
$map->takeWhile(fn ($v) => true);
$map->takeWhile(fn ($v) => false);
$map->takeWhile(fn ($v) => $v === 'a');
$map->takeWhile(fn ($v) => $v === 'k');
$map->takeWhile(fn ($v) => $v === 'rolf');
$map->takeWhile(fn () => true);
$map->takeWhile(fn () => false);
}

public function benchmarkDrop(): void
/**
* @param array{value: int<0, max>} $data
*/
#[ParamProviders('provideDrop')]
public function benchmarkDrop(array $data): MapInterface
{
$map = $this->createFromIterable($this->createAssociativeIterable());
return $this
->createFromIterable($this->createAssociativeIterable())
->drop($data['value']);
}

$map->drop(0);
$map->drop(1);
$map->drop(8);
$map->drop(1000);
/**
* @return list<array{value: int<0, max>}>
*/
public function provideDrop(): array

{
return [
['value' => 0],
['value' => 1],
['value' => 8],
['value' => 1000],
];
}

public function benchmarkDropWhile(): void
{
$map = $this->createFromIterable($this->createAssociativeIterable());

$map->dropWhile(fn ($v) => 'a');
$map->dropWhile(fn ($v) => 'k');
$map->dropWhile(fn ($v) => 'rolf');
$map->dropWhile(fn ($v) => true);
$map->dropWhile(fn ($v) => false);
$map->dropWhile(fn ($v) => $v === 'a');
$map->dropWhile(fn ($v) => $v === 'k');
$map->dropWhile(fn ($v) => $v === 'rolf');
$map->dropWhile(fn () => true);
$map->dropWhile(fn () => false);
}

public function benchmarkSlice(): void
/**
* @param array{start: int<0, max>, length: int<0, max>} $data
*/
#[ParamProviders('provideSlice')]
public function benchmarkSlice(array $data): MapInterface
{
$map = $this->createFromIterable($this->createAssociativeIterable());
return $this
->createFromIterable($this->createAssociativeIterable())
->slice($data['start'], $data['length']);
}

$map->slice(0, 10);
$map->slice(5, 10);
$map->slice(15, 10);
$map->slice(1000, 100);
/**
* @return list<array{start: int<0, max>, length: int<0, max>}>
*/
public function provideSlice(): array
{
return [
['start' => 0, 'length' => 10],
['start' => 5, 'length' => 10],
['start' => 15, 'length' => 10],
['start' => 1000, 'length' => 100],
];
}

public function benchmarkChunk(): void
/**
* @param array{value: positive-int} $data
*/
#[ParamProviders('provideChunk')]
public function benchmarkChunk(array $data): VectorInterface
{
$map = $this->createFromIterable($this->createAssociativeIterable());
return $this
->createFromIterable($this->createAssociativeIterable())
->chunk($data['value']);
}

$map->chunk(1);
$map->chunk(2);
$map->chunk(3);
$map->chunk(10);
$map->chunk(1000);
/**
* @return list<array{value: positive-int}>
*/
public function provideChunk(): array
{
return [
['value' => 1],
['value' => 2],
['value' => 3],
['value' => 10],
['value' => 1000],
];
}

/**
@@ -187,12 +263,10 @@ public function createEmptyIterable(): iterable
* @template Tk of array-key
* @template Tv
*
* @param iterable<Tk, Tv> $items
*
* @param iterable<Tk, Tv> $items *
* @return MapInterface<Tk, Tv>
*/
abstract protected function createFromIterable(iterable $items): MapInterface;

/**
* @template Tk of array-key
* @template Tv
@@ -204,7 +278,7 @@ abstract protected function createFromIterable(iterable $items): MapInterface;
abstract protected function createFromArray(array $items): MapInterface;

/**
* @return \Generator
* @return \Generator<int, string, void, void>
*/
function createNumericIterable(): \Generator
{
@@ -222,9 +296,9 @@ function createNumericIterable(): \Generator
}

/**
* @return \Generator
* @return \Generator<string, string, void, void>
*/
function createAssociativeIterable(): \Generator
public function createAssociativeIterable(): \Generator
{
yield 'a' => 'a';
yield 'b' => 'b';
17 changes: 16 additions & 1 deletion tests/benchmark/Collection/MapBench.php
Original file line number Diff line number Diff line change
@@ -6,14 +6,29 @@
use Psl\Collection\MapInterface;
use Psl\Collection\Map;

#[Groups(["collection"])]
class MapBench extends AbstractMapBench
{
/**
* @template TKey of array-key
* @template TValue
*
* @param iterable<TKey, TValue> $items
*
* @return MapInterface<TKey, TValue>
*/
protected function createFromIterable(iterable $items): MapInterface
{
return Map::fromItems($items);
}

/**
* @template TKey of array-key
* @template TValue
*
* @param array<TKey, TValue> $items
*
* @return MapInterface<TKey, TValue>
*/
protected function createFromArray(array $items): MapInterface
{
return Map::fromArray($items);
61 changes: 43 additions & 18 deletions tests/benchmark/Collection/MutableMapBench.php
Original file line number Diff line number Diff line change
@@ -6,50 +6,75 @@
use Psl\Collection\MutableMapInterface;
use Psl\Collection\MutableMap;

#[Groups(["collection"])]
class MutableMapBench extends AbstractMapBench
{
public function benchSet(): void
public function benchmarkSet(): void
{
$map = $this->createFromIterable($this->createAssociativeIterable());

// TODO
// $map->set(...);
foreach (\range('a', 'k') as $value) {
$map->set($value, $value);
}
}
public function benchSetAll(): void

public function benchmarkSetAll(): void
{
$map = $this->createFromIterable($this->createAssociativeIterable());

// TODO
// $map->setAll(...);
$map->setAll([
'a' => 'a',
'b' => 'b',
'c' => 'c',
'd' => 'd',
'e' => 'e',
'f' => 'f',
'g' => 'g',
'h' => 'h',
'i' => 'i',
'j' => 'j',
'k' => 'k',
]);
}
public function benchAdd(): void
public function benchmarkAdd(): void
{
$map = $this->createFromIterable($this->createAssociativeIterable());

// TODO
// $map->add(...);
foreach (\range('A', 'Z') as $value) {
$map->add($value, $value);
}
}
public function benchAddAll(): void
public function benchmarkAddAll(): void
{
$map = $this->createFromIterable($this->createAssociativeIterable());

// TODO
// $map->addAll(...);
$map->addAll([
'A' => 'A',
'B' => 'B',
'C' => 'C',
'D' => 'D',
'E' => 'E',
'F' => 'F',
'G' => 'G',
'H' => 'H',
'I' => 'I',
'J' => 'J',
'K' => 'K',
]);
}
public function benchRemove(): void
public function benchmarkRemove(): void
{
$map = $this->createFromIterable($this->createAssociativeIterable());

// TODO
// $map->remove(...);
foreach (\range('a', 'k') as $value) {
$map->remove($value);
}
}
public function benchClear(): void
public function benchmarkClear(): void
{
$map = $this->createFromIterable($this->createAssociativeIterable());

// TODO
// $map->clear(...);
$map->clear();
}

protected function createFromIterable(iterable $items): MutableMapInterface