Skip to content

Commit 5ce491f

Browse files
committed
Optimize repeated parsing of links without closing brace
1 parent 540d850 commit 5ce491f

File tree

1 file changed

+33
-8
lines changed

1 file changed

+33
-8
lines changed

src/Util/LinkParserHelper.php

+33-8
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,7 @@ final class LinkParserHelper
3131
public static function parseLinkDestination(Cursor $cursor): ?string
3232
{
3333
if ($cursor->getCurrentCharacter() === '<') {
34-
if ($res = $cursor->match(RegexHelper::REGEX_LINK_DESTINATION_BRACES)) {
35-
// Chop off surrounding <..>:
36-
return UrlEncoder::unescapeAndEncode(
37-
RegexHelper::unescape(\substr($res, 1, -1))
38-
);
39-
}
40-
41-
return null;
34+
return self::parseDestinationBraces($cursor);
4235
}
4336

4437
$destination = self::manuallyParseLinkDestination($cursor);
@@ -137,4 +130,36 @@ private static function manuallyParseLinkDestination(Cursor $cursor): ?string
137130

138131
return $destination;
139132
}
133+
134+
/** @var \WeakReference<Cursor>|null */
135+
private static ?\WeakReference $lastCursor = null;
136+
private static bool $lastCursorLacksClosingBrace = false;
137+
138+
private static function parseDestinationBraces(Cursor $cursor): ?string
139+
{
140+
// Optimization: If we've previously parsed this cursor and returned `null`, we know
141+
// that no closing brace exists, so we can skip the regex entirely. This helps avoid
142+
// certain pathological cases where the regex engine can take a very long time to
143+
// determine that no match exists.
144+
if (self::$lastCursor !== null && self::$lastCursor->get() === $cursor) {
145+
if (self::$lastCursorLacksClosingBrace) {
146+
return null;
147+
}
148+
} else {
149+
self::$lastCursor = \WeakReference::create($cursor);
150+
}
151+
152+
if ($res = $cursor->match(RegexHelper::REGEX_LINK_DESTINATION_BRACES)) {
153+
self::$lastCursorLacksClosingBrace = false;
154+
155+
// Chop off surrounding <..>:
156+
return UrlEncoder::unescapeAndEncode(
157+
RegexHelper::unescape(\substr($res, 1, -1))
158+
);
159+
}
160+
161+
self::$lastCursorLacksClosingBrace = true;
162+
163+
return null;
164+
}
140165
}

0 commit comments

Comments
 (0)