Improve Tokenizer::scan performance by 98.2%.

- Checking the first character of the opening and closing tags is >90% faster than baseline for my test case.
- Inlining the `tagChange` method is 18% faster than baseline.
- Together they yield a 98.2% wall clock time improvement!

Hat tip to @sam-osborne for the first one :)

https://github.com/mardix/Handlebars/pull/6
This commit is contained in:
Justin Hileman
2019-07-21 16:02:17 -07:00
parent bbb43caa1a
commit 72d07520ec
+21 -22
View File
@@ -72,9 +72,13 @@ class Mustache_Tokenizer
private $tokens; private $tokens;
private $seenTag; private $seenTag;
private $line; private $line;
private $otag; private $otag;
private $ctag; private $otagChar;
private $otagLen; private $otagLen;
private $ctag;
private $ctagChar;
private $ctagLen; private $ctagLen;
/** /**
@@ -111,12 +115,13 @@ class Mustache_Tokenizer
for ($i = 0; $i < $len; $i++) { for ($i = 0; $i < $len; $i++) {
switch ($this->state) { switch ($this->state) {
case self::IN_TEXT: case self::IN_TEXT:
if ($this->tagChange($this->otag, $this->otagLen, $text, $i)) { $char = $text[$i];
// Test whether it's time to change tags.
if ($char === $this->otagChar && substr($text, $i, $this->otagLen) === $this->otag) {
$i--; $i--;
$this->flushBuffer(); $this->flushBuffer();
$this->state = self::IN_TAG_TYPE; $this->state = self::IN_TAG_TYPE;
} else { } else {
$char = $text[$i];
$this->buffer .= $char; $this->buffer .= $char;
if ($char === "\n") { if ($char === "\n") {
$this->flushBuffer(); $this->flushBuffer();
@@ -152,7 +157,9 @@ class Mustache_Tokenizer
break; break;
default: default:
if ($this->tagChange($this->ctag, $this->ctagLen, $text, $i)) { $char = $text[$i];
// Test whether it's time to change tags.
if ($char === $this->ctagChar && substr($text, $i, $this->ctagLen) === $this->ctag) {
$token = array( $token = array(
self::TYPE => $this->tagType, self::TYPE => $this->tagType,
self::NAME => trim($this->buffer), self::NAME => trim($this->buffer),
@@ -197,7 +204,7 @@ class Mustache_Tokenizer
$this->state = self::IN_TEXT; $this->state = self::IN_TEXT;
$this->tokens[] = $token; $this->tokens[] = $token;
} else { } else {
$this->buffer .= $text[$i]; $this->buffer .= $char;
} }
break; break;
} }
@@ -226,9 +233,13 @@ class Mustache_Tokenizer
$this->tokens = array(); $this->tokens = array();
$this->seenTag = false; $this->seenTag = false;
$this->line = 0; $this->line = 0;
$this->otag = '{{'; $this->otag = '{{';
$this->ctag = '}}'; $this->otagChar = '{';
$this->otagLen = 2; $this->otagLen = 2;
$this->ctag = '}}';
$this->ctagChar = '}';
$this->ctagLen = 2; $this->ctagLen = 2;
} }
@@ -295,8 +306,11 @@ class Mustache_Tokenizer
list($_, $otag, $ctag) = $matches; list($_, $otag, $ctag) = $matches;
$this->otag = $otag; $this->otag = $otag;
$this->ctag = $ctag; $this->otagChar = $otag[0];
$this->otagLen = strlen($otag); $this->otagLen = strlen($otag);
$this->ctag = $ctag;
$this->ctagChar = $ctag[0];
$this->ctagLen = strlen($ctag); $this->ctagLen = strlen($ctag);
} }
@@ -325,19 +339,4 @@ class Mustache_Tokenizer
return $end + $this->ctagLen - 1; return $end + $this->ctagLen - 1;
} }
/**
* Test whether it's time to change tags.
*
* @param string $tag Current tag name
* @param int $tagLen Current tag name length
* @param string $text Mustache template source
* @param int $index Current tokenizer index
*
* @return bool True if this is a closing section tag
*/
private function tagChange($tag, $tagLen, $text, $index)
{
return substr($text, $index, $tagLen) === $tag;
}
} }