XPath refactoring (ast_filter/filter_posinv/predicates use the same function, removed greater* specializations for compare_rel, starts_with is used more extensively, const-correctness fixes)

git-svn-id: http://pugixml.googlecode.com/svn/trunk@425 99668b35-9821-0410-8761-19e4c4f06640
This commit is contained in:
arseny.kapoulkine 2010-05-17 06:54:06 +00:00
parent 8b50d8c567
commit 31c4cb2d8b
2 changed files with 32 additions and 86 deletions

View File

@ -93,9 +93,15 @@ namespace
#endif #endif
} }
bool starts_with(const string_t& s, const char_t* pattern) bool starts_with(const char_t* string, const char_t* pattern)
{ {
return s.compare(0, impl::strlen(pattern), pattern) == 0; while (*pattern && *string == *pattern)
{
string++;
pattern++;
}
return *pattern == 0;
} }
const char_t* find_char(const char_t* s, char_t c) const char_t* find_char(const char_t* s, char_t c)
@ -513,14 +519,6 @@ namespace
} }
}; };
template <class T> struct greater
{
bool operator()(const T& lhs, const T& rhs) const
{
return lhs > rhs;
}
};
template <class T> struct less template <class T> struct less
{ {
bool operator()(const T& lhs, const T& rhs) const bool operator()(const T& lhs, const T& rhs) const
@ -529,14 +527,6 @@ namespace
} }
}; };
template <class T> struct greater_equal
{
bool operator()(const T& lhs, const T& rhs) const
{
return lhs >= rhs;
}
};
template <class T> struct less_equal template <class T> struct less_equal
{ {
bool operator()(const T& lhs, const T& rhs) const bool operator()(const T& lhs, const T& rhs) const
@ -1308,7 +1298,7 @@ namespace pugi
template <class Cbool, class Cdouble, class Cstring> struct compare_eq template <class Cbool, class Cdouble, class Cstring> struct compare_eq
{ {
static bool run(xpath_ast_node* lhs, xpath_ast_node* rhs, xpath_context& c) static bool run(xpath_ast_node* lhs, xpath_ast_node* rhs, const xpath_context& c)
{ {
if (lhs->rettype() != xpath_type_node_set && rhs->rettype() != xpath_type_node_set) if (lhs->rettype() != xpath_type_node_set && rhs->rettype() != xpath_type_node_set)
{ {
@ -1403,7 +1393,7 @@ namespace pugi
template <class Cdouble> struct compare_rel template <class Cdouble> struct compare_rel
{ {
static bool run(xpath_ast_node* lhs, xpath_ast_node* rhs, xpath_context& c) static bool run(xpath_ast_node* lhs, xpath_ast_node* rhs, const xpath_context& c)
{ {
if (lhs->rettype() != xpath_type_node_set && rhs->rettype() != xpath_type_node_set) if (lhs->rettype() != xpath_type_node_set && rhs->rettype() != xpath_type_node_set)
return Cdouble()(lhs->eval_number(c), rhs->eval_number(c)); return Cdouble()(lhs->eval_number(c), rhs->eval_number(c));
@ -1504,7 +1494,7 @@ namespace pugi
// There are no attribute nodes corresponding to attributes that declare namespaces // There are no attribute nodes corresponding to attributes that declare namespaces
// That is, "xmlns:..." or "xmlns" // That is, "xmlns:..." or "xmlns"
if (impl::strequalrange(a.name(), PUGIXML_TEXT("xmlns"), 5) && (a.name()[5] == 0 || a.name()[5] == ':')) return; if (starts_with(a.name(), PUGIXML_TEXT("xmlns")) && (a.name()[5] == 0 || a.name()[5] == ':')) return;
switch (m_test) switch (m_test)
{ {
@ -1518,7 +1508,7 @@ namespace pugi
break; break;
case nodetest_all_in_namespace: case nodetest_all_in_namespace:
if (impl::strequalrange(a.name(), m_contents, impl::strlen(m_contents))) if (starts_with(a.name(), m_contents))
ns.push_back(xpath_node(a, parent)); ns.push_back(xpath_node(a, parent));
break; break;
@ -1567,7 +1557,7 @@ namespace pugi
break; break;
case nodetest_all_in_namespace: case nodetest_all_in_namespace:
if (n.type() == node_element && impl::strequalrange(n.name(), m_contents, impl::strlen(m_contents))) if (n.type() == node_element && starts_with(n.name(), m_contents))
ns.push_back(n); ns.push_back(n);
break; break;
@ -1791,7 +1781,7 @@ namespace pugi
} }
} }
template <class T> void step_do(xpath_node_set& ns, xpath_context& c, T v) template <class T> void step_do(xpath_node_set& ns, const xpath_context& c, T v)
{ {
const axis_t axis = T::axis; const axis_t axis = T::axis;
@ -1971,7 +1961,7 @@ namespace pugi
m_right = value; m_right = value;
} }
bool eval_boolean(xpath_context& c) bool eval_boolean(const xpath_context& c)
{ {
switch (m_type) switch (m_type)
{ {
@ -1993,16 +1983,16 @@ namespace pugi
return compare_rel<less<double> >::run(m_left, m_right, c); return compare_rel<less<double> >::run(m_left, m_right, c);
case ast_op_greater: case ast_op_greater:
return compare_rel<greater<double> >::run(m_left, m_right, c); return compare_rel<less<double> >::run(m_right, m_left, c);
case ast_op_less_or_equal: case ast_op_less_or_equal:
return compare_rel<less_equal<double> >::run(m_left, m_right, c); return compare_rel<less_equal<double> >::run(m_left, m_right, c);
case ast_op_greater_or_equal: case ast_op_greater_or_equal:
return compare_rel<greater_equal<double> >::run(m_left, m_right, c); return compare_rel<less_equal<double> >::run(m_right, m_left, c);
case ast_func_starts_with: case ast_func_starts_with:
return starts_with(m_left->eval_string(c), m_right->eval_string(c).c_str()); return starts_with(m_left->eval_string(c).c_str(), m_right->eval_string(c).c_str());
case ast_func_contains: case ast_func_contains:
{ {
@ -2073,7 +2063,7 @@ namespace pugi
} }
} }
double eval_number(xpath_context& c) double eval_number(const xpath_context& c)
{ {
switch (m_type) switch (m_type)
{ {
@ -2171,7 +2161,7 @@ namespace pugi
} }
} }
string_t eval_string(xpath_context& c) string_t eval_string(const xpath_context& c)
{ {
switch (m_type) switch (m_type)
{ {
@ -2373,7 +2363,7 @@ namespace pugi
} }
} }
xpath_node_set eval_node_set(xpath_context& c) xpath_node_set eval_node_set(const xpath_context& c)
{ {
switch (m_type) switch (m_type)
{ {
@ -2393,67 +2383,18 @@ namespace pugi
} }
case ast_filter: case ast_filter:
{
xpath_node_set set = m_left->eval_node_set(c);
set.sort();
xpath_context oc = c;
size_t i = 0;
xpath_node_set::iterator last = set.mut_begin();
// remove_if... or well, sort of
for (xpath_node_set::const_iterator it = set.begin(); it != set.end(); ++it, ++i)
{
c.n = *it;
c.position = i + 1;
c.size = set.size();
if (m_right->rettype() == xpath_type_number)
{
if (m_right->eval_number(c) == i + 1)
*last++ = *it;
}
else if (m_right->eval_boolean(c))
*last++ = *it;
}
c = oc;
set.truncate(last);
return set;
}
case ast_filter_posinv: case ast_filter_posinv:
{ {
xpath_node_set set = m_left->eval_node_set(c); xpath_node_set set = m_left->eval_node_set(c);
xpath_context oc = c; // either expression is a number or it contains position() call; sort by document order
if (m_type == ast_filter) set.sort();
size_t i = 0;
apply_predicate(set, 0, m_right, c);
xpath_node_set::iterator last = set.mut_begin();
// remove_if... or well, sort of
for (xpath_node_set::const_iterator it = set.begin(); it != set.end(); ++it, ++i)
{
c.n = *it;
c.position = i + 1;
c.size = set.size();
if (m_right->eval_boolean(c))
*last++ = *it;
}
c = oc;
set.truncate(last);
return set; return set;
} }
case ast_func_id: case ast_func_id:
return xpath_node_set(); return xpath_node_set();

View File

@ -707,4 +707,9 @@ TEST_XML_FLAGS(xpath_string_value, "<node><c1>pcdata</c1><c2><child/></c2><c3 at
CHECK_XPATH_STRING(n, STR("string(c6/node())"), STR("cdata")); CHECK_XPATH_STRING(n, STR("string(c6/node())"), STR("cdata"));
} }
TEST_XML(xpath_string_concat_translate, "<node>foobar</node>")
{
CHECK_XPATH_STRING(doc, STR("concat('a', 'b', 'c', translate(node, 'o', 'a'), 'd')"), STR("abcfaabard"));
}
#endif #endif