Implement non-recursive node output

This makes node output 3% faster, prevents it from ever running out of
stack space and makes the profiling results more actionable for profilers
that can't merge information from recursive calls.

git-svn-id: https://pugixml.googlecode.com/svn/trunk@1014 99668b35-9821-0410-8761-19e4c4f06640
This commit is contained in:
Arseny Kapoulkine 2014-09-21 21:52:07 +00:00
parent 2f1fed4b9f
commit 4ed5972d4f

View File

@ -3269,6 +3269,12 @@ PUGI__NS_BEGIN
while (*s);
}
PUGI__FN void text_output_indent(xml_buffered_writer& writer, const char_t* indent, unsigned int depth)
{
for (unsigned int i = 0; i < depth; ++i)
writer.write(indent);
}
PUGI__FN void node_output_attributes(xml_buffered_writer& writer, const xml_node& node, unsigned int flags)
{
const char_t* default_name = PUGIXML_TEXT(":anonymous");
@ -3285,24 +3291,9 @@ PUGI__NS_BEGIN
}
}
PUGI__FN void node_output(xml_buffered_writer& writer, const xml_node& node, const char_t* indent, unsigned int flags, unsigned int depth)
PUGI__FN bool node_output_start(xml_buffered_writer& writer, const xml_node& node, unsigned int flags)
{
const char_t* default_name = PUGIXML_TEXT(":anonymous");
if ((flags & format_indent) != 0 && (flags & format_raw) == 0)
for (unsigned int i = 0; i < depth; ++i) writer.write(indent);
switch (node.type())
{
case node_document:
{
for (xml_node n = node.first_child(); n; n = n.next_sibling())
node_output(writer, n, indent, flags, depth);
break;
}
case node_element:
{
const char_t* name = node.name()[0] ? node.name() : default_name;
writer.write('<');
@ -3318,12 +3309,7 @@ PUGI__NS_BEGIN
{
writer.write('>');
for (xml_node n = node.first_child(); n; n = n.next_sibling())
node_output(writer, n, indent, flags, depth + 1);
writer.write('<', '/');
writer.write(name);
writer.write('>');
return true;
}
}
else if (!node.first_child())
@ -3345,20 +3331,31 @@ PUGI__NS_BEGIN
{
writer.write('>', '\n');
for (xml_node n = node.first_child(); n; n = n.next_sibling())
node_output(writer, n, indent, flags, depth + 1);
return true;
}
if ((flags & format_indent) != 0 && (flags & format_raw) == 0)
for (unsigned int i = 0; i < depth; ++i) writer.write(indent);
return false;
}
PUGI__FN void node_output_end(xml_buffered_writer& writer, const xml_node& node, unsigned int flags)
{
const char_t* default_name = PUGIXML_TEXT(":anonymous");
const char_t* name = node.name()[0] ? node.name() : default_name;
writer.write('<', '/');
writer.write(name);
writer.write('>', '\n');
writer.write('>');
if ((flags & format_raw) == 0)
writer.write('\n');
}
break;
}
PUGI__FN void node_output_simple(xml_buffered_writer& writer, const xml_node& node, unsigned int flags)
{
const char_t* default_name = PUGIXML_TEXT(":anonymous");
switch (node.type())
{
case node_pcdata:
text_output(writer, node.value(), ctx_special_pcdata, flags);
if ((flags & format_raw) == 0) writer.write('\n');
@ -3414,6 +3411,65 @@ PUGI__NS_BEGIN
}
}
PUGI__FN void node_output(xml_buffered_writer& writer, const xml_node& root, const char_t* indent, unsigned int flags, unsigned int depth)
{
xml_node node = root;
do
{
assert(node);
// begin writing current node
if ((flags & (format_indent | format_raw)) == format_indent)
text_output_indent(writer, indent, depth);
if (node.type() == node_element)
{
if (node_output_start(writer, node, flags))
{
node = node.first_child();
depth++;
continue;
}
}
else if (node.type() == node_document)
{
if (node.first_child())
{
node = node.first_child();
continue;
}
}
else
{
node_output_simple(writer, node, flags);
}
// continue to the next node
while (node != root)
{
if (node.next_sibling())
{
node = node.next_sibling();
break;
}
node = node.parent();
depth--;
// write closing node
if (node.type() == node_element)
{
if ((flags & (format_indent | format_raw)) == format_indent)
text_output_indent(writer, indent, depth);
node_output_end(writer, node, flags);
}
}
}
while (node != root);
}
inline bool has_declaration(const xml_node& node)
{
for (xml_node child = node.first_child(); child; child = child.next_sibling())