Add shallow_copy support for improve performance of literal string

This commit is contained in:
halx99 2021-09-30 13:00:58 +08:00
parent 4852708894
commit 0d9a303991
2 changed files with 47 additions and 46 deletions

View File

@ -432,6 +432,7 @@ PUGI__NS_BEGIN
#endif #endif
// extra metadata bits // extra metadata bits
static const uintptr_t xml_memory_page_const_buffer_mask = 128;
static const uintptr_t xml_memory_page_contents_shared_mask = 64; static const uintptr_t xml_memory_page_contents_shared_mask = 64;
static const uintptr_t xml_memory_page_name_allocated_mask = 32; static const uintptr_t xml_memory_page_name_allocated_mask = 32;
static const uintptr_t xml_memory_page_value_allocated_mask = 16; static const uintptr_t xml_memory_page_value_allocated_mask = 16;
@ -2354,9 +2355,9 @@ PUGI__NS_BEGIN
} }
template <typename String, typename Header> template <typename String, typename Header>
PUGI__FN bool strcpy_insitu(String& dest, Header& header, uintptr_t header_mask, const char_t* source, size_t source_length) PUGI__FN bool strcpy_insitu(String& dest, Header& header, uintptr_t header_mask, const char_t* source, size_t source_length, bool shallow_copy = false)
{ {
if (source_length == 0) if (source_length == 0 || shallow_copy)
{ {
// empty string and null pointer are equivalent, so just deallocate old memory // empty string and null pointer are equivalent, so just deallocate old memory
xml_allocator* alloc = PUGI__GETPAGE_IMPL(header)->allocator; xml_allocator* alloc = PUGI__GETPAGE_IMPL(header)->allocator;
@ -2364,7 +2365,7 @@ PUGI__NS_BEGIN
if (header & header_mask) alloc->deallocate_string(dest); if (header & header_mask) alloc->deallocate_string(dest);
// mark the string as not allocated // mark the string as not allocated
dest = 0; dest = !shallow_copy ? nullptr : const_cast<String>(source);
header &= ~header_mask; header &= ~header_mask;
return true; return true;
@ -5320,18 +5321,18 @@ namespace pugi
} }
#endif #endif
PUGI__FN bool xml_attribute::set_name(string_view_t rhs) PUGI__FN bool xml_attribute::set_name(string_view_t rhs, bool shallow_copy)
{ {
if (!_attr) return false; if (!_attr) return false;
return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs.data(), rhs.length()); return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs.data(), rhs.length(), shallow_copy);
} }
PUGI__FN bool xml_attribute::set_value(string_view_t rhs) PUGI__FN bool xml_attribute::set_value(string_view_t rhs, bool shallow_copy)
{ {
if (!_attr) return false; if (!_attr) return false;
return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs.data(), rhs.length()); return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs.data(), rhs.length(), shallow_copy);
} }
PUGI__FN bool xml_attribute::set_value(int rhs) PUGI__FN bool xml_attribute::set_value(int rhs)
@ -5674,27 +5675,27 @@ namespace pugi
return _root && _root->first_child ? xml_node(_root->first_child->prev_sibling_c) : xml_node(); return _root && _root->first_child ? xml_node(_root->first_child->prev_sibling_c) : xml_node();
} }
PUGI__FN bool xml_node::set_name(string_view_t rhs) PUGI__FN bool xml_node::set_name(string_view_t rhs, bool shallow_copy)
{ {
xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null; xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null;
if (type_ != node_element && type_ != node_pi && type_ != node_declaration) if (type_ != node_element && type_ != node_pi && type_ != node_declaration)
return false; return false;
return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs.data(), rhs.length()); return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs.data(), rhs.length(), shallow_copy);
} }
PUGI__FN bool xml_node::set_value(string_view_t rhs) PUGI__FN bool xml_node::set_value(string_view_t rhs, bool shallow_copy)
{ {
xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null; xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null;
if (type_ != node_pcdata && type_ != node_cdata && type_ != node_comment && type_ != node_pi && type_ != node_doctype) if (type_ != node_pcdata && type_ != node_cdata && type_ != node_comment && type_ != node_pi && type_ != node_doctype)
return false; return false;
return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs.data(), rhs.length()); return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs.data(), rhs.length(), shallow_copy);
} }
PUGI__FN xml_attribute xml_node::append_attribute(string_view_t name_) PUGI__FN xml_attribute xml_node::append_attribute(string_view_t name_, bool shallow_copy)
{ {
if (!impl::allow_insert_attribute(type())) return xml_attribute(); if (!impl::allow_insert_attribute(type())) return xml_attribute();
@ -5706,12 +5707,12 @@ namespace pugi
impl::append_attribute(a._attr, _root); impl::append_attribute(a._attr, _root);
a.set_name(name_); a.set_name(name_, shallow_copy);
return a; return a;
} }
PUGI__FN xml_attribute xml_node::prepend_attribute(string_view_t name_) PUGI__FN xml_attribute xml_node::prepend_attribute(string_view_t name_, bool shallow_copy)
{ {
if (!impl::allow_insert_attribute(type())) return xml_attribute(); if (!impl::allow_insert_attribute(type())) return xml_attribute();
@ -5723,12 +5724,12 @@ namespace pugi
impl::prepend_attribute(a._attr, _root); impl::prepend_attribute(a._attr, _root);
a.set_name(name_); a.set_name(name_, shallow_copy);
return a; return a;
} }
PUGI__FN xml_attribute xml_node::insert_attribute_after(string_view_t name_, const xml_attribute& attr) PUGI__FN xml_attribute xml_node::insert_attribute_after(string_view_t name_, const xml_attribute& attr, bool shallow_copy)
{ {
if (!impl::allow_insert_attribute(type())) return xml_attribute(); if (!impl::allow_insert_attribute(type())) return xml_attribute();
if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute();
@ -5741,12 +5742,12 @@ namespace pugi
impl::insert_attribute_after(a._attr, attr._attr, _root); impl::insert_attribute_after(a._attr, attr._attr, _root);
a.set_name(name_); a.set_name(name_, shallow_copy);
return a; return a;
} }
PUGI__FN xml_attribute xml_node::insert_attribute_before(string_view_t name_, const xml_attribute& attr) PUGI__FN xml_attribute xml_node::insert_attribute_before(string_view_t name_, const xml_attribute& attr, bool shallow_copy)
{ {
if (!impl::allow_insert_attribute(type())) return xml_attribute(); if (!impl::allow_insert_attribute(type())) return xml_attribute();
if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute();
@ -5759,7 +5760,7 @@ namespace pugi
impl::insert_attribute_before(a._attr, attr._attr, _root); impl::insert_attribute_before(a._attr, attr._attr, _root);
a.set_name(name_); a.set_name(name_, shallow_copy);
return a; return a;
} }
@ -5846,7 +5847,7 @@ namespace pugi
impl::append_node(n._root, _root); impl::append_node(n._root, _root);
if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"), true);
return n; return n;
} }
@ -5863,7 +5864,7 @@ namespace pugi
impl::prepend_node(n._root, _root); impl::prepend_node(n._root, _root);
if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"), true);
return n; return n;
} }
@ -5881,7 +5882,7 @@ namespace pugi
impl::insert_node_before(n._root, node._root); impl::insert_node_before(n._root, node._root);
if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"), true);
return n; return n;
} }
@ -5899,43 +5900,43 @@ namespace pugi
impl::insert_node_after(n._root, node._root); impl::insert_node_after(n._root, node._root);
if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"), true);
return n; return n;
} }
PUGI__FN xml_node xml_node::append_child(string_view_t name_) PUGI__FN xml_node xml_node::append_child(string_view_t name_, bool shallow_copy)
{ {
xml_node result = append_child(node_element); xml_node result = append_child(node_element);
result.set_name(name_); result.set_name(name_, shallow_copy);
return result; return result;
} }
PUGI__FN xml_node xml_node::prepend_child(string_view_t name_) PUGI__FN xml_node xml_node::prepend_child(string_view_t name_, bool shallow_copy)
{ {
xml_node result = prepend_child(node_element); xml_node result = prepend_child(node_element);
result.set_name(name_); result.set_name(name_, shallow_copy);
return result; return result;
} }
PUGI__FN xml_node xml_node::insert_child_after(string_view_t name_, const xml_node& node) PUGI__FN xml_node xml_node::insert_child_after(string_view_t name_, const xml_node& node, bool shallow_copy)
{ {
xml_node result = insert_child_after(node_element, node); xml_node result = insert_child_after(node_element, node);
result.set_name(name_); result.set_name(name_, shallow_copy);
return result; return result;
} }
PUGI__FN xml_node xml_node::insert_child_before(string_view_t name_, const xml_node& node) PUGI__FN xml_node xml_node::insert_child_before(string_view_t name_, const xml_node& node, bool shallow_copy)
{ {
xml_node result = insert_child_before(node_element, node); xml_node result = insert_child_before(node_element, node);
result.set_name(name_); result.set_name(name_, shallow_copy);
return result; return result;
} }
@ -6537,11 +6538,11 @@ namespace pugi
} }
#endif #endif
PUGI__FN bool xml_text::set(string_view_t rhs) PUGI__FN bool xml_text::set(string_view_t rhs, bool shallow_copy)
{ {
xml_node_struct* dn = _data_new(); xml_node_struct* dn = _data_new();
return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs.data(), rhs.length()) : false; return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs.data(), rhs.length(), shallow_copy) : false;
} }
PUGI__FN bool xml_text::set(int rhs) PUGI__FN bool xml_text::set(int rhs)

