Browse Source

Speed up the open elements stack

split-manual
J. King 3 years ago
parent
commit
8031648e03
  1. 4
      lib/Data.php
  2. 102
      lib/OpenElementsStack.php
  3. 2
      lib/Stack.php

4
lib/Data.php

@ -245,11 +245,9 @@ class Data {
break;
}
}
if (!$advancePointer && $count) {
$this->data->seek(-($this->data->posChar - $start));
$this->data->seek(-($this->data->posChar() - $start));
}
return $string;
}

102
lib/OpenElementsStack.php

@ -85,7 +85,20 @@ class OpenElementsStack extends Stack {
],
];
protected $fragmentContext;
/** @var ?\dW\HTML5\Element */
protected $fragmentContext = null;
/** @var ?\dW\HTML5\Element */
public $currentNode = null;
/** @var ?string */
public $currentNodeName = null;
/** @var ?string */
public $currentNodeNamespace = null;
/** @var ?\dW\HTML5\Element */
public $adjustedCurrentNode = null;
/** @var ?string */
public $adjustedCurrentNodeName = null;
/** @var ?string */
public $adjustedCurrentNodeNamespace = null;
public function __construct(?Element $fragmentContext = null) {
// If the fragment context is not null and is not a document fragment, document,
@ -96,26 +109,52 @@ class OpenElementsStack extends Stack {
$this->fragmentContext = $fragmentContext;
}
public function pop() {
$out = array_pop($this->_storage);
$this->computeProperties();
return $out;
}
public function offsetSet($offset, $value) {
assert($offset >= 0, new Exception(Exception::STACK_INVALID_INDEX, $offset));
if (is_null($offset)) {
$this->_storage[] = $value;
} else {
$this->_storage[$offset] = $value;
}
$this->computeProperties();
}
public function offsetUnset($offset) {
assert($offset >= 0 && $offset < count($this->_storage), new Exception(Exception::STACK_INVALID_INDEX, $offset));
array_splice($this->_storage, $offset, 1, []);
$this->computeProperties();
}
public function insert(Element $element, ?int $at = null): void {
assert($at === null || ($at >= 0 && $at <= count($this->_storage)), new \Exception("Invalid stack index $at"));
if ($at === null) {
$this[] = $element;
} else {
array_splice($this->_storage, $at, 0, [$element]);
$this->computeProperties();
}
}
public function popUntil(string ...$target): void {
do {
$node = $this->pop();
$node = array_pop($this->_storage);
assert(isset($node), new \Exception("Stack is empty"));
} while ($node->namespaceURI !== null || !in_array($node->nodeName, $target));
$this->computeProperties();
}
public function popUntilSame(Element $target): void {
do {
$node = $this->pop();
$node = array_pop($this->_storage);
} while (!$node->isSameNode($target));
$this->computeProperties();
}
public function find(string ...$name): int {
@ -165,8 +204,9 @@ class OpenElementsStack extends Stack {
$map[$name] = false;
}
while (!$this->isEmpty() && $this->top()->namespaceURI === null && ($map[$this->top()->nodeName] ?? false)) {
$this->pop();
array_pop($this->_storage);
}
$this->computeProperties();
}
public function generateImpliedEndTagsThoroughly(): void {
@ -174,8 +214,9 @@ class OpenElementsStack extends Stack {
# thoroughly, then, while the current node is {elided list of element names},
# the UA must pop the current node off the stack of open elements.
while (!$this->isEmpty() && $this->top()->namespaceURI === null && (self::IMPLIED_END_TAGS_THOROUGH[$this->top()->nodeName] ?? false)) {
$this->pop();
array_pop($this->_storage);
}
$this->computeProperties();
}
public function clearToTableContext(): void {
@ -190,6 +231,7 @@ class OpenElementsStack extends Stack {
while (sizeof($this->_storage) > $stop) {
array_pop($this->_storage);
}
$this->computeProperties();
}
public function clearToTableBodyContext(): void {
@ -204,6 +246,7 @@ class OpenElementsStack extends Stack {
while (sizeof($this->_storage) > $stop) {
array_pop($this->_storage);
}
$this->computeProperties();
}
public function clearToTableRowContext(): void {
@ -218,6 +261,7 @@ class OpenElementsStack extends Stack {
while (sizeof($this->_storage) > $stop) {
array_pop($this->_storage);
}
$this->computeProperties();
}
public function hasElementInScope(...$target): bool {
@ -286,30 +330,30 @@ class OpenElementsStack extends Stack {
assert(false, new \Exception("Stack is invalid: ".(string) $this));
}
public function __get($property) {
switch ($property) {
case 'adjustedCurrentNode':
# The adjusted current node is the context element if the parser was created by
# the HTML fragment parsing algorithm and the stack of open elements has only one
# element in it (fragment case); otherwise, the adjusted current node is the
# current node.
return ($this->fragmentContext && count($this->_storage) === 1) ? $this->fragmentContext : $this->__get('currentNode');
case 'adjustedCurrentNodeName':
$adjustedCurrentNode = $this->__get('adjustedCurrentNode');
return (!is_null($adjustedCurrentNode)) ? $adjustedCurrentNode->nodeName : null;
case 'adjustedCurrentNodeNamespace':
$adjustedCurrentNode = $this->__get('adjustedCurrentNode');
return (!is_null($adjustedCurrentNode)) ? $adjustedCurrentNode->namespaceURI: null;
case 'currentNode':
return $this->top();
case 'currentNodeName':
$currentNode = $this->__get('currentNode');
return ($currentNode && $currentNode->nodeType) ? $currentNode->nodeName : null;
case 'currentNodeNamespace':
$currentNode = $this->__get('currentNode');
return (!is_null($currentNode)) ? $currentNode->namespaceURI: null;
default:
return null;
protected function computeProperties(): void {
$this->currentNode = $this->top();
# The adjusted current node is the context element if the parser was created by
# the HTML fragment parsing algorithm and the stack of open elements has only one
# element in it (fragment case); otherwise, the adjusted current node is the
# current node.
if ($this->fragmentContext && sizeof($this->_storage) === 1) {
$this->adjustedCurrentNode = $this->fragmentContext;
} else {
$this->adjustedCurrentNode = $this->currentNode;
}
if ($this->currentNode) {
$this->currentNodeName = $this->currentNode->nodeName;
$this->currentNodeNamespace = $this->currentNode->namespaceURI;
} else {
$this->currentNodeName = null;
$this->currentNodeNamespace = null;
}
if ($this->adjustedCurrentNode) {
$this->adjustedCurrentNodeName = $this->adjustedCurrentNode->nodeName;
$this->adjustedCurrentNodeNamespace = $this->adjustedCurrentNode->namespaceURI;
} else {
$this->adjustedCurrentNodeName = null;
$this->adjustedCurrentNodeNamespace = null;
}
}

2
lib/Stack.php

@ -4,8 +4,6 @@ namespace dW\HTML5;
abstract class Stack implements \ArrayAccess, \Countable, \IteratorAggregate {
protected $_storage = [];
protected $fragmentCase;
protected $fragmentContext;
public function offsetSet($offset, $value) {
assert($offset >= 0, new Exception(Exception::STACK_INVALID_INDEX, $offset));

Loading…
Cancel
Save