From b7030c526fa1f2b5bc331a17b680c55216dec8dd Mon Sep 17 00:00:00 2001 From: jvoisin Date: Sun, 24 May 2026 22:48:16 +0200 Subject: [PATCH] perf: call Match/isInSlice directly in Until traversal helpers getParentsNodes and getSiblingNodes created a newSingleSelection per ancestor/sibling node just to call IsMatcher or IsNodes for the until-stop condition. Since these are always single-node checks, call stopm.Match(p) and isInSlice(stopNodes, p) directly, avoiding the Selection allocation and the method dispatch overhead. name old ns/op new ns/op delta ParentsUntil-8 30700 16100 -47.6% ParentsUntilNodes-8 82700 28400 -65.7% NextUntil-8 38000 25700 -32.4% NextUntilNodes-8 13700 5900 -56.9% PrevUntil-8 109600 82600 -24.6% PrevUntilNodes-8 11600 4600 -60.3% name old B/op new B/op delta ParentsUntil-8 11528 4248 -63.2% ParentsUntilNodes-8 39040 10448 -73.2% NextUntil-8 8592 7712 -10.2% NextUntilNodes-8 5536 1304 -76.4% PrevUntil-8 30344 28280 -6.8% PrevUntilNodes-8 4248 920 -78.3% name old allocs new allocs delta ParentsUntil-8 304 44 -85.5% ParentsUntilNodes-8 904 60 -93.4% NextUntil-8 216 106 -50.9% NextUntilNodes-8 156 27 -82.7% PrevUntil-8 408 150 -63.2% PrevUntilNodes-8 129 23 -82.2% --- traversal.go | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/traversal.go b/traversal.go index c45fa5d..46bac05 100644 --- a/traversal.go +++ b/traversal.go @@ -562,13 +562,12 @@ func findWithMatcher(nodes []*html.Node, m Matcher) []*html.Node { func getParentsNodes(nodes []*html.Node, stopm Matcher, stopNodes []*html.Node) []*html.Node { return mapNodes(nodes, func(i int, n *html.Node) (result []*html.Node) { for p := n.Parent; p != nil; p = p.Parent { - sel := newSingleSelection(p, nil) if stopm != nil { - if sel.IsMatcher(stopm) { + if stopm.Match(p) { break } } else if len(stopNodes) > 0 { - if sel.IsNodes(stopNodes...) { + if isInSlice(stopNodes, p) { break } } @@ -589,13 +588,9 @@ func getSiblingNodes(nodes []*html.Node, st siblingType, untilm Matcher, untilNo if st == siblingNextUntil || st == siblingPrevUntil { f = func(n *html.Node) bool { if untilm != nil { - // Matcher-based condition - sel := newSingleSelection(n, nil) - return sel.IsMatcher(untilm) + return untilm.Match(n) } else if len(untilNodes) > 0 { - // Nodes-based condition - sel := newSingleSelection(n, nil) - return sel.IsNodes(untilNodes...) + return isInSlice(untilNodes, n) } return false }