Skip to content

Commit 0bba733

Browse files
bartbutlerJakeQZ
authored andcommitted
[TASK] Avoid poor scaling of array_search() with very long arrays (#413)
When there were many many elements in `$aStack`, starting the delimiter search from the beginning for each loop iteration was very slow. This is addressed by building a new array, rather than modifying `$aStack` in place, and iterating over it in a single pass. A particular 1.6M style string is now parsed in 5 seconds rather than 4 minutes.
1 parent ef8c59c commit 0bba733

File tree

2 files changed

+15
-6
lines changed

2 files changed

+15
-6
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ This project adheres to [Semantic Versioning](https://semver.org/).
99

1010
### Changed
1111

12+
- Improve performance of Value::parseValue with many delimiters by refactoring to remove array_search()
13+
1214
### Deprecated
1315

1416
### Removed

src/Value/Value.php

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,23 +67,30 @@ public static function parseValue(ParserState $oParserState, array $aListDelimit
6767
}
6868
// Convert the list to list objects
6969
foreach ($aListDelimiters as $sDelimiter) {
70-
if (count($aStack) === 1) {
70+
$iStackLength = count($aStack);
71+
if ($iStackLength === 1) {
7172
return $aStack[0];
7273
}
73-
$iStartPosition = null;
74-
while (($iStartPosition = array_search($sDelimiter, $aStack, true)) !== false) {
74+
$aNewStack = [];
75+
for ($iStartPosition = 0; $iStartPosition < $iStackLength; ++$iStartPosition) {
76+
if ($iStartPosition === ($iStackLength - 1) || $sDelimiter !== $aStack[$iStartPosition + 1]) {
77+
$aNewStack[] = $aStack[$iStartPosition];
78+
continue;
79+
}
7580
$iLength = 2; //Number of elements to be joined
76-
for ($i = $iStartPosition + 2; $i < count($aStack); $i += 2, ++$iLength) {
81+
for ($i = $iStartPosition + 3; $i < $iStackLength; $i += 2, ++$iLength) {
7782
if ($sDelimiter !== $aStack[$i]) {
7883
break;
7984
}
8085
}
8186
$oList = new RuleValueList($sDelimiter, $oParserState->currentLine());
82-
for ($i = $iStartPosition - 1; $i - $iStartPosition + 1 < $iLength * 2; $i += 2) {
87+
for ($i = $iStartPosition; $i - $iStartPosition < $iLength * 2; $i += 2) {
8388
$oList->addListComponent($aStack[$i]);
8489
}
85-
array_splice($aStack, $iStartPosition - 1, $iLength * 2 - 1, [$oList]);
90+
$aNewStack[] = $oList;
91+
$iStartPosition += $iLength * 2 - 2;
8692
}
93+
$aStack = $aNewStack;
8794
}
8895
if (!isset($aStack[0])) {
8996
throw new UnexpectedTokenException(

0 commit comments

Comments
 (0)