View File

@ -540,8 +540,8 @@ namespace pugi
bool as_bool(bool def = false) const; bool as_bool(bool def = false) const;
// Set attribute name/value (returns false if attribute is empty or there is not enough memory) // Set attribute name/value (returns false if attribute is empty or there is not enough memory)
bool set_name(string_view_t rhs); bool set_name(string_view_t rhs, bool shallow_copy = false);
bool set_value(string_view_t rhs); bool set_value(string_view_t rhs, bool shallow_copy = false);
// Set attribute value with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") // Set attribute value with type conversion (numbers are converted to strings, boolean is converted to "true"/"false")
bool set_value(int rhs); bool set_value(int rhs);
@ -674,14 +674,14 @@ namespace pugi
const char_t* child_value(const char_t* name) const; const char_t* child_value(const char_t* name) const;
// Set node name/value (returns false if node is empty, there is not enough memory, or node can not have name/value) // Set node name/value (returns false if node is empty, there is not enough memory, or node can not have name/value)
bool set_name(string_view_t rhs); bool set_name(string_view_t rhs, bool shallow_copy = false);
bool set_value(string_view_t rhs); bool set_value(string_view_t rhs, bool shallow_copy = false);
// Add attribute with specified name. Returns added attribute, or empty attribute on errors. // Add attribute with specified name. Returns added attribute, or empty attribute on errors.
xml_attribute append_attribute(string_view_t name); xml_attribute append_attribute(string_view_t name, bool shallow_copy = false);
xml_attribute prepend_attribute(string_view_t name); xml_attribute prepend_attribute(string_view_t name, bool shallow_copy = false);
xml_attribute insert_attribute_after(string_view_t name, const xml_attribute& attr); xml_attribute insert_attribute_after(string_view_t name, const xml_attribute& attr, bool shallow_copy = false);
xml_attribute insert_attribute_before(string_view_t name, const xml_attribute& attr); xml_attribute insert_attribute_before(string_view_t name, const xml_attribute& attr, bool shallow_copy = false);
// Add a copy of the specified attribute. Returns added attribute, or empty attribute on errors. // Add a copy of the specified attribute. Returns added attribute, or empty attribute on errors.
xml_attribute append_copy(const xml_attribute& proto); xml_attribute append_copy(const xml_attribute& proto);
@ -696,10 +696,10 @@ namespace pugi
xml_node insert_child_before(xml_node_type type, const xml_node& node); xml_node insert_child_before(xml_node_type type, const xml_node& node);
// Add child element with specified name. Returns added node, or empty node on errors. // Add child element with specified name. Returns added node, or empty node on errors.
xml_node append_child(string_view_t name); xml_node append_child(string_view_t name, bool shallow_copy = false);
xml_node prepend_child(string_view_t name); xml_node prepend_child(string_view_t name, bool shallow_copy = false);
xml_node insert_child_after(string_view_t name, const xml_node& node); xml_node insert_child_after(string_view_t name, const xml_node& node, bool shallow_copy = false);
xml_node insert_child_before(string_view_t name, const xml_node& node); xml_node insert_child_before(string_view_t name, const xml_node& node, bool shallow_copy = false);
// Add a copy of the specified node as a child. Returns added node, or empty node on errors. // Add a copy of the specified node as a child. Returns added node, or empty node on errors.
xml_node append_copy(const xml_node& proto); xml_node append_copy(const xml_node& proto);
@ -900,7 +900,7 @@ namespace pugi
bool as_bool(bool def = false) const; bool as_bool(bool def = false) const;
// Set text (returns false if object is empty or there is not enough memory) // Set text (returns false if object is empty or there is not enough memory)
bool set(string_view_t rhs); bool set(string_view_t rhs, bool shallow_copy = false);
// Set text with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") // Set text with type conversion (numbers are converted to strings, boolean is converted to "true"/"false")
bool set(int rhs); bool set(int rhs);