Skip to content

Commit 094af3d

Browse files
herndlmondrejmirtes
authored andcommitted
Extract generic variants of ConstantArray removeFirst and removeLast
1 parent d3589dc commit 094af3d

File tree

1 file changed

+54
-24
lines changed

1 file changed

+54
-24
lines changed

src/Type/Constant/ConstantArrayType.php

Lines changed: 54 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -549,32 +549,48 @@ public function isIterableAtLeastOnce(): TrinaryLogic
549549

550550
public function removeLast(): self
551551
{
552-
if (count($this->keyTypes) === 0) {
552+
return $this->removeLastElements(1);
553+
}
554+
555+
/** @param positive-int $length */
556+
private function removeLastElements(int $length): self
557+
{
558+
$keyTypesCount = count($this->keyTypes);
559+
if ($keyTypesCount === 0) {
553560
return $this;
554561
}
555562

556-
$i = count($this->keyTypes) - 1;
557-
558563
$keyTypes = $this->keyTypes;
559564
$valueTypes = $this->valueTypes;
560565
$optionalKeys = $this->optionalKeys;
566+
$nextAutoindex = $this->nextAutoIndexes;
561567

562-
if ($this->isOptionalKey($i)) {
563-
unset($optionalKeys[$i]);
564-
// Removing the last optional element makes the previous non-optional element optional
565-
for ($j = $i - 1; $j >= 0; $j--) {
566-
if (!$this->isOptionalKey($j)) {
567-
$optionalKeys[] = $j;
568-
break;
568+
$optionalKeysRemoved = 0;
569+
$newLength = $keyTypesCount - $length;
570+
for ($i = $keyTypesCount - 1; $i >= 0; $i--) {
571+
$isOptional = $this->isOptionalKey($i);
572+
573+
if ($i >= $newLength) {
574+
if ($isOptional) {
575+
$optionalKeysRemoved++;
576+
unset($optionalKeys[$i]);
569577
}
578+
579+
$removedKeyType = array_pop($keyTypes);
580+
array_pop($valueTypes);
581+
$nextAutoindex = $removedKeyType instanceof ConstantIntegerType
582+
? $removedKeyType->getValue()
583+
: $this->getNextAutoIndex(); // @phpstan-ignore-line
584+
continue;
585+
}
586+
587+
if ($isOptional || $optionalKeysRemoved <= 0) {
588+
continue;
570589
}
571-
}
572590

573-
$removedKeyType = array_pop($keyTypes);
574-
array_pop($valueTypes);
575-
$nextAutoindex = $removedKeyType instanceof ConstantIntegerType
576-
? $removedKeyType->getValue()
577-
: $this->getNextAutoIndex(); // @phpstan-ignore-line
591+
$optionalKeys[] = $i;
592+
$optionalKeysRemoved--;
593+
}
578594

579595
return new self(
580596
$keyTypes,
@@ -584,31 +600,45 @@ public function removeLast(): self
584600
);
585601
}
586602

587-
public function removeFirst(): Type
603+
public function removeFirst(): self
604+
{
605+
return $this->removeFirstElements(1);
606+
}
607+
608+
/** @param positive-int $length */
609+
private function removeFirstElements(int $length, bool $reindex = true): self
588610
{
589611
$builder = ConstantArrayTypeBuilder::createEmpty();
590-
$makeNextNonOptionalOptional = false;
612+
613+
$optionalKeysIgnored = 0;
591614
foreach ($this->keyTypes as $i => $keyType) {
592615
$isOptional = $this->isOptionalKey($i);
593-
if ($i === 0) {
594-
$makeNextNonOptionalOptional = $isOptional;
616+
if ($i <= $length - 1) {
617+
if ($isOptional) {
618+
$optionalKeysIgnored++;
619+
}
595620
continue;
596621
}
597622

598-
if (!$isOptional && $makeNextNonOptionalOptional) {
623+
if (!$isOptional && $optionalKeysIgnored > 0) {
599624
$isOptional = true;
600-
$makeNextNonOptionalOptional = false;
625+
$optionalKeysIgnored--;
601626
}
602627

603628
$valueType = $this->valueTypes[$i];
604-
if ($keyType instanceof ConstantIntegerType) {
629+
if ($reindex && $keyType instanceof ConstantIntegerType) {
605630
$keyType = null;
606631
}
607632

608633
$builder->setOffsetValueType($keyType, $valueType, $isOptional);
609634
}
610635

611-
return $builder->getArray();
636+
$array = $builder->getArray();
637+
if (!$array instanceof self) {
638+
throw new ShouldNotHappenException();
639+
}
640+
641+
return $array;
612642
}
613643

614644
public function slice(int $offset, ?int $limit, bool $preserveKeys = false): self

0 commit comments

Comments
 (0)