XPath: Optimized concat (it's now O(n) instead of O(n^2) and there are less allocations)
git-svn-id: http://pugixml.googlecode.com/svn/trunk@698 99668b35-9821-0410-8761-19e4c4f06640
This commit is contained in:
parent
b33ac7477c
commit
b81027b00d
@ -7263,6 +7263,66 @@ namespace pugi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xpath_string eval_string_concat(const xpath_context& c)
|
||||||
|
{
|
||||||
|
assert(_type == ast_func_concat);
|
||||||
|
|
||||||
|
// count the string number
|
||||||
|
unsigned int count = 1;
|
||||||
|
for (xpath_ast_node* n = _right; n; n = n->_next) count++;
|
||||||
|
|
||||||
|
// gather all strings
|
||||||
|
xpath_string static_buffer[4];
|
||||||
|
xpath_string* buffer = static_buffer;
|
||||||
|
|
||||||
|
// allocate on-heap for large concats
|
||||||
|
if (count > sizeof(static_buffer) / sizeof(static_buffer[0]))
|
||||||
|
{
|
||||||
|
buffer = static_cast<xpath_string*>(global_allocate(count * sizeof(xpath_string)));
|
||||||
|
if (!buffer) return xpath_string(); // $$ out of memory
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < count; ++i) new (&buffer[i]) xpath_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute all strings
|
||||||
|
_left->eval_string(c).swap(buffer[0]);
|
||||||
|
|
||||||
|
size_t pos = 1;
|
||||||
|
for (xpath_ast_node* n = _right; n; n = n->_next, ++pos) n->eval_string(c).swap(buffer[pos]);
|
||||||
|
assert(pos == count);
|
||||||
|
|
||||||
|
// get total length
|
||||||
|
size_t length = 0;
|
||||||
|
for (unsigned int i = 0; i < count; ++i) length += buffer[i].length();
|
||||||
|
|
||||||
|
// create final string
|
||||||
|
char_t* result = static_cast<char_t*>(global_allocate((length + 1) * sizeof(char_t)));
|
||||||
|
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
char_t* ri = result;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < count; ++i)
|
||||||
|
for (const char_t* bi = buffer[i].c_str(); *bi; ++bi)
|
||||||
|
*ri++ = *bi;
|
||||||
|
|
||||||
|
*ri = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// deallocate strings
|
||||||
|
if (buffer != static_buffer)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < count; ++i) buffer[i].~xpath_string();
|
||||||
|
|
||||||
|
global_deallocate(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// return result
|
||||||
|
if (!result) return xpath_string(); // $$ out of memory
|
||||||
|
|
||||||
|
return xpath_string(result, true);
|
||||||
|
}
|
||||||
|
|
||||||
xpath_string eval_string(const xpath_context& c)
|
xpath_string eval_string(const xpath_context& c)
|
||||||
{
|
{
|
||||||
switch (_type)
|
switch (_type)
|
||||||
@ -7322,14 +7382,7 @@ namespace pugi
|
|||||||
return _left->eval_string(c);
|
return _left->eval_string(c);
|
||||||
|
|
||||||
case ast_func_concat:
|
case ast_func_concat:
|
||||||
{
|
return eval_string_concat(c);
|
||||||
xpath_string r = _left->eval_string(c);
|
|
||||||
|
|
||||||
for (xpath_ast_node* n = _right; n; n = n->_next)
|
|
||||||
r.append(n->eval_string(c));
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
case ast_func_substring_before:
|
case ast_func_substring_before:
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user