diff options
-rw-r--r-- | src/pugixml.cpp | 73 |
1 files changed, 44 insertions, 29 deletions
diff --git a/src/pugixml.cpp b/src/pugixml.cpp index 8e61182..3979eb9 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -1654,13 +1654,15 @@ PUGI__NS_BEGIN } #endif - inline bool strcpy_insitu_allow(size_t length, uintptr_t allocated, char_t* target) + inline bool strcpy_insitu_allow(size_t length, uintptr_t header, uintptr_t header_mask, char_t* target) { - assert(target); + // never reuse shared memory + if (header & xml_memory_page_name_or_value_shared_mask) return false; + size_t target_length = strlength(target); // always reuse document buffer memory if possible - if (!allocated) return target_length >= length; + if ((header & header_mask) == 0) return target_length >= length; // reuse heap memory if waste is not too great const size_t reuse_threshold = 32; @@ -1687,7 +1689,7 @@ PUGI__NS_BEGIN return true; } - else if (dest && strcpy_insitu_allow(source_length, header & header_mask, dest)) + else if (dest && strcpy_insitu_allow(source_length, header, header_mask, dest)) { // we can reuse old buffer, so just copy the new data (including zero terminator) memcpy(dest, source, (source_length + 1) * sizeof(char_t)); @@ -3605,42 +3607,55 @@ PUGI__NS_BEGIN return true; } - PUGI__FN void node_copy_contents(xml_node dest, const xml_node source) + PUGI__FN void node_copy_string(char_t*& dest, uintptr_t& header, uintptr_t header_mask, char_t* source, uintptr_t& source_header, xml_allocator* alloc) { - assert(dest.type() == source.type()); - - switch (source.type()) - { - case node_element: - case node_declaration: + if (source) { - dest.set_name(source.name()); + if (alloc && (source_header & header_mask) == 0) + { + dest = source; - for (xml_attribute a = source.first_attribute(); a; a = a.next_attribute()) - dest.append_attribute(a.name()).set_value(a.value()); - break; + // since strcpy_insitu can reuse document buffer memory we need to mark both source and dest as shared + header |= xml_memory_page_name_or_value_shared_mask; + source_header |= xml_memory_page_name_or_value_shared_mask; + } + else + strcpy_insitu(dest, header, header_mask, source); } + } - case node_pcdata: - case node_cdata: - case node_comment: - case node_doctype: - dest.set_value(source.value()); - break; + PUGI__FN void node_copy_contents(xml_allocator* alloc, xml_node dest, const xml_node source) + { + assert(dest.type() == source.type()); - case node_pi: - dest.set_name(source.name()); - dest.set_value(source.value()); - break; + xml_node_struct* dn = dest.internal_object(); + xml_node_struct* sn = source.internal_object(); - default: - assert(!"Invalid node type"); + node_copy_string(dn->name, dn->header, xml_memory_page_name_allocated_mask, sn->name, sn->header, alloc); + node_copy_string(dn->value, dn->header, xml_memory_page_value_allocated_mask, sn->value, sn->header, alloc); + + for (xml_attribute_struct* sa = sn->first_attribute; sa; sa = sa->next_attribute) + { + xml_attribute_struct* da = impl::append_new_attribute(dn, impl::get_allocator(dn)); + + node_copy_string(da->name, da->header, xml_memory_page_name_allocated_mask, sa->name, sa->header, alloc); + node_copy_string(da->value, da->header, xml_memory_page_value_allocated_mask, sa->value, sa->header, alloc); } } + PUGI__FN xml_allocator* node_get_shared_allocator(const xml_node lhs, const xml_node rhs) + { + xml_allocator& la = impl::get_allocator(lhs.internal_object()); + xml_allocator& ra = impl::get_allocator(rhs.internal_object()); + + return (&la == &ra) ? &la : 0; + } + PUGI__FN void node_copy_tree(xml_node dest, const xml_node source) { - node_copy_contents(dest, source); + xml_allocator* alloc = node_get_shared_allocator(dest, source); + + node_copy_contents(alloc, dest, source); xml_node destit = dest; xml_node sourceit = source.first_child(); @@ -3651,7 +3666,7 @@ PUGI__NS_BEGIN { xml_node copy = destit.append_child(sourceit.type()); - node_copy_contents(copy, sourceit); + node_copy_contents(alloc, copy, sourceit); if (sourceit.first_child()) { |