From 0bba733982b2db2b50ec682d61ed35d6142cbc50 Mon Sep 17 00:00:00 2001 From: Bart Butler Date: Mon, 26 Feb 2024 20:21:27 +0100 Subject: [PATCH 1/2] [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. --- CHANGELOG.md | 2 ++ src/Value/Value.php | 19 +++++++++++++------ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 86ceb2ca..a2db5eaa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). ### Changed +- Improve performance of Value::parseValue with many delimiters by refactoring to remove array_search() + ### Deprecated ### Removed diff --git a/src/Value/Value.php b/src/Value/Value.php index ce6d5790..6be2110c 100644 --- a/src/Value/Value.php +++ b/src/Value/Value.php @@ -67,23 +67,30 @@ public static function parseValue(ParserState $oParserState, array $aListDelimit } // Convert the list to list objects foreach ($aListDelimiters as $sDelimiter) { - if (count($aStack) === 1) { + $iStackLength = count($aStack); + if ($iStackLength === 1) { return $aStack[0]; } - $iStartPosition = null; - while (($iStartPosition = array_search($sDelimiter, $aStack, true)) !== false) { + $aNewStack = []; + for ($iStartPosition = 0; $iStartPosition < $iStackLength; ++$iStartPosition) { + if ($iStartPosition === ($iStackLength - 1) || $sDelimiter !== $aStack[$iStartPosition + 1]) { + $aNewStack[] = $aStack[$iStartPosition]; + continue; + } $iLength = 2; //Number of elements to be joined - for ($i = $iStartPosition + 2; $i < count($aStack); $i += 2, ++$iLength) { + for ($i = $iStartPosition + 3; $i < $iStackLength; $i += 2, ++$iLength) { if ($sDelimiter !== $aStack[$i]) { break; } } $oList = new RuleValueList($sDelimiter, $oParserState->currentLine()); - for ($i = $iStartPosition - 1; $i - $iStartPosition + 1 < $iLength * 2; $i += 2) { + for ($i = $iStartPosition; $i - $iStartPosition < $iLength * 2; $i += 2) { $oList->addListComponent($aStack[$i]); } - array_splice($aStack, $iStartPosition - 1, $iLength * 2 - 1, [$oList]); + $aNewStack[] = $oList; + $iStartPosition += $iLength * 2 - 2; } + $aStack = $aNewStack; } if (!isset($aStack[0])) { throw new UnexpectedTokenException( From 1d70d5cb23e18be6dd3b4df9c34fb8a906854e28 Mon Sep 17 00:00:00 2001 From: JakeQZ Date: Fri, 28 Jun 2024 22:52:15 +0100 Subject: [PATCH 2/2] [CLEANUP] Add missing PR number to changelog (#626) (#413) --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a2db5eaa..9bc570bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). ### Changed -- Improve performance of Value::parseValue with many delimiters by refactoring to remove array_search() +- Improve performance of Value::parseValue with many delimiters by refactoring to remove array_search() (#413) ### Deprecated