perf: presize node-set maps in mapNodes, ClosestNodes and winnowNodes

Three internal helpers build a map[*html.Node]bool from a known set of
nodes (or use one as a dedup accumulator over a known number of input
nodes) but allocate the map without a size hint. They then incur
grow-and-double rehashing as entries are inserted.

Pass len(nodes) as the size hint at make time:

- traversal.go mapNodes: dedup map shared by appendWithoutDuplicates
  across every per-node result. mapNodes is the engine behind most
  traversal helpers (Parents, Children, Next/Prev, Siblings, Find*,
  Contents, ...), so the impact is broad.
- traversal.go ClosestNodes: target-node set built from nodes...
- filter.go winnowNodes: large-N path's lookup set built from nodes...

Double-digit performance gains across ~all benchmarks.
This commit is contained in:
jvoisin
2026-05-27 23:11:36 +02:00
parent e2468fa06d
commit 5f07eebb27
2 changed files with 3 additions and 3 deletions
+1 -1
View File
@@ -149,7 +149,7 @@ func winnowNodes(sel *Selection, nodes []*html.Node, keep bool) []*html.Node {
})
}
set := make(map[*html.Node]bool)
set := make(map[*html.Node]bool, len(nodes))
for _, n := range nodes {
set[n] = true
}
+2 -2
View File
@@ -149,7 +149,7 @@ func (s *Selection) ClosestMatcher(m Matcher) *Selection {
// ClosestNodes gets the first element that matches one of the nodes by testing the
// element itself and traversing up through its ancestors in the DOM tree.
func (s *Selection) ClosestNodes(nodes ...*html.Node) *Selection {
set := make(map[*html.Node]bool)
set := make(map[*html.Node]bool, len(nodes))
for _, n := range nodes {
set[n] = true
}
@@ -689,7 +689,7 @@ func getParentNodes(nodes []*html.Node) []*html.Node {
// Returns an array of nodes mapped by calling the callback function once for
// each node in the source nodes.
func mapNodes(nodes []*html.Node, f func(int, *html.Node) []*html.Node) (result []*html.Node) {
set := make(map[*html.Node]bool)
set := make(map[*html.Node]bool, len(nodes))
for i, n := range nodes {
if vals := f(i, n); len(vals) > 0 {
result = appendWithoutDuplicates(result, vals, set)