dom: speedup HTMLCollection.item() w/ an internal state

This commit is contained in:
Pierre Tachoire
2023-10-27 17:55:53 +02:00
parent 5f05cffff9
commit 055bde96e4
2 changed files with 22 additions and 4 deletions

View File

@@ -83,8 +83,12 @@ pub fn testExecFn(
.{ .src = "let getElementsByTagNameAll = document.getElementsByTagName('*')", .ex = "undefined" },
.{ .src = "getElementsByTagNameAll.length", .ex = "8" },
.{ .src = "getElementsByTagNameAll.item(0).localName", .ex = "html" },
.{ .src = "getElementsByTagNameAll.item(0).localName", .ex = "html" },
.{ .src = "getElementsByTagNameAll.item(1).localName", .ex = "head" },
.{ .src = "getElementsByTagNameAll.item(0).localName", .ex = "html" },
.{ .src = "getElementsByTagNameAll.item(2).localName", .ex = "body" },
.{ .src = "getElementsByTagNameAll.item(3).localName", .ex = "div" },
.{ .src = "getElementsByTagNameAll.item(7).localName", .ex = "p" },
.{ .src = "getElementsByTagNameAll.namedItem('para-empty-child').localName", .ex = "span" },
};
try checkCases(js_env, &getElementsByTagName);

View File

@@ -19,6 +19,10 @@ pub const HTMLCollection = struct {
// match comparison is case insensitive.
match: []const u8,
// save a state for the collection to improve the _item speed.
cur_idx: u32 = undefined,
cur_node: *parser.Node = undefined,
// next iterates hover the DOM tree to return the next following node or
// null at the end.
fn _next(root: *parser.Node, cur: *parser.Node) ?*parser.Node {
@@ -87,12 +91,18 @@ pub const HTMLCollection = struct {
}
pub fn _item(self: *HTMLCollection, index: u32) ?*parser.Element {
var len: u32 = 0;
var i: u32 = 0;
var node: *parser.Node = self.root;
var ntype: parser.NodeType = undefined;
var is_wildcard = std.mem.eql(u8, self.match, "*");
// Use the current state to improve speed if possible.
if (self.cur_idx != undefined and index >= self.cur_idx) {
i = self.cur_idx;
node = self.cur_node;
}
// FIXME using a fixed length buffer here avoid the need of an allocator
// to get an upper case match value. But if the match value (a tag
// name) is greater than 128 chars, the code will panic.
@@ -105,12 +115,16 @@ pub const HTMLCollection = struct {
ntype = parser.nodeType(node);
if (ntype == .element) {
if (is_wildcard or std.mem.eql(u8, imatch, parser.nodeName(node))) {
len += 1;
// check if we found the searched element.
if (len == index + 1) {
if (i == index) {
// save the current state
self.cur_node = node;
self.cur_idx = i;
return @as(*parser.Element, @ptrCast(node));
}
i += 1;
}
}