Skip to content

Commit e7ad3e0

Browse files
committed
Introduce OrderedListInterface::fill
Signed-off-by: Maximilian Bösing <[email protected]>
1 parent d935782 commit e7ad3e0

File tree

3 files changed

+190
-0
lines changed

3 files changed

+190
-0
lines changed

src/OrderedList.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@
55

66
use Webmozart\Assert\Assert;
77
use function array_combine;
8+
use function array_fill;
89
use function array_keys;
910
use function array_map;
1011
use function array_merge;
12+
use function array_replace;
1113
use function array_values;
14+
use function is_callable;
1215
use function serialize;
1316
use function sort;
1417
use const SORT_NATURAL;
@@ -183,4 +186,48 @@ public function unify(
183186

184187
return $instance;
185188
}
189+
190+
public function fill(int $startIndex, int $amount, $value): OrderedListInterface
191+
{
192+
Assert::greaterThanEq($startIndex, 0, 'Given $startIndex must be greater than or equal to %2$s. Got: %s');
193+
Assert::greaterThanEq($amount, 1, 'Given $amount must be greater than or equal to %2$s. Got: %s');
194+
Assert::lessThanEq(
195+
$startIndex,
196+
$this->count(),
197+
'Give $startIndex must be less than or equal to %2$s to keep the list a continious list. Got: %s.'
198+
);
199+
200+
$instance = clone $this;
201+
202+
/** @psalm-var list<TValue> $combined */
203+
$combined = array_replace(
204+
$this->data,
205+
$this->createListFilledWithValues($startIndex, $amount, $value)
206+
);
207+
208+
$instance->data = $combined;
209+
210+
return $instance;
211+
}
212+
213+
/**
214+
* @psalm-param TValue|Closure(int $index):TValue $value
215+
*
216+
* @psalm-return array<int,TValue>
217+
*/
218+
private function createListFilledWithValues(int $start, int $amount, $value): array
219+
{
220+
if (!is_callable($value)) {
221+
/** @psalm-var array<int,TValue> $list */
222+
$list = array_fill($start, $amount, $value);
223+
return $list;
224+
}
225+
226+
$list = [];
227+
for ($index = $start; $index <= $amount; $index++) {
228+
$list[$index] = $value($index);
229+
}
230+
231+
return $list;
232+
}
186233
}

src/OrderedListInterface.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
namespace Boesing\TypedArrays;
55

6+
use InvalidArgumentException;
7+
68
/**
79
* @template TValue
810
* @template-extends ArrayInterface<int,TValue>
@@ -91,4 +93,12 @@ public function unify(
9193
?callable $unificationIdentifierGenerator = null,
9294
?callable $callback = null
9395
): OrderedListInterface;
96+
97+
/**
98+
* @psalm-param TValue|Closure(int $index):TValue $value
99+
* @psalm-return OrderedListInterface<TValue>
100+
* @psalm-immutable
101+
* @throws InvalidArgumentException if start index does is not fitting in the current list state.
102+
*/
103+
public function fill(int $startIndex, int $amount, $value): OrderedListInterface;
94104
}

tests/GenericOrderedListTest.php

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212
use PHPUnit\Framework\TestCase;
1313
use stdClass;
1414
use Webmozart\Assert\Assert;
15+
use function array_fill;
1516
use function chr;
1617
use function md5;
18+
use function mt_rand;
1719
use function spl_object_hash;
1820
use function strnatcmp;
1921

@@ -701,4 +703,135 @@ public function testToMapConversionErrorsOnIntegerishKeys(): void
701703
return (string) $value;
702704
});
703705
}
706+
707+
/**
708+
* @template TValue
709+
* @psalm-param list<TValue> $initial
710+
* @psalm-param TValue $fillUp
711+
* @dataProvider invalidStartIndices
712+
*/
713+
public function testFillWillThrowExceptionWhenStartIndexIsInvalid(
714+
int $startIndex,
715+
array $initial,
716+
$fillUp,
717+
string $expectedExceptionMessage
718+
): void {
719+
$list = new GenericOrderedList($initial);
720+
$this->expectException(InvalidArgumentException::class);
721+
$this->expectExceptionMessage($expectedExceptionMessage);
722+
$list->fill($startIndex, mt_rand(1, 10), $fillUp);
723+
}
724+
725+
/**
726+
* @template TValue
727+
* @psalm-param TValue $value
728+
* @dataProvider scalarFillValues
729+
*/
730+
public function testFillAppendsScalarValues(int $amount, $value): void
731+
{
732+
self::assertIsScalar($value);
733+
/** @var OrderedListInterface<TValue> $list */
734+
$list = new GenericOrderedList([]);
735+
$list = $list->fill(0, $amount, $value);
736+
self::assertEquals(array_fill(0, $amount, $value), $list->toNativeArray());
737+
}
738+
739+
/**
740+
* @template mixed
741+
* @psalm-return Generator<string,array{0:int,1:list<mixed>,2:mixed,3:non-empty-string}>
742+
*/
743+
public function invalidStartIndices(): Generator
744+
{
745+
yield 'negative' => [
746+
-1,
747+
[],
748+
0,
749+
'Given $startIndex must be greater than or equal to',
750+
];
751+
752+
yield 'non continues index' => [
753+
1,
754+
[],
755+
0,
756+
'to keep the list a continious list.',
757+
];
758+
759+
yield 'non continues index #2' => [
760+
10,
761+
[0, 1, 2,],
762+
3,
763+
'to keep the list a continious list.',
764+
];
765+
}
766+
767+
/**
768+
* @psalm-return Generator<string,array{0:int,1:mixed}>
769+
*/
770+
public function scalarFillValues(): Generator
771+
{
772+
yield 'int' => [
773+
1,
774+
0,
775+
];
776+
777+
yield 'string' => [
778+
99,
779+
'foo',
780+
];
781+
782+
yield 'float' => [
783+
10,
784+
0.1,
785+
];
786+
787+
yield 'true' => [
788+
8,
789+
true,
790+
];
791+
792+
yield 'false' => [
793+
50,
794+
false,
795+
];
796+
}
797+
798+
public function testFillUsesCallbackToGenerateValue(): void
799+
{
800+
$callback = static function (int $index): string {
801+
return chr($index + 65);
802+
};
803+
804+
/** @var OrderedListInterface<string> $list */
805+
$abc = new GenericOrderedList([]);
806+
$abc = $abc->fill(0, 25, $callback);
807+
808+
self::assertEquals([
809+
'A',
810+
'B',
811+
'C',
812+
'D',
813+
'E',
814+
'F',
815+
'G',
816+
'H',
817+
'I',
818+
'J',
819+
'K',
820+
'L',
821+
'M',
822+
'N',
823+
'O',
824+
'P',
825+
'Q',
826+
'R',
827+
'S',
828+
'T',
829+
'U',
830+
'V',
831+
'W',
832+
'X',
833+
'Y',
834+
'Z',
835+
], $abc->toNativeArray());
836+
}
704837
}

0 commit comments

Comments
 (0)