PureXML/Sources/XPath
Mihaela Mihaljevic b104723fed
perf(xpath): cache and fuse the following-sibling/preceding-sibling axes (#306)
siblingPosition(of:) located the context node with
parent.children.firstIndex { $0 === tree } on every call: a linear scan of the
parent's child list, independent of the result. Over a wide parent evaluated
from many context siblings (//x/following-sibling::y) that scan was quadratic,
and the axes then materialized every sibling before the node test filtered it.

Look the index up through the shared per-evaluation SiblingIndexCache (O(1)
after the per-parent table is built), and fuse the step's node test into the
walk so a rejected sibling is never wrapped (the same fusion the descendant and
following/preceding axes use). The selected siblings and their order are
unchanged.

The gratuitous per-context scan and the non-match wrapping are gone (the
remaining per-context iteration over the siblings is inherent to the axis); a
wide-parent following-sibling query is ~1.2-1.6x faster. The full suite, the
W3C XPath/XSLT and Apache Xalan corpora, and the WASM build stay green;
SiblingAxisTests pins the fused node test and document order.
2026-06-25 22:41:32 +02:00
..
Axis.swift perf(xpath): skip the document-order sort for an already-ordered single step (#283) 2026-06-25 05:04:00 +02:00
AxisNavigation.swift perf(xpath): cache and fuse the following-sibling/preceding-sibling axes (#306) 2026-06-25 22:41:32 +02:00
Budget.swift
Compiler.swift
CompilerDescendantFusion.swift perf(xpath): fuse // into a descendant step for non-positional predicates (#281) 2026-06-25 03:21:03 +02:00
CompilerPaths.swift perf(xpath): fuse // into a descendant step for non-positional predicates (#281) 2026-06-25 03:21:03 +02:00
CoreFunctions.swift
EvaluationContext.swift perf(xpath): cache and fuse the following-sibling/preceding-sibling axes (#306) 2026-06-25 22:41:32 +02:00
Evaluator.swift perf(xpath): skip the document-order sort for an already-ordered single step (#283) 2026-06-25 05:04:00 +02:00
EvaluatorOperators.swift
EvaluatorSteps.swift perf(xpath): cache and fuse the following-sibling/preceding-sibling axes (#306) 2026-06-25 22:41:32 +02:00
Expression.swift
EXSLTFunctions.swift fix(xslt): make key(), id(), and EXSLT set functions linear over wide fan-outs (#300) 2026-06-25 18:45:08 +02:00
NodeFunctions.swift
NodeTest.swift
Query.swift
QueryError.swift
Selection.swift
SiblingIndexCache.swift fix(xpath): cache the attribute index for document-order keys (#305) 2026-06-25 22:01:13 +02:00
Step.swift
StringFunctions.swift
Value.swift
XPathNode.swift fix(xpath): cache the attribute index for document-order keys (#305) 2026-06-25 22:01:13 +02:00