XPath: Optimize [position()=expr] and [last()]

To get more benefits from constant predicate/filter optimization we rewrite
[position()=expr] predicates into [expr] for numeric expressions. Right now
the rewrite is only for entire expressions - it may be beneficial to split
complex expressions like [position()=constant and expr] into [constant][expr]
but that is more complicated.

last() does not depend on the node set contents so is "constant" as far as
our optimization is concerned so we can evaluate it once.
This commit is contained in:
Arseny Kapoulkine 2014-10-27 18:50:09 -07:00
parent dbfe85a717
commit c64d4820b1
2 changed files with 17 additions and 1 deletions

View file

@ -9765,6 +9765,14 @@ PUGI__NS_BEGIN
if (_right) _right->optimize(alloc);
if (_next) _next->optimize(alloc);
// Rewrite [position()=expr] with [expr]
// Note that this step has to go before classification to recognize [position()=1]
if ((_type == ast_filter || _type == ast_predicate) &&
_right->_type == ast_op_equal && _right->_left->_type == ast_func_position && _right->_right->_rettype == xpath_type_number)
{
_right = _right->_right;
}
// Classify filter/predicate ops to perform various optimizations during evaluation
if (_type == ast_filter || _type == ast_predicate)
{
@ -9772,7 +9780,7 @@ PUGI__NS_BEGIN
if (_right->_type == ast_number_constant && _right->_data.number == 1.0)
_test = predicate_constant_one;
else if (_right->_rettype == xpath_type_number && (_right->_type == ast_number_constant || _right->_type == ast_variable))
else if (_right->_rettype == xpath_type_number && (_right->_type == ast_number_constant || _right->_type == ast_variable || _right->_type == ast_func_last))
_test = predicate_constant;
else if (_right->_rettype != xpath_type_number && _right->is_posinv_expr())
_test = predicate_posinv;

View file

@ -475,6 +475,14 @@ TEST_XML(xpath_paths_predicate_constant_boolean, "<node><chapter/><chapter/><cha
CHECK_XPATH_NODESET_VAR(n, STR("following-sibling::chapter[$true]"), &set) % 6 % 7;
}
TEST_XML(xpath_paths_predicate_position_eq, "<node><chapter/><chapter/><chapter>3</chapter><chapter/><chapter/></node>")
{
CHECK_XPATH_NODESET(doc, STR("node/chapter[position()=1]")) % 3;
CHECK_XPATH_NODESET(doc, STR("node/chapter[position()=2+2]")) % 7;
CHECK_XPATH_NODESET(doc, STR("node/chapter[position()=last()]")) % 8;
CHECK_XPATH_NODESET(doc, STR("node/chapter[position()=string()]")) % 5;
}
TEST_XML(xpath_paths_predicate_several, "<node><employee/><employee secretary=''/><employee assistant=''/><employee secretary='' assistant=''/><employee assistant='' secretary=''/></node>")
{
xml_node n = doc.child(STR("node"));