| @@ -22,15 +22,16 @@ | ||
| 22 | 22 | * @internal |
| 23 | 23 | */ |
| 24 | 24 | class Reader |
| 25 | 25 | { |
| 26 | - private string $source; | |
| 26 | + private static array $anchoredPatterns = []; | |
| 27 | + | |
| 27 | 28 | private int $length; |
| 28 | 29 | private int $position = 0; |
| 29 | 30 | |
| 30 | - public function __construct(string $source) | |
| 31 | - { | |
| 32 | - $this->source = $source; | |
| 31 | + public function __construct( | |
| 32 | + private string $source, | |
| 33 | + ) { | |
| 33 | 34 | $this->length = \strlen($source); |
| 34 | 35 | } |
| 35 | 36 | |
| 36 | 37 | public function isEOF(): bool |
| @@ -52,12 +53,9 @@ | ||
| 52 | 53 | { |
| 53 | 54 | return substr($this->source, $this->position + $offset, $length); |
| 54 | 55 | } |
| 55 | 56 | |
| 56 | - /** | |
| 57 | - * @return int|false | |
| 58 | - */ | |
| 59 | - public function getOffset(string $string): int|bool | |
| 57 | + public function getOffset(string $string): int|false | |
| 60 | 58 | { |
| 61 | 59 | $position = strpos($this->source, $string, $this->position); |
| 62 | 60 | |
| 63 | 61 | return false === $position ? false : $position - $this->position; |
| @@ -64,11 +62,14 @@ | ||
| 64 | 62 | } |
| 65 | 63 | |
| 66 | 64 | public function findPattern(string $pattern): array|false |
| 67 | 65 | { |
| 68 | - $source = substr($this->source, $this->position); | |
| 66 | + // Match in place instead of copying the remaining source before every probe. | |
| 67 | + // Combined with an offset, "^" still anchors at the start of the whole subject, | |
| 68 | + // so a leading anchor is turned into "\\G", which anchors at the offset instead. | |
| 69 | + $pattern = self::$anchoredPatterns[$pattern] ??= '^' === ($pattern[1] ?? '') ? $pattern[0].'\\G'.substr($pattern, 2) : $pattern; | |
| 69 | 70 | |
| 70 | - if (preg_match($pattern, $source, $matches)) { | |
| 71 | + if (preg_match($pattern, $this->source, $matches, 0, $this->position)) { | |
| 71 | 72 | return $matches; |
| 72 | 73 | } |
| 73 | 74 | |
| 74 | 75 | return false; |