Skip to content

perf: scan adjacent element directly in Next/Prev sibling traversal#573

Open
jvoisin wants to merge 1 commit into
PuerkitoBio:masterfrom
jvoisin:cyber
Open

perf: scan adjacent element directly in Next/Prev sibling traversal#573
jvoisin wants to merge 1 commit into
PuerkitoBio:masterfrom
jvoisin:cyber

Conversation

@jvoisin

@jvoisin jvoisin commented May 31, 2026

Copy link
Copy Markdown
Contributor

Next() and Prev() request a single sibling per source node, and distinct source nodes always have distinct immediate siblings, so the results can never contain duplicates. Routing them through mapNodes (which allocates a dedup map and a throwaway one-element slice per node) and the general getChildrenWithSiblingType iterator is suboptimal.

This commit adds a dedicated fast path in getSiblingNodes that scans straight to the adjacent element node and appends into a presized slice, skipping the dedup map and the iterator closure entirely.

benchstat (count=10, all p=0.000):

              |   old    |           new            |
              |  allocs  |  allocs   vs base        |
Next-8        |   60.00  |  2.000    -96.67%        |
Prev-8        |   60.00  |  2.000    -96.67%        |
NextFiltered-8|   65.00  |  7.000    -89.23%        |
PrevFiltered-8|   65.00  |  7.000    -89.23%        |

sec/op:  Next -89%, Prev -92%, Filtered variants -72%
B/op:    ~-80%

Next() and Prev() request a single sibling per source node, and distinct
source nodes always have distinct immediate siblings, so the results can
never contain duplicates. Routing them through mapNodes (which allocates a
dedup map and a throwaway one-element slice per node) and the general
getChildrenWithSiblingType iterator is suboptimal.

This commit adds a dedicated fast path in getSiblingNodes that scans straight
to the adjacent element node and appends into a presized slice, skipping the
dedup map and the iterator closure entirely.

benchstat (count=10, all p=0.000):

                  |   old    |           new            |
                  |  allocs  |  allocs   vs base        |
    Next-8        |   60.00  |  2.000    -96.67%        |
    Prev-8        |   60.00  |  2.000    -96.67%        |
    NextFiltered-8|   65.00  |  7.000    -89.23%        |
    PrevFiltered-8|   65.00  |  7.000    -89.23%        |

    sec/op:  Next -89%, Prev -92%, Filtered variants -72%
    B/op:    ~-80%
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant