Implement non-recursive node copying
This makes node copying 6% 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@1027 99668b35-9821-0410-8761-19e4c4f06640
This commit is contained in:
parent
8e2aeb6f60
commit
ddf6db3078
@ -3602,29 +3602,19 @@ PUGI__NS_BEGIN
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
PUGI__FN void recursive_copy_skip(xml_node& dest, const xml_node& source, const xml_node& skip)
|
PUGI__FN void node_copy_contents(xml_node dest, xml_node source)
|
||||||
{
|
{
|
||||||
assert(dest.type() == source.type());
|
assert(dest.type() == source.type());
|
||||||
|
|
||||||
switch (source.type())
|
switch (source.type())
|
||||||
{
|
{
|
||||||
case node_element:
|
case node_element:
|
||||||
|
case node_declaration:
|
||||||
{
|
{
|
||||||
dest.set_name(source.name());
|
dest.set_name(source.name());
|
||||||
|
|
||||||
for (xml_attribute a = source.first_attribute(); a; a = a.next_attribute())
|
for (xml_attribute a = source.first_attribute(); a; a = a.next_attribute())
|
||||||
dest.append_attribute(a.name()).set_value(a.value());
|
dest.append_attribute(a.name()).set_value(a.value());
|
||||||
|
|
||||||
for (xml_node c = source.first_child(); c; c = c.next_sibling())
|
|
||||||
{
|
|
||||||
if (c == skip) continue;
|
|
||||||
|
|
||||||
xml_node cc = dest.append_child(c.type());
|
|
||||||
assert(cc);
|
|
||||||
|
|
||||||
recursive_copy_skip(cc, c, skip);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3640,21 +3630,50 @@ PUGI__NS_BEGIN
|
|||||||
dest.set_value(source.value());
|
dest.set_value(source.value());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case node_declaration:
|
|
||||||
{
|
|
||||||
dest.set_name(source.name());
|
|
||||||
|
|
||||||
for (xml_attribute a = source.first_attribute(); a; a = a.next_attribute())
|
|
||||||
dest.append_attribute(a.name()).set_value(a.value());
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert(!"Invalid node type");
|
assert(!"Invalid node type");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PUGI__FN void node_copy_tree(xml_node dest, xml_node source)
|
||||||
|
{
|
||||||
|
node_copy_contents(dest, source);
|
||||||
|
|
||||||
|
xml_node destit = dest;
|
||||||
|
xml_node sourceit = source.first_child();
|
||||||
|
|
||||||
|
while (sourceit && sourceit != source)
|
||||||
|
{
|
||||||
|
if (sourceit != dest)
|
||||||
|
{
|
||||||
|
xml_node copy = destit.append_child(sourceit.type());
|
||||||
|
|
||||||
|
node_copy_contents(copy, sourceit);
|
||||||
|
|
||||||
|
if (sourceit.first_child())
|
||||||
|
{
|
||||||
|
destit = copy;
|
||||||
|
sourceit = sourceit.first_child();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// continue to the next node
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (sourceit.next_sibling())
|
||||||
|
{
|
||||||
|
sourceit = sourceit.next_sibling();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceit = sourceit.parent();
|
||||||
|
destit = destit.parent();
|
||||||
|
}
|
||||||
|
while (sourceit != source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline bool is_text_node(xml_node_struct* node)
|
inline bool is_text_node(xml_node_struct* node)
|
||||||
{
|
{
|
||||||
xml_node_type type = static_cast<xml_node_type>((node->header & impl::xml_memory_page_type_mask) + 1);
|
xml_node_type type = static_cast<xml_node_type>((node->header & impl::xml_memory_page_type_mask) + 1);
|
||||||
@ -4965,7 +4984,7 @@ namespace pugi
|
|||||||
{
|
{
|
||||||
xml_node result = append_child(proto.type());
|
xml_node result = append_child(proto.type());
|
||||||
|
|
||||||
if (result) impl::recursive_copy_skip(result, proto, result);
|
if (result) impl::node_copy_tree(result, proto);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -4974,7 +4993,7 @@ namespace pugi
|
|||||||
{
|
{
|
||||||
xml_node result = prepend_child(proto.type());
|
xml_node result = prepend_child(proto.type());
|
||||||
|
|
||||||
if (result) impl::recursive_copy_skip(result, proto, result);
|
if (result) impl::node_copy_tree(result, proto);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -4983,7 +5002,7 @@ namespace pugi
|
|||||||
{
|
{
|
||||||
xml_node result = insert_child_after(proto.type(), node);
|
xml_node result = insert_child_after(proto.type(), node);
|
||||||
|
|
||||||
if (result) impl::recursive_copy_skip(result, proto, result);
|
if (result) impl::node_copy_tree(result, proto);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -4992,7 +5011,7 @@ namespace pugi
|
|||||||
{
|
{
|
||||||
xml_node result = insert_child_before(proto.type(), node);
|
xml_node result = insert_child_before(proto.type(), node);
|
||||||
|
|
||||||
if (result) impl::recursive_copy_skip(result, proto, result);
|
if (result) impl::node_copy_tree(result, proto);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user