From 15697a7b8600d93b141e0ccb4349364252895f64 Mon Sep 17 00:00:00 2001 From: halx99 Date: Wed, 29 Sep 2021 10:37:52 +0800 Subject: [PATCH 01/43] Initial string_view for set_name, set_value --- src/pugixml.cpp | 16 ++--- src/pugixml.hpp | 159 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 163 insertions(+), 12 deletions(-) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index 2b365d94..374c8ebe 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -5320,18 +5320,18 @@ namespace pugi } #endif - PUGI__FN bool xml_attribute::set_name(const char_t* rhs) + PUGI__FN bool xml_attribute::set_name(string_view rhs) { if (!_attr) return false; - return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs)); + return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs.data(), rhs.length()); } - PUGI__FN bool xml_attribute::set_value(const char_t* rhs) + PUGI__FN bool xml_attribute::set_value(string_view rhs) { if (!_attr) return false; - return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs)); + return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs.data(), rhs.length()); } PUGI__FN bool xml_attribute::set_value(int rhs) @@ -5674,24 +5674,24 @@ namespace pugi return _root && _root->first_child ? xml_node(_root->first_child->prev_sibling_c) : xml_node(); } - PUGI__FN bool xml_node::set_name(const char_t* rhs) + PUGI__FN bool xml_node::set_name(string_view rhs) { xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null; if (type_ != node_element && type_ != node_pi && type_ != node_declaration) return false; - return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs)); + return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs.data(), rhs.length()); } - PUGI__FN bool xml_node::set_value(const char_t* rhs) + PUGI__FN bool xml_node::set_value(string_view rhs) { 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) return false; - return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs)); + return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs.data(), rhs.length()); } PUGI__FN xml_attribute xml_node::append_attribute(const char_t* name_) diff --git a/src/pugixml.hpp b/src/pugixml.hpp index ed234fb9..2213336f 100644 --- a/src/pugixml.hpp +++ b/src/pugixml.hpp @@ -38,6 +38,16 @@ # include #endif +#if (defined(__cplusplus) && __cplusplus == 201703L) || (defined(_MSC_VER) && _MSC_VER > 1900 && ((defined(_HAS_CXX17) && _HAS_CXX17 == 1) || (defined(_MSVC_LANG) && (_MSVC_LANG > 201402L)))) +#ifndef PUGI_CXX17_FEATURES +#define PUGI_CXX17_FEATURES 1 +#endif // C++17 features macro +#endif // C++17 features check + +#if defined(PUGI_CXX17_FEATURES) && PUGI_CXX17_FEATURES +#include +#endif // C++17 features + // Macro for deprecated features #ifndef PUGIXML_DEPRECATED # if defined(__GNUC__) @@ -140,6 +150,147 @@ namespace pugi #endif } +// string_view +namespace pugi { +#if defined(PUGI_CXX17_FEATURES) && PUGI_CXX17_FEATURES + template > + using basic_string_view = std::basic_string_view; + typedef std::string_view string_view; + typedef std::wstring_view wstring_view; + typedef std::u16string_view u16string_view; + typedef std::u32string_view u32string_view; + typedef std::hash string_view_hash; +#else + template > + struct basic_string_view { + std::size_t s; + const Char* p; + + basic_string_view(const std::string& r) + : basic_string_view(r.data(), r.size()) { + } + basic_string_view(const Char* ptr) + : basic_string_view(ptr, Traits::length(ptr)) { + } + basic_string_view(const Char* ptr, std::size_t sz) + : s(sz), p(ptr) { + } + + static int compare(const Char* lhs_p, std::size_t lhs_sz, const Char* rhs_p, std::size_t rhs_sz) { + int result = Traits::compare(lhs_p, rhs_p, lhs_sz < rhs_sz ? lhs_sz : rhs_sz); + if (result != 0) + return result; + if (lhs_sz < rhs_sz) + return -1; + if (lhs_sz > rhs_sz) + return 1; + return 0; + } + + const Char* begin() const { + return p; + } + + const Char* end() const { + return p + s; + } + + const Char* cbegin() const { + return p; + } + + const Char* cend() const { + return p + s; + } + + const Char* data() const { + return p; + } + + std::size_t size() const { + return s; + } + + std::size_t length() const { + return size(); + } + + operator std::basic_string() const { + return std::basic_string(data(), size()); + } + + bool operator==(const basic_string_view& r) const { + return compare(p, s, r.data(), r.size()) == 0; + } + + bool operator==(const Char* r) const { + return compare(r, Traits::length(r), p, s) == 0; + } + + bool operator==(const std::basic_string& r) const { + return compare(r.data(), r.size(), p, s) == 0; + } + + bool operator!=(const basic_string_view& r) const { + return !(*this == r); + } + + bool operator!=(const char* r) const { + return !(*this == r); + } + + bool operator!=(const std::basic_string& r) const { + return !(*this == r); + } + }; + + template > + struct basic_string_view_hash { + typedef basic_string_view argument_type; + typedef std::size_t result_type; + + template + result_type operator()(const std::basic_string& r) const { + return (*this)(argument_type(r.c_str(), r.size())); + } + + result_type operator()(const argument_type& r) const { +#if defined(SOL_USE_BOOST) && SOL_USE_BOOST + return boost::hash_range(r.begin(), r.end()); +#else + // Modified, from libstdc++ + // An implementation attempt at Fowler No Voll, 1a. + // Supposedly, used in MSVC, + // GCC (libstdc++) uses MurmurHash of some sort for 64-bit though...? + // But, well. Can't win them all, right? + // This should normally only apply when NOT using boost, + // so this should almost never be tapped into... + std::size_t hash = 0; + const unsigned char* cptr = reinterpret_cast(r.data()); + for (std::size_t sz = r.size(); sz != 0; --sz) { + hash ^= static_cast(*cptr++); + hash *= static_cast(1099511628211ULL); + } + return hash; +#endif + } + }; +} // namespace pugi + +namespace std { + template + struct hash< ::pugi::basic_string_view > : ::pugi::basic_string_view_hash {}; +} // namespace std + +namespace pugi { + using string_view = basic_string_view; + using wstring_view = basic_string_view; + using u16string_view = basic_string_view; + using u32string_view = basic_string_view; + using string_view_hash = std::hash; +#endif +} // namespace pugi + // The PugiXML namespace namespace pugi { @@ -415,8 +566,8 @@ namespace pugi bool as_bool(bool def = false) const; // Set attribute name/value (returns false if attribute is empty or there is not enough memory) - bool set_name(const char_t* rhs); - bool set_value(const char_t* rhs); + bool set_name(string_view rhs); + bool set_value(string_view rhs); // Set attribute value with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") bool set_value(int rhs); @@ -549,8 +700,8 @@ namespace pugi 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) - bool set_name(const char_t* rhs); - bool set_value(const char_t* rhs); + bool set_name(string_view rhs); + bool set_value(string_view rhs); // Add attribute with specified name. Returns added attribute, or empty attribute on errors. xml_attribute append_attribute(const char_t* name); From 3a975d2f8e15285b8b03e02ca8d613dd45883993 Mon Sep 17 00:00:00 2001 From: halx99 Date: Wed, 29 Sep 2021 11:21:31 +0800 Subject: [PATCH 02/43] Add explicit boolean type for store as 'true' or 'false' --- src/pugixml.cpp | 16 ++++++++-------- src/pugixml.hpp | 26 +++++++++++++++++++------- tests/test_dom_modify.cpp | 8 ++++---- tests/test_dom_text.cpp | 6 +++--- 4 files changed, 34 insertions(+), 22 deletions(-) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index 374c8ebe..e5994854 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -5258,7 +5258,7 @@ namespace pugi return _attr; } - PUGI__FN xml_attribute& xml_attribute::operator=(const char_t* rhs) + PUGI__FN xml_attribute& xml_attribute::operator=(string_view rhs) { set_value(rhs); return *this; @@ -5300,7 +5300,7 @@ namespace pugi return *this; } - PUGI__FN xml_attribute& xml_attribute::operator=(bool rhs) + PUGI__FN xml_attribute& xml_attribute::operator=(boolean rhs) { set_value(rhs); return *this; @@ -5390,7 +5390,7 @@ namespace pugi return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, precision); } - PUGI__FN bool xml_attribute::set_value(bool rhs) + PUGI__FN bool xml_attribute::set_value(boolean rhs) { if (!_attr) return false; @@ -6537,11 +6537,11 @@ namespace pugi } #endif - PUGI__FN bool xml_text::set(const char_t* rhs) + PUGI__FN bool xml_text::set(string_view rhs) { xml_node_struct* dn = _data_new(); - return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs)) : false; + return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs.data(), rhs.length()) : false; } PUGI__FN bool xml_text::set(int rhs) @@ -6600,7 +6600,7 @@ namespace pugi return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, precision) : false; } - PUGI__FN bool xml_text::set(bool rhs) + PUGI__FN bool xml_text::set(boolean rhs) { xml_node_struct* dn = _data_new(); @@ -6623,7 +6623,7 @@ namespace pugi } #endif - PUGI__FN xml_text& xml_text::operator=(const char_t* rhs) + PUGI__FN xml_text& xml_text::operator=(string_view rhs) { set(rhs); return *this; @@ -6665,7 +6665,7 @@ namespace pugi return *this; } - PUGI__FN xml_text& xml_text::operator=(bool rhs) + PUGI__FN xml_text& xml_text::operator=(boolean rhs) { set(rhs); return *this; diff --git a/src/pugixml.hpp b/src/pugixml.hpp index 2213336f..a0b14a3a 100644 --- a/src/pugixml.hpp +++ b/src/pugixml.hpp @@ -291,6 +291,18 @@ namespace pugi { #endif } // namespace pugi +// explicit boolean type +namespace pugi { + struct boolean { + boolean() : value(false) {} + explicit boolean(bool bval) : value(bval) {} + bool value; + operator bool() const { return value; } + }; + static const boolean true_value{ true }; + static const boolean false_value{ false }; +} + // The PugiXML namespace namespace pugi { @@ -578,7 +590,7 @@ namespace pugi bool set_value(double rhs, int precision); bool set_value(float rhs); bool set_value(float rhs, int precision); - bool set_value(bool rhs); + bool set_value(boolean rhs); #ifdef PUGIXML_HAS_LONG_LONG bool set_value(long long rhs); @@ -586,14 +598,14 @@ namespace pugi #endif // Set attribute value (equivalent to set_value without error checking) - xml_attribute& operator=(const char_t* rhs); + xml_attribute& operator=(string_view rhs); xml_attribute& operator=(int rhs); xml_attribute& operator=(unsigned int rhs); xml_attribute& operator=(long rhs); xml_attribute& operator=(unsigned long rhs); xml_attribute& operator=(double rhs); xml_attribute& operator=(float rhs); - xml_attribute& operator=(bool rhs); + xml_attribute& operator=(boolean rhs); #ifdef PUGIXML_HAS_LONG_LONG xml_attribute& operator=(long long rhs); @@ -926,7 +938,7 @@ namespace pugi bool as_bool(bool def = false) const; // Set text (returns false if object is empty or there is not enough memory) - bool set(const char_t* rhs); + bool set(string_view rhs); // Set text with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") bool set(int rhs); @@ -937,7 +949,7 @@ namespace pugi bool set(double rhs, int precision); bool set(float rhs); bool set(float rhs, int precision); - bool set(bool rhs); + bool set(boolean rhs); #ifdef PUGIXML_HAS_LONG_LONG bool set(long long rhs); @@ -945,14 +957,14 @@ namespace pugi #endif // Set text (equivalent to set without error checking) - xml_text& operator=(const char_t* rhs); + xml_text& operator=(string_view rhs); xml_text& operator=(int rhs); xml_text& operator=(unsigned int rhs); xml_text& operator=(long rhs); xml_text& operator=(unsigned long rhs); xml_text& operator=(double rhs); xml_text& operator=(float rhs); - xml_text& operator=(bool rhs); + xml_text& operator=(boolean rhs); #ifdef PUGIXML_HAS_LONG_LONG xml_text& operator=(long long rhs); diff --git a/tests/test_dom_modify.cpp b/tests/test_dom_modify.cpp index ff9d4407..88554e2a 100644 --- a/tests/test_dom_modify.cpp +++ b/tests/test_dom_modify.cpp @@ -30,8 +30,8 @@ TEST_XML(dom_attr_assign, "") node.append_attribute(STR("attr7")) = 0.25f; xml_attribute() = 0.25f; - node.append_attribute(STR("attr8")) = true; - xml_attribute() = true; + node.append_attribute(STR("attr8")) = true_value; + xml_attribute() = true_value; CHECK_NODE(node, STR("")); } @@ -67,8 +67,8 @@ TEST_XML(dom_attr_set_value, "") CHECK(node.append_attribute(STR("attr7")).set_value(0.25f)); CHECK(!xml_attribute().set_value(0.25f)); - CHECK(node.append_attribute(STR("attr8")).set_value(true)); - CHECK(!xml_attribute().set_value(true)); + CHECK(node.append_attribute(STR("attr8")).set_value(true_value)); + CHECK(!xml_attribute().set_value(true_value)); CHECK_NODE(node, STR("")); } diff --git a/tests/test_dom_text.cpp b/tests/test_dom_text.cpp index c71e54ea..aa131e6f 100644 --- a/tests/test_dom_text.cpp +++ b/tests/test_dom_text.cpp @@ -270,7 +270,7 @@ TEST_XML(dom_text_assign, "") node.append_child(STR("text7")).text() = 0.25f; xml_text() = 0.25f; - node.append_child(STR("text8")).text() = true; + node.append_child(STR("text8")).text() = true_value; xml_text() = true; CHECK_NODE(node, STR("v1-2147483647-2147483648429496729542949672940.50.25true")); @@ -297,8 +297,8 @@ TEST_XML(dom_text_set_value, "") CHECK(node.append_child(STR("text7")).text().set(0.25f)); CHECK(!xml_text().set(0.25f)); - CHECK(node.append_child(STR("text8")).text().set(true)); - CHECK(!xml_text().set(true)); + CHECK(node.append_child(STR("text8")).text().set(true_value)); + CHECK(!xml_text().set(true_value)); CHECK_NODE(node, STR("v1-2147483647-2147483648429496729542949672940.50.25true")); } From aeda2eff24d06e6c5c74c48a5bc76753d891b30d Mon Sep 17 00:00:00 2001 From: halx99 Date: Wed, 29 Sep 2021 11:47:05 +0800 Subject: [PATCH 03/43] Use string_view when needs store --- src/pugixml.cpp | 16 ++++++++-------- src/pugixml.hpp | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index e5994854..db19bf0a 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -5694,7 +5694,7 @@ namespace pugi return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs.data(), rhs.length()); } - PUGI__FN xml_attribute xml_node::append_attribute(const char_t* name_) + PUGI__FN xml_attribute xml_node::append_attribute(string_view name_) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); @@ -5711,7 +5711,7 @@ namespace pugi return a; } - PUGI__FN xml_attribute xml_node::prepend_attribute(const char_t* name_) + PUGI__FN xml_attribute xml_node::prepend_attribute(string_view name_) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); @@ -5728,7 +5728,7 @@ namespace pugi return a; } - PUGI__FN xml_attribute xml_node::insert_attribute_after(const char_t* name_, const xml_attribute& attr) + PUGI__FN xml_attribute xml_node::insert_attribute_after(string_view name_, const xml_attribute& attr) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); @@ -5746,7 +5746,7 @@ namespace pugi return a; } - PUGI__FN xml_attribute xml_node::insert_attribute_before(const char_t* name_, const xml_attribute& attr) + PUGI__FN xml_attribute xml_node::insert_attribute_before(string_view name_, const xml_attribute& attr) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); @@ -5904,7 +5904,7 @@ namespace pugi return n; } - PUGI__FN xml_node xml_node::append_child(const char_t* name_) + PUGI__FN xml_node xml_node::append_child(string_view name_) { xml_node result = append_child(node_element); @@ -5913,7 +5913,7 @@ namespace pugi return result; } - PUGI__FN xml_node xml_node::prepend_child(const char_t* name_) + PUGI__FN xml_node xml_node::prepend_child(string_view name_) { xml_node result = prepend_child(node_element); @@ -5922,7 +5922,7 @@ namespace pugi return result; } - PUGI__FN xml_node xml_node::insert_child_after(const char_t* name_, const xml_node& node) + PUGI__FN xml_node xml_node::insert_child_after(string_view name_, const xml_node& node) { xml_node result = insert_child_after(node_element, node); @@ -5931,7 +5931,7 @@ namespace pugi return result; } - PUGI__FN xml_node xml_node::insert_child_before(const char_t* name_, const xml_node& node) + PUGI__FN xml_node xml_node::insert_child_before(string_view name_, const xml_node& node) { xml_node result = insert_child_before(node_element, node); diff --git a/src/pugixml.hpp b/src/pugixml.hpp index a0b14a3a..062b5fa2 100644 --- a/src/pugixml.hpp +++ b/src/pugixml.hpp @@ -716,10 +716,10 @@ namespace pugi bool set_value(string_view rhs); // Add attribute with specified name. Returns added attribute, or empty attribute on errors. - xml_attribute append_attribute(const char_t* name); - xml_attribute prepend_attribute(const char_t* name); - xml_attribute insert_attribute_after(const char_t* name, const xml_attribute& attr); - xml_attribute insert_attribute_before(const char_t* name, const xml_attribute& attr); + xml_attribute append_attribute(string_view name); + xml_attribute prepend_attribute(string_view name); + xml_attribute insert_attribute_after(string_view name, const xml_attribute& attr); + xml_attribute insert_attribute_before(string_view name, const xml_attribute& attr); // Add a copy of the specified attribute. Returns added attribute, or empty attribute on errors. xml_attribute append_copy(const xml_attribute& proto); @@ -734,10 +734,10 @@ namespace pugi 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. - xml_node append_child(const char_t* name); - xml_node prepend_child(const char_t* name); - xml_node insert_child_after(const char_t* name, const xml_node& node); - xml_node insert_child_before(const char_t* name, const xml_node& node); + xml_node append_child(string_view name); + xml_node prepend_child(string_view name); + xml_node insert_child_after(string_view name, const xml_node& node); + xml_node insert_child_before(string_view name, const xml_node& node); // 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); From b79d5806cc9fe33377b255aecd8e3e369859b958 Mon Sep 17 00:00:00 2001 From: halx99 Date: Wed, 29 Sep 2021 14:56:23 +0800 Subject: [PATCH 04/43] Use basic_string_view instead of string_view --- src/pugixml.cpp | 30 ++++++++++++------------- src/pugixml.hpp | 59 +++++++++++++++++++++++++++---------------------- 2 files changed, 47 insertions(+), 42 deletions(-) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index db19bf0a..55fd9ac3 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -5258,7 +5258,7 @@ namespace pugi return _attr; } - PUGI__FN xml_attribute& xml_attribute::operator=(string_view rhs) + PUGI__FN xml_attribute& xml_attribute::operator=(string_view_t rhs) { set_value(rhs); return *this; @@ -5320,14 +5320,14 @@ namespace pugi } #endif - PUGI__FN bool xml_attribute::set_name(string_view rhs) + PUGI__FN bool xml_attribute::set_name(string_view_t rhs) { if (!_attr) return false; return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs.data(), rhs.length()); } - PUGI__FN bool xml_attribute::set_value(string_view rhs) + PUGI__FN bool xml_attribute::set_value(string_view_t rhs) { if (!_attr) return false; @@ -5674,7 +5674,7 @@ namespace pugi return _root && _root->first_child ? xml_node(_root->first_child->prev_sibling_c) : xml_node(); } - PUGI__FN bool xml_node::set_name(string_view rhs) + PUGI__FN bool xml_node::set_name(string_view_t rhs) { xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null; @@ -5684,7 +5684,7 @@ namespace pugi return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs.data(), rhs.length()); } - PUGI__FN bool xml_node::set_value(string_view rhs) + PUGI__FN bool xml_node::set_value(string_view_t rhs) { xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null; @@ -5694,7 +5694,7 @@ namespace pugi return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs.data(), rhs.length()); } - PUGI__FN xml_attribute xml_node::append_attribute(string_view name_) + PUGI__FN xml_attribute xml_node::append_attribute(string_view_t name_) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); @@ -5711,7 +5711,7 @@ namespace pugi return a; } - PUGI__FN xml_attribute xml_node::prepend_attribute(string_view name_) + PUGI__FN xml_attribute xml_node::prepend_attribute(string_view_t name_) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); @@ -5728,7 +5728,7 @@ namespace pugi return a; } - PUGI__FN xml_attribute xml_node::insert_attribute_after(string_view name_, const xml_attribute& attr) + PUGI__FN xml_attribute xml_node::insert_attribute_after(string_view_t name_, const xml_attribute& attr) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); @@ -5746,7 +5746,7 @@ namespace pugi return a; } - PUGI__FN xml_attribute xml_node::insert_attribute_before(string_view name_, const xml_attribute& attr) + PUGI__FN xml_attribute xml_node::insert_attribute_before(string_view_t name_, const xml_attribute& attr) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); @@ -5904,7 +5904,7 @@ namespace pugi return n; } - PUGI__FN xml_node xml_node::append_child(string_view name_) + PUGI__FN xml_node xml_node::append_child(string_view_t name_) { xml_node result = append_child(node_element); @@ -5913,7 +5913,7 @@ namespace pugi return result; } - PUGI__FN xml_node xml_node::prepend_child(string_view name_) + PUGI__FN xml_node xml_node::prepend_child(string_view_t name_) { xml_node result = prepend_child(node_element); @@ -5922,7 +5922,7 @@ namespace pugi return result; } - PUGI__FN xml_node xml_node::insert_child_after(string_view name_, const xml_node& node) + PUGI__FN xml_node xml_node::insert_child_after(string_view_t name_, const xml_node& node) { xml_node result = insert_child_after(node_element, node); @@ -5931,7 +5931,7 @@ namespace pugi return result; } - PUGI__FN xml_node xml_node::insert_child_before(string_view name_, const xml_node& node) + PUGI__FN xml_node xml_node::insert_child_before(string_view_t name_, const xml_node& node) { xml_node result = insert_child_before(node_element, node); @@ -6537,7 +6537,7 @@ namespace pugi } #endif - PUGI__FN bool xml_text::set(string_view rhs) + PUGI__FN bool xml_text::set(string_view_t rhs) { xml_node_struct* dn = _data_new(); @@ -6623,7 +6623,7 @@ namespace pugi } #endif - PUGI__FN xml_text& xml_text::operator=(string_view rhs) + PUGI__FN xml_text& xml_text::operator=(string_view_t rhs) { set(rhs); return *this; diff --git a/src/pugixml.hpp b/src/pugixml.hpp index 062b5fa2..6b4a097e 100644 --- a/src/pugixml.hpp +++ b/src/pugixml.hpp @@ -139,18 +139,8 @@ # define PUGIXML_CHAR char #endif -namespace pugi -{ - // Character type used for all internal storage and operations; depends on PUGIXML_WCHAR_MODE - typedef PUGIXML_CHAR char_t; -#ifndef PUGIXML_NO_STL - // String type used for operations that work with STL string; depends on PUGIXML_WCHAR_MODE - typedef std::basic_string, std::allocator > string_t; -#endif -} - -// string_view +// The string_view namespace pugi { #if defined(PUGI_CXX17_FEATURES) && PUGI_CXX17_FEATURES template > @@ -291,7 +281,8 @@ namespace pugi { #endif } // namespace pugi -// explicit boolean type +// The explicit boolean type to avoid compiler ambiguous match const char_t* as scalar type 'bool', +// because we preferred compiler match const char_t* as string_view_t namespace pugi { struct boolean { boolean() : value(false) {} @@ -301,6 +292,20 @@ namespace pugi { }; static const boolean true_value{ true }; static const boolean false_value{ false }; +} // namespace pugi + +namespace pugi +{ + // Character type used for all internal storage and operations; depends on PUGIXML_WCHAR_MODE + typedef PUGIXML_CHAR char_t; + +#ifndef PUGIXML_NO_STL + // String type used for operations that work with STL string; depends on PUGIXML_WCHAR_MODE + typedef std::basic_string, std::allocator > string_t; +#endif + + // string_view type used for operations that work with pugi::string_view, depends on PUGIXML_WCHAR_MODE + typedef pugi::basic_string_view > string_view_t; } // The PugiXML namespace @@ -578,8 +583,8 @@ namespace pugi bool as_bool(bool def = false) const; // Set attribute name/value (returns false if attribute is empty or there is not enough memory) - bool set_name(string_view rhs); - bool set_value(string_view rhs); + bool set_name(string_view_t rhs); + bool set_value(string_view_t rhs); // Set attribute value with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") bool set_value(int rhs); @@ -598,7 +603,7 @@ namespace pugi #endif // Set attribute value (equivalent to set_value without error checking) - xml_attribute& operator=(string_view rhs); + xml_attribute& operator=(string_view_t rhs); xml_attribute& operator=(int rhs); xml_attribute& operator=(unsigned int rhs); xml_attribute& operator=(long rhs); @@ -712,14 +717,14 @@ namespace pugi 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) - bool set_name(string_view rhs); - bool set_value(string_view rhs); + bool set_name(string_view_t rhs); + bool set_value(string_view_t rhs); // Add attribute with specified name. Returns added attribute, or empty attribute on errors. - xml_attribute append_attribute(string_view name); - xml_attribute prepend_attribute(string_view name); - xml_attribute insert_attribute_after(string_view name, const xml_attribute& attr); - xml_attribute insert_attribute_before(string_view name, const xml_attribute& attr); + xml_attribute append_attribute(string_view_t name); + xml_attribute prepend_attribute(string_view_t name); + xml_attribute insert_attribute_after(string_view_t name, const xml_attribute& attr); + xml_attribute insert_attribute_before(string_view_t name, const xml_attribute& attr); // Add a copy of the specified attribute. Returns added attribute, or empty attribute on errors. xml_attribute append_copy(const xml_attribute& proto); @@ -734,10 +739,10 @@ namespace pugi 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. - xml_node append_child(string_view name); - xml_node prepend_child(string_view name); - xml_node insert_child_after(string_view name, const xml_node& node); - xml_node insert_child_before(string_view name, const xml_node& node); + xml_node append_child(string_view_t name); + xml_node prepend_child(string_view_t name); + xml_node insert_child_after(string_view_t name, const xml_node& node); + xml_node insert_child_before(string_view_t name, const xml_node& node); // 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); @@ -938,7 +943,7 @@ namespace pugi bool as_bool(bool def = false) const; // Set text (returns false if object is empty or there is not enough memory) - bool set(string_view rhs); + bool set(string_view_t rhs); // Set text with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") bool set(int rhs); @@ -957,7 +962,7 @@ namespace pugi #endif // Set text (equivalent to set without error checking) - xml_text& operator=(string_view rhs); + xml_text& operator=(string_view_t rhs); xml_text& operator=(int rhs); xml_text& operator=(unsigned int rhs); xml_text& operator=(long rhs); From 5f1eb20568e6d3fce9b6dd342136c134bdf4dedb Mon Sep 17 00:00:00 2001 From: halx99 Date: Wed, 29 Sep 2021 15:19:22 +0800 Subject: [PATCH 05/43] Fix appveyor msvc120 compile error --- src/pugixml.hpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/pugixml.hpp b/src/pugixml.hpp index 6b4a097e..ddfa4adf 100644 --- a/src/pugixml.hpp +++ b/src/pugixml.hpp @@ -147,9 +147,6 @@ namespace pugi { using basic_string_view = std::basic_string_view; typedef std::string_view string_view; typedef std::wstring_view wstring_view; - typedef std::u16string_view u16string_view; - typedef std::u32string_view u32string_view; - typedef std::hash string_view_hash; #else template > struct basic_string_view { @@ -273,11 +270,8 @@ namespace std { } // namespace std namespace pugi { - using string_view = basic_string_view; - using wstring_view = basic_string_view; - using u16string_view = basic_string_view; - using u32string_view = basic_string_view; - using string_view_hash = std::hash; + typedef basic_string_view string_view; + typedef basic_string_view wstring_view; #endif } // namespace pugi From 4ed7a7f746e7fbeee1bd66bd488beaaa4cdb9fa9 Mon Sep 17 00:00:00 2001 From: halx99 Date: Wed, 29 Sep 2021 16:48:25 +0800 Subject: [PATCH 06/43] Fix compile issue for compiler without cpp11 --- src/pugixml.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pugixml.hpp b/src/pugixml.hpp index ddfa4adf..b892db58 100644 --- a/src/pugixml.hpp +++ b/src/pugixml.hpp @@ -284,8 +284,8 @@ namespace pugi { bool value; operator bool() const { return value; } }; - static const boolean true_value{ true }; - static const boolean false_value{ false }; + static const boolean true_value(true); + static const boolean false_value(false); } // namespace pugi namespace pugi From fd795fdf64f5698d238ab11942c9455d4adeddc0 Mon Sep 17 00:00:00 2001 From: halx99 Date: Wed, 29 Sep 2021 17:01:12 +0800 Subject: [PATCH 07/43] Avoid unnecessary strlen operations --- src/pugixml.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index 55fd9ac3..7ab0ab78 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -4648,18 +4648,18 @@ PUGI__NS_BEGIN // set value with conversion functions template - PUGI__FN bool set_value_ascii(String& dest, Header& header, uintptr_t header_mask, char* buf) + PUGI__FN bool set_value_ascii(String& dest, Header& header, uintptr_t header_mask, char* buf, size_t len) { #ifdef PUGIXML_WCHAR_MODE char_t wbuf[128]; - assert(strlen(buf) < sizeof(wbuf) / sizeof(wbuf[0])); + assert(len < sizeof(wbuf) / sizeof(wbuf[0])); size_t offset = 0; for (; buf[offset]; ++offset) wbuf[offset] = buf[offset]; return strcpy_insitu(dest, header, header_mask, wbuf, offset); #else - return strcpy_insitu(dest, header, header_mask, buf, strlen(buf)); + return strcpy_insitu(dest, header, header_mask, buf, len); #endif } @@ -4677,18 +4677,18 @@ PUGI__NS_BEGIN PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, float value, int precision) { char buf[128]; - PUGI__SNPRINTF(buf, "%.*g", precision, double(value)); + int n = PUGI__SNPRINTF(buf, "%.*g", precision, double(value)); - return set_value_ascii(dest, header, header_mask, buf); + return set_value_ascii(dest, header, header_mask, buf, n); } template PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, double value, int precision) { char buf[128]; - PUGI__SNPRINTF(buf, "%.*g", precision, value); + int n = PUGI__SNPRINTF(buf, "%.*g", precision, value); - return set_value_ascii(dest, header, header_mask, buf); + return set_value_ascii(dest, header, header_mask, buf, n); } template From e3af24413db411b1acb284a601f82ab8a3762edb Mon Sep 17 00:00:00 2001 From: halx99 Date: Thu, 30 Sep 2021 08:26:45 +0800 Subject: [PATCH 08/43] Fix for non-cpp11 compiler --- src/pugixml.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pugixml.hpp b/src/pugixml.hpp index b892db58..e3c1da01 100644 --- a/src/pugixml.hpp +++ b/src/pugixml.hpp @@ -143,12 +143,12 @@ // The string_view namespace pugi { #if defined(PUGI_CXX17_FEATURES) && PUGI_CXX17_FEATURES - template > + template > using basic_string_view = std::basic_string_view; typedef std::string_view string_view; typedef std::wstring_view wstring_view; #else - template > + template > struct basic_string_view { std::size_t s; const Char* p; @@ -231,7 +231,7 @@ namespace pugi { } }; - template > + template > struct basic_string_view_hash { typedef basic_string_view argument_type; typedef std::size_t result_type; From bffbcfddd3f8e83e310f59206a39281ab8bbfdc0 Mon Sep 17 00:00:00 2001 From: halx99 Date: Thu, 30 Sep 2021 08:46:06 +0800 Subject: [PATCH 09/43] Fix for non-cpp11 compiler --- src/pugixml.hpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/pugixml.hpp b/src/pugixml.hpp index e3c1da01..b9b2c721 100644 --- a/src/pugixml.hpp +++ b/src/pugixml.hpp @@ -150,17 +150,17 @@ namespace pugi { #else template > struct basic_string_view { - std::size_t s; const Char* p; - + std::size_t s; + basic_string_view(const std::string& r) - : basic_string_view(r.data(), r.size()) { + : p(r.data()), s(r.size()) { } basic_string_view(const Char* ptr) - : basic_string_view(ptr, Traits::length(ptr)) { + : p(ptr), s(Traits::length(ptr)) { } basic_string_view(const Char* ptr, std::size_t sz) - : s(sz), p(ptr) { + : p(ptr), s(sz) { } static int compare(const Char* lhs_p, std::size_t lhs_sz, const Char* rhs_p, std::size_t rhs_sz) { @@ -242,9 +242,6 @@ namespace pugi { } result_type operator()(const argument_type& r) const { -#if defined(SOL_USE_BOOST) && SOL_USE_BOOST - return boost::hash_range(r.begin(), r.end()); -#else // Modified, from libstdc++ // An implementation attempt at Fowler No Voll, 1a. // Supposedly, used in MSVC, @@ -259,7 +256,6 @@ namespace pugi { hash *= static_cast(1099511628211ULL); } return hash; -#endif } }; } // namespace pugi From dbced76d857ea84be5159d9805290cc5b2ae561b Mon Sep 17 00:00:00 2001 From: halx99 Date: Thu, 30 Sep 2021 11:30:17 +0800 Subject: [PATCH 10/43] Update pugixml.hpp --- src/pugixml.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pugixml.hpp b/src/pugixml.hpp index b9b2c721..62052f64 100644 --- a/src/pugixml.hpp +++ b/src/pugixml.hpp @@ -262,7 +262,7 @@ namespace pugi { namespace std { template - struct hash< ::pugi::basic_string_view > : ::pugi::basic_string_view_hash {}; + struct hash > : pugi::basic_string_view_hash {}; } // namespace std namespace pugi { From 485270889426d9b9d7438bcfbdec08521a29d7ab Mon Sep 17 00:00:00 2001 From: halx99 Date: Thu, 30 Sep 2021 11:42:35 +0800 Subject: [PATCH 11/43] Fix for non-cpp11 compiler --- src/pugixml.hpp | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/src/pugixml.hpp b/src/pugixml.hpp index 62052f64..3076e37b 100644 --- a/src/pugixml.hpp +++ b/src/pugixml.hpp @@ -230,41 +230,8 @@ namespace pugi { return !(*this == r); } }; - - template > - struct basic_string_view_hash { - typedef basic_string_view argument_type; - typedef std::size_t result_type; - - template - result_type operator()(const std::basic_string& r) const { - return (*this)(argument_type(r.c_str(), r.size())); - } - - result_type operator()(const argument_type& r) const { - // Modified, from libstdc++ - // An implementation attempt at Fowler No Voll, 1a. - // Supposedly, used in MSVC, - // GCC (libstdc++) uses MurmurHash of some sort for 64-bit though...? - // But, well. Can't win them all, right? - // This should normally only apply when NOT using boost, - // so this should almost never be tapped into... - std::size_t hash = 0; - const unsigned char* cptr = reinterpret_cast(r.data()); - for (std::size_t sz = r.size(); sz != 0; --sz) { - hash ^= static_cast(*cptr++); - hash *= static_cast(1099511628211ULL); - } - return hash; - } - }; } // namespace pugi -namespace std { - template - struct hash > : pugi::basic_string_view_hash {}; -} // namespace std - namespace pugi { typedef basic_string_view string_view; typedef basic_string_view wstring_view; From 0d9a3039910a715287c97afe4de14b5688745ef2 Mon Sep 17 00:00:00 2001 From: halx99 Date: Thu, 30 Sep 2021 13:00:58 +0800 Subject: [PATCH 12/43] Add shallow_copy support for improve performance of literal string --- src/pugixml.cpp | 67 +++++++++++++++++++++++++------------------------ src/pugixml.hpp | 26 +++++++++---------- 2 files changed, 47 insertions(+), 46 deletions(-) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index 7ab0ab78..3eabaf62 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -432,6 +432,7 @@ PUGI__NS_BEGIN #endif // 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_name_allocated_mask = 32; static const uintptr_t xml_memory_page_value_allocated_mask = 16; @@ -2354,9 +2355,9 @@ PUGI__NS_BEGIN } template - 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 xml_allocator* alloc = PUGI__GETPAGE_IMPL(header)->allocator; @@ -2364,7 +2365,7 @@ PUGI__NS_BEGIN if (header & header_mask) alloc->deallocate_string(dest); // mark the string as not allocated - dest = 0; + dest = !shallow_copy ? nullptr : const_cast(source); header &= ~header_mask; return true; @@ -5320,18 +5321,18 @@ namespace pugi } #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; - 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; - 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) @@ -5674,27 +5675,27 @@ namespace pugi 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; if (type_ != node_element && type_ != node_pi && type_ != node_declaration) 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; if (type_ != node_pcdata && type_ != node_cdata && type_ != node_comment && type_ != node_pi && type_ != node_doctype) 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(); @@ -5706,12 +5707,12 @@ namespace pugi impl::append_attribute(a._attr, _root); - a.set_name(name_); + a.set_name(name_, shallow_copy); 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(); @@ -5723,12 +5724,12 @@ namespace pugi impl::prepend_attribute(a._attr, _root); - a.set_name(name_); + a.set_name(name_, shallow_copy); 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 (!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); - a.set_name(name_); + a.set_name(name_, shallow_copy); 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 (!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); - a.set_name(name_); + a.set_name(name_, shallow_copy); return a; } @@ -5846,7 +5847,7 @@ namespace pugi 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; } @@ -5863,7 +5864,7 @@ namespace pugi 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; } @@ -5881,7 +5882,7 @@ namespace pugi 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; } @@ -5899,43 +5900,43 @@ namespace pugi 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; } - 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); - result.set_name(name_); + result.set_name(name_, shallow_copy); 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); - result.set_name(name_); + result.set_name(name_, shallow_copy); 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); - result.set_name(name_); + result.set_name(name_, shallow_copy); 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); - result.set_name(name_); + result.set_name(name_, shallow_copy); return result; } @@ -6537,11 +6538,11 @@ namespace pugi } #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(); - 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) diff --git a/src/pugixml.hpp b/src/pugixml.hpp index 3076e37b..53edae8a 100644 --- a/src/pugixml.hpp +++ b/src/pugixml.hpp @@ -540,8 +540,8 @@ namespace pugi bool as_bool(bool def = false) const; // 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_value(string_view_t rhs); + bool set_name(string_view_t rhs, bool shallow_copy = false); + 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") bool set_value(int rhs); @@ -674,14 +674,14 @@ namespace pugi 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) - bool set_name(string_view_t rhs); - bool set_value(string_view_t rhs); + bool set_name(string_view_t rhs, bool shallow_copy = false); + bool set_value(string_view_t rhs, bool shallow_copy = false); // Add attribute with specified name. Returns added attribute, or empty attribute on errors. - xml_attribute append_attribute(string_view_t name); - xml_attribute prepend_attribute(string_view_t name); - xml_attribute insert_attribute_after(string_view_t name, const xml_attribute& attr); - xml_attribute insert_attribute_before(string_view_t name, const xml_attribute& attr); + xml_attribute append_attribute(string_view_t name, bool shallow_copy = false); + 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, bool shallow_copy = false); + 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. 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); // Add child element with specified name. Returns added node, or empty node on errors. - xml_node append_child(string_view_t name); - xml_node prepend_child(string_view_t name); - xml_node insert_child_after(string_view_t name, const xml_node& node); - xml_node insert_child_before(string_view_t name, const xml_node& node); + xml_node append_child(string_view_t name, bool shallow_copy = false); + 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, bool shallow_copy = false); + 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. xml_node append_copy(const xml_node& proto); @@ -900,7 +900,7 @@ namespace pugi bool as_bool(bool def = false) const; // 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") bool set(int rhs); From 366113e72e3cf85896fa9f857bc0e899e07408dd Mon Sep 17 00:00:00 2001 From: halx99 Date: Thu, 30 Sep 2021 13:27:39 +0800 Subject: [PATCH 13/43] Make logic more clearly --- src/pugixml.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index 3eabaf62..d5ec1ad2 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -2365,7 +2365,7 @@ PUGI__NS_BEGIN if (header & header_mask) alloc->deallocate_string(dest); // mark the string as not allocated - dest = !shallow_copy ? nullptr : const_cast(source); + dest = source_length ? nullptr : const_cast(source); header &= ~header_mask; return true; From 15cec5f982d64c67c6a16157bd9d51f4ad9791e3 Mon Sep 17 00:00:00 2001 From: halx99 Date: Thu, 30 Sep 2021 14:36:42 +0800 Subject: [PATCH 14/43] Fix logic --- src/pugixml.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index d5ec1ad2..7aa6f9e0 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -2365,7 +2365,7 @@ PUGI__NS_BEGIN if (header & header_mask) alloc->deallocate_string(dest); // mark the string as not allocated - dest = source_length ? nullptr : const_cast(source); + dest = source_length == 0 ? nullptr : const_cast(source); header &= ~header_mask; return true; From bd0fd028603a05b7d12f0ddae222b62b0ffe8d92 Mon Sep 17 00:00:00 2001 From: halx99 Date: Thu, 30 Sep 2021 14:39:01 +0800 Subject: [PATCH 15/43] Delete unused --- src/pugixml.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index 7aa6f9e0..85638bca 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -432,7 +432,6 @@ PUGI__NS_BEGIN #endif // 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_name_allocated_mask = 32; static const uintptr_t xml_memory_page_value_allocated_mask = 16; From 909b3b65f1f3c9deeae840f25d21836f00e1341c Mon Sep 17 00:00:00 2001 From: halx99 Date: Thu, 23 Dec 2021 15:13:59 +0800 Subject: [PATCH 16/43] Add length field for name & value --- src/pugixml.cpp | 106 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 70 insertions(+), 36 deletions(-) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index 85638bca..cec242bc 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -1104,6 +1104,9 @@ namespace pugi char_t* name; char_t* value; + int name_len; + int value_len; + xml_attribute_struct* prev_attribute_c; xml_attribute_struct* next_attribute; }; @@ -1119,6 +1122,8 @@ namespace pugi char_t* name; char_t* value; + int name_len; + int value_len; xml_node_struct* parent; @@ -2593,14 +2598,16 @@ PUGI__NS_BEGIN #define PUGI__SCANFOR(X) { while (*s != 0 && !(X)) ++s; } #define PUGI__SCANWHILE(X) { while (X) ++s; } #define PUGI__SCANWHILE_UNROLL(X) { for (;;) { char_t ss = s[0]; if (PUGI__UNLIKELY(!(X))) { break; } ss = s[1]; if (PUGI__UNLIKELY(!(X))) { s += 1; break; } ss = s[2]; if (PUGI__UNLIKELY(!(X))) { s += 2; break; } ss = s[3]; if (PUGI__UNLIKELY(!(X))) { s += 3; break; } s += 4; } } - #define PUGI__ENDSEG() { ch = *s; *s = 0; ++s; } + #define PUGI__ENDSEG(p,v) { ch = *s; p->v##_len = static_cast(s - p->v); *s = '\0'; ++s; } #define PUGI__THROW_ERROR(err, m) return error_offset = m, error_status = err, static_cast(0) #define PUGI__CHECK_ERROR(err, m) { if (*s == 0) PUGI__THROW_ERROR(err, m); } - PUGI__FN char_t* strconv_comment(char_t* s, char_t endch) + PUGI__FN char_t* strconv_comment(char_t* s, char_t endch, int& len) { gap g; + char_t* begin = s; + while (true) { PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_comment)); @@ -2613,7 +2620,9 @@ PUGI__NS_BEGIN } else if (s[0] == '-' && s[1] == '-' && PUGI__ENDSWITH(s[2], '>')) // comment ends here { - *g.flush(s) = 0; + auto end = g.flush(s); + *end = '\0'; + len = static_cast(end - begin); return s + (s[2] == '>' ? 3 : 2); } @@ -2625,10 +2634,12 @@ PUGI__NS_BEGIN } } - PUGI__FN char_t* strconv_cdata(char_t* s, char_t endch) + PUGI__FN char_t* strconv_cdata(char_t* s, char_t endch, int& len) { gap g; + char_t* begin = s; + while (true) { PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_cdata)); @@ -2641,7 +2652,9 @@ PUGI__NS_BEGIN } else if (s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>')) // CDATA ends here { - *g.flush(s) = 0; + auto end = g.flush(s); + *end = '\0'; + len = static_cast(end - begin); return s + 1; } @@ -2653,11 +2666,11 @@ PUGI__NS_BEGIN } } - typedef char_t* (*strconv_pcdata_t)(char_t*); + typedef char_t* (*strconv_pcdata_t)(char_t*, int& len); template struct strconv_pcdata_impl { - static char_t* parse(char_t* s) + static char_t* parse(char_t* s, int& len) { gap g; @@ -2675,7 +2688,8 @@ PUGI__NS_BEGIN while (end > begin && PUGI__IS_CHARTYPE(end[-1], ct_space)) --end; - *end = 0; + *end = '\0'; + len = static_cast(end - begin); return s + 1; } @@ -2697,7 +2711,8 @@ PUGI__NS_BEGIN while (end > begin && PUGI__IS_CHARTYPE(end[-1], ct_space)) --end; - *end = 0; + *end = '\0'; + len = static_cast(end - begin); return s; } @@ -2724,14 +2739,16 @@ PUGI__NS_BEGIN } } - typedef char_t* (*strconv_attribute_t)(char_t*, char_t); + typedef char_t* (*strconv_attribute_t)(char_t*, char_t, int& len); template struct strconv_attribute_impl { - static char_t* parse_wnorm(char_t* s, char_t end_quote) + static char_t* parse_wnorm(char_t* s, char_t end_quote, int& len) { gap g; + char_t* begin = s; + // trim leading whitespaces if (PUGI__IS_CHARTYPE(*s, ct_space)) { @@ -2751,9 +2768,11 @@ PUGI__NS_BEGIN { char_t* str = g.flush(s); - do *str-- = 0; + do *str-- = '\0'; while (PUGI__IS_CHARTYPE(*str, ct_space)); + len = static_cast(str + 1 - begin); + return s + 1; } else if (PUGI__IS_CHARTYPE(*s, ct_space)) @@ -2780,17 +2799,21 @@ PUGI__NS_BEGIN } } - static char_t* parse_wconv(char_t* s, char_t end_quote) + static char_t* parse_wconv(char_t* s, char_t end_quote, int& len) { gap g; + char_t* begin = s; + while (true) { PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr_ws)); if (*s == end_quote) { - *g.flush(s) = 0; + auto end = g.flush(s); + *end = '\0'; + len = static_cast(end - begin); return s + 1; } @@ -2816,17 +2839,21 @@ PUGI__NS_BEGIN } } - static char_t* parse_eol(char_t* s, char_t end_quote) + static char_t* parse_eol(char_t* s, char_t end_quote, int& len) { gap g; + char_t* begin = s; + while (true) { PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr)); if (*s == end_quote) { - *g.flush(s) = 0; + auto end = g.flush(s); + *end = '\0'; + len = static_cast(end - begin); return s + 1; } @@ -2848,17 +2875,21 @@ PUGI__NS_BEGIN } } - static char_t* parse_simple(char_t* s, char_t end_quote) + static char_t* parse_simple(char_t* s, char_t end_quote, int& len) { gap g; + char_t* begin = s; + while (true) { PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr)); if (*s == end_quote) { - *g.flush(s) = 0; + auto end = g.flush(s); + *end = '\0'; + len = static_cast(end - begin); return s + 1; } @@ -3058,7 +3089,7 @@ PUGI__NS_BEGIN if (PUGI__OPTSET(parse_eol) && PUGI__OPTSET(parse_comments)) { - s = strconv_comment(s, endch); + s = strconv_comment(s, endch, cursor->value_len); if (!s) PUGI__THROW_ERROR(status_bad_comment, cursor->value); } @@ -3068,9 +3099,10 @@ PUGI__NS_BEGIN PUGI__SCANFOR(s[0] == '-' && s[1] == '-' && PUGI__ENDSWITH(s[2], '>')); PUGI__CHECK_ERROR(status_bad_comment, s); - if (PUGI__OPTSET(parse_comments)) - *s = 0; // Zero-terminate this segment at the first terminating '-'. - + if (PUGI__OPTSET(parse_comments)) { + *s = '\0'; // Zero-terminate this segment at the first terminating '-'. + cursor->value_len = static_cast(s - cursor->value); + } s += (s[2] == '>' ? 3 : 2); // Step over the '\0->'. } } @@ -3090,7 +3122,7 @@ PUGI__NS_BEGIN if (PUGI__OPTSET(parse_eol)) { - s = strconv_cdata(s, endch); + s = strconv_cdata(s, endch, cursor->value_len); if (!s) PUGI__THROW_ERROR(status_bad_cdata, cursor->value); } @@ -3100,7 +3132,8 @@ PUGI__NS_BEGIN PUGI__SCANFOR(s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>')); PUGI__CHECK_ERROR(status_bad_cdata, s); - *s++ = 0; // Zero-terminate this segment. + cursor->value_len = s - cursor->value; + *s++ = '\0'; // Zero-terminate this segment. } } else // Flagged for discard, but we still have to scan for the terminator. @@ -3128,7 +3161,7 @@ PUGI__NS_BEGIN if (!s) return s; assert((*s == 0 && endch == '>') || *s == '>'); - if (*s) *s++ = 0; + if (*s) *s++ = '\0'; if (PUGI__OPTSET(parse_doctype)) { @@ -3137,6 +3170,7 @@ PUGI__NS_BEGIN PUGI__PUSHNODE(node_doctype); cursor->value = mark; + cursor->value_len = static_cast(s - mark - 1); } } else if (*s == 0 && endch == '-') PUGI__THROW_ERROR(status_bad_comment, s); @@ -3182,7 +3216,7 @@ PUGI__NS_BEGIN cursor->name = target; - PUGI__ENDSEG(); + PUGI__ENDSEG(cursor, name); // parse value/attributes if (ch == '?') @@ -3215,11 +3249,9 @@ PUGI__NS_BEGIN { // store value and step over > cursor->value = value; - + PUGI__ENDSEG(cursor, value); PUGI__POPNODE(); - PUGI__ENDSEG(); - s += (*s == '>'); } } @@ -3263,7 +3295,7 @@ PUGI__NS_BEGIN cursor->name = s; PUGI__SCANWHILE_UNROLL(PUGI__IS_CHARTYPE(ss, ct_symbol)); // Scan for a terminator. - PUGI__ENDSEG(); // Save char in 'ch', terminate & step over. + PUGI__ENDSEG(cursor, name); // Save char in 'ch', terminate & step over. if (ch == '>') { @@ -3284,7 +3316,7 @@ PUGI__NS_BEGIN a->name = s; // Save the offset. PUGI__SCANWHILE_UNROLL(PUGI__IS_CHARTYPE(ss, ct_symbol)); // Scan for a terminator. - PUGI__ENDSEG(); // Save char in 'ch', terminate & step over. + PUGI__ENDSEG(a, name); // Save char in 'ch', terminate & step over. if (PUGI__IS_CHARTYPE(ch, ct_space)) { @@ -3304,7 +3336,7 @@ PUGI__NS_BEGIN ++s; // Step over the quote. a->value = s; // Save the offset. - s = strconv_attribute(s, ch); + s = strconv_attribute(s, ch, a->value_len); if (!s) PUGI__THROW_ERROR(status_bad_attribute, a->value); @@ -3442,20 +3474,22 @@ PUGI__NS_BEGIN if (cursor->parent || PUGI__OPTSET(parse_fragment)) { + pugi::xml_node_struct* target; if (PUGI__OPTSET(parse_embed_pcdata) && cursor->parent && !cursor->first_child && !cursor->value) { - cursor->value = s; // Save the offset. + target = cursor; // cursor->value = s; // Save the offset. } else { PUGI__PUSHNODE(node_pcdata); // Append a new node on the tree. - cursor->value = s; // Save the offset. + target = cursor; // cursor->value = s; // Save the offset. PUGI__POPNODE(); // Pop since this is a standalone. } - s = strconv_pcdata(s); + target->value = s; + s = strconv_pcdata(s, target->value_len); if (!*s) break; } @@ -8376,7 +8410,7 @@ PUGI__NS_BEGIN // zero-terminate assert(s < result + result_size); - *s = 0; + *s = '\0'; return xpath_string::from_heap_preallocated(result, s); } From 69e24c7fdd85c0322da787e758ae4deaf3308d3c Mon Sep 17 00:00:00 2001 From: halx99 Date: Thu, 23 Dec 2021 15:45:20 +0800 Subject: [PATCH 17/43] Add string_view name & value getter with suffix for compatible --- src/pugixml.cpp | 61 ++++++++++++++++++++++++++++++++++++++++++++++++- src/pugixml.hpp | 10 ++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index cec242bc..cb8bfa38 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -3132,7 +3132,7 @@ PUGI__NS_BEGIN PUGI__SCANFOR(s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>')); PUGI__CHECK_ERROR(status_bad_cdata, s); - cursor->value_len = s - cursor->value; + cursor->value_len = static_cast(s - cursor->value); *s++ = '\0'; // Zero-terminate this segment. } } @@ -5230,6 +5230,11 @@ namespace pugi return (_attr && _attr->value) ? _attr->value + 0 : def; } + PUGI__FN string_view_t xml_attribute::as_string_sv(string_view_t def) const + { + return (_attr && _attr->value) ? string_view_t(_attr->value + 0, _attr->value_len) : def; + } + PUGI__FN int xml_attribute::as_int(int def) const { return (_attr && _attr->value) ? impl::get_value_int(_attr->value) : def; @@ -5277,11 +5282,21 @@ namespace pugi return (_attr && _attr->name) ? _attr->name + 0 : PUGIXML_TEXT(""); } + PUGI__FN string_view_t xml_attribute::name_sv() const + { + return (_attr && _attr->name) ? string_view_t(_attr->name + 0, _attr->name_len) : string_view_t(PUGIXML_TEXT(""), 0); + } + PUGI__FN const char_t* xml_attribute::value() const { return (_attr && _attr->value) ? _attr->value + 0 : PUGIXML_TEXT(""); } + PUGI__FN string_view_t xml_attribute::value_sv() const + { + return (_attr && _attr->value) ? string_view_t(_attr->value + 0, _attr->value_len) : string_view_t(PUGIXML_TEXT(""), 0); + } + PUGI__FN size_t xml_attribute::hash_value() const { return static_cast(reinterpret_cast(_attr) / sizeof(xml_attribute_struct)); @@ -5556,6 +5571,11 @@ namespace pugi return (_root && _root->name) ? _root->name + 0 : PUGIXML_TEXT(""); } + PUGI__FN string_view_t xml_node::name_sv() const + { + return (_root && _root->name) ? string_view_t(_root->name + 0, _root->name_len) : string_view_t(PUGIXML_TEXT(""), 0); + } + PUGI__FN xml_node_type xml_node::type() const { return _root ? PUGI__NODETYPE(_root) : node_null; @@ -5566,6 +5586,11 @@ namespace pugi return (_root && _root->value) ? _root->value + 0 : PUGIXML_TEXT(""); } + PUGI__FN string_view_t xml_node::value_sv() const + { + return (_root && _root->value) ? string_view_t(_root->value + 0, _root->value_len) : string_view_t(PUGIXML_TEXT(""), 0); + } + PUGI__FN xml_node xml_node::child(const char_t* name_) const { if (!_root) return xml_node(); @@ -5683,11 +5708,31 @@ namespace pugi return PUGIXML_TEXT(""); } + PUGI__FN string_view_t xml_node::child_value_sv() const + { + if (!_root) return string_view_t(PUGIXML_TEXT(""), 0); + + // element nodes can have value if parse_embed_pcdata was used + if (PUGI__NODETYPE(_root) == node_element && _root->value) + return string_view_t(_root->value, _root->value_len); + + for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) + if (impl::is_text_node(i) && i->value) + return string_view_t(i->value, i->value_len); + + return string_view_t(PUGIXML_TEXT(""), 0); + } + PUGI__FN const char_t* xml_node::child_value(const char_t* name_) const { return child(name_).child_value(); } + PUGI__FN string_view_t xml_node::child_value_sv(const char_t* name_) const + { + return child(name_).child_value_sv(); + } + PUGI__FN xml_attribute xml_node::first_attribute() const { return _root ? xml_attribute(_root->first_attribute) : xml_attribute(); @@ -6513,6 +6558,13 @@ namespace pugi return (d && d->value) ? d->value + 0 : PUGIXML_TEXT(""); } + PUGI__FN string_view_t xml_text::get_sv() const + { + xml_node_struct* d = _data(); + + return (d && d->value) ? string_view_t(d->value + 0, d->value_len) : string_view_t(PUGIXML_TEXT(""), 0); + } + PUGI__FN const char_t* xml_text::as_string(const char_t* def) const { xml_node_struct* d = _data(); @@ -6520,6 +6572,13 @@ namespace pugi return (d && d->value) ? d->value + 0 : def; } + PUGI__FN string_view_t xml_text::as_string_sv(string_view_t def) const + { + xml_node_struct* d = _data(); + + return (d && d->value) ? string_view_t(d->value + 0, d->value_len) : def; + } + PUGI__FN int xml_text::as_int(int def) const { xml_node_struct* d = _data(); diff --git a/src/pugixml.hpp b/src/pugixml.hpp index 53edae8a..a43c0a71 100644 --- a/src/pugixml.hpp +++ b/src/pugixml.hpp @@ -520,10 +520,14 @@ namespace pugi // Get attribute name/value, or "" if attribute is empty const char_t* name() const; + string_view_t name_sv() const; + const char_t* value() const; + string_view_t value_sv() const; // Get attribute value, or the default value if attribute is empty const char_t* as_string(const char_t* def = PUGIXML_TEXT("")) const; + string_view_t as_string_sv(string_view_t def = string_view_t(PUGIXML_TEXT(""), 0)) const; // Get attribute value as a number, or the default value if conversion did not succeed or attribute is empty int as_int(int def = 0) const; @@ -632,10 +636,12 @@ namespace pugi // Get node name, or "" if node is empty or it has no name const char_t* name() const; + string_view_t name_sv() const; // Get node value, or "" if node is empty or it has no value // Note: For text node.value() does not return "text"! Use child_value() or text() methods to access text inside nodes. const char_t* value() const; + string_view_t value_sv() const; // Get attribute list xml_attribute first_attribute() const; @@ -669,9 +675,11 @@ namespace pugi // Get child value of current node; that is, value of the first child node of type PCDATA/CDATA const char_t* child_value() const; + string_view_t child_value_sv() const; // Get child value of child with specified name. Equivalent to child(name).child_value(). const char_t* child_value(const char_t* name) const; + string_view_t child_value_sv(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) bool set_name(string_view_t rhs, bool shallow_copy = false); @@ -881,9 +889,11 @@ namespace pugi // Get text, or "" if object is empty const char_t* get() const; + string_view_t get_sv() const; // Get text, or the default value if object is empty const char_t* as_string(const char_t* def = PUGIXML_TEXT("")) const; + string_view_t as_string_sv(string_view_t def = string_view_t(PUGIXML_TEXT(""), 0)) const; // Get text as a number, or the default value if conversion did not succeed or object is empty int as_int(int def = 0) const; From 233d7fd4f36d7b5c5dec92d54a0ed574b8e7c037 Mon Sep 17 00:00:00 2001 From: deal Date: Thu, 23 Dec 2021 16:00:12 +0800 Subject: [PATCH 18/43] Update build.yml --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bf6948b8..52caea47 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,7 +12,7 @@ jobs: matrix: os: [ubuntu, macos] compiler: [g++, clang++] - defines: [standard, PUGIXML_WCHAR_MODE, PUGIXML_COMPACT, PUGIXML_NO_EXCEPTIONS] + defines: [standard, PUGIXML_WCHAR_MODE, PUGIXML_NO_EXCEPTIONS] exclude: - os: macos compiler: g++ @@ -38,7 +38,7 @@ jobs: strategy: matrix: arch: [Win32, x64] - defines: [standard, PUGIXML_WCHAR_MODE, PUGIXML_COMPACT, PUGIXML_NO_EXCEPTIONS] + defines: [standard, PUGIXML_WCHAR_MODE, PUGIXML_NO_EXCEPTIONS] steps: - uses: actions/checkout@v1 - name: cmake configure From 4e4af118380a6ab4308197a97c1e4ffcbc8c05fa Mon Sep 17 00:00:00 2001 From: deal Date: Thu, 23 Dec 2021 16:05:36 +0800 Subject: [PATCH 19/43] Fix warnings on PUGIXML_WCHAR_MODE --- src/pugixml.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index cb8bfa38..7e5148ac 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -4685,6 +4685,7 @@ PUGI__NS_BEGIN PUGI__FN bool set_value_ascii(String& dest, Header& header, uintptr_t header_mask, char* buf, size_t len) { #ifdef PUGIXML_WCHAR_MODE + (void)len; char_t wbuf[128]; assert(len < sizeof(wbuf) / sizeof(wbuf[0])); From b025069fbe714992865d3b765a2d3c823f7ebd9c Mon Sep 17 00:00:00 2001 From: halx99 Date: Thu, 23 Dec 2021 16:11:40 +0800 Subject: [PATCH 20/43] Fix for old compilers --- src/pugixml.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index 7e5148ac..2db585fd 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -2620,7 +2620,7 @@ PUGI__NS_BEGIN } else if (s[0] == '-' && s[1] == '-' && PUGI__ENDSWITH(s[2], '>')) // comment ends here { - auto end = g.flush(s); + char_t* end = g.flush(s); *end = '\0'; len = static_cast(end - begin); @@ -2652,7 +2652,7 @@ PUGI__NS_BEGIN } else if (s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>')) // CDATA ends here { - auto end = g.flush(s); + char_t* end = g.flush(s); *end = '\0'; len = static_cast(end - begin); @@ -2811,7 +2811,7 @@ PUGI__NS_BEGIN if (*s == end_quote) { - auto end = g.flush(s); + char_t* end = g.flush(s); *end = '\0'; len = static_cast(end - begin); @@ -2851,7 +2851,7 @@ PUGI__NS_BEGIN if (*s == end_quote) { - auto end = g.flush(s); + char_t* end = g.flush(s); *end = '\0'; len = static_cast(end - begin); @@ -2887,7 +2887,7 @@ PUGI__NS_BEGIN if (*s == end_quote) { - auto end = g.flush(s); + char_t* end = g.flush(s); *end = '\0'; len = static_cast(end - begin); From 9129d7900cb979cf7e411fa108aa2df42722dbd0 Mon Sep 17 00:00:00 2001 From: halx99 Date: Thu, 23 Dec 2021 16:15:30 +0800 Subject: [PATCH 21/43] Fix ci --- src/pugixml.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index 2db585fd..b73f30e7 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -2369,7 +2369,7 @@ PUGI__NS_BEGIN if (header & header_mask) alloc->deallocate_string(dest); // mark the string as not allocated - dest = source_length == 0 ? nullptr : const_cast(source); + dest = source_length == 0 ? NULL : const_cast(source); header &= ~header_mask; return true; From 7791e7dfbbbfea41ade8c22e0a0f946346582eda Mon Sep 17 00:00:00 2001 From: halx99 Date: Thu, 23 Dec 2021 16:55:08 +0800 Subject: [PATCH 22/43] Store length for setters --- src/pugixml.cpp | 100 ++++++++++++++++++++++++------------------------ 1 file changed, 51 insertions(+), 49 deletions(-) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index b73f30e7..94dc1508 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -2359,8 +2359,10 @@ PUGI__NS_BEGIN } template - 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) + PUGI__FN bool strcpy_insitu(String& dest, int& dest_len, Header& header, uintptr_t header_mask, const char_t* source, size_t source_length, bool shallow_copy = false) { + dest_len = static_cast(source_length); + if (source_length == 0 || shallow_copy) { // empty string and null pointer are equivalent, so just deallocate old memory @@ -2378,7 +2380,7 @@ PUGI__NS_BEGIN { // we can reuse old buffer, so just copy the new data (including zero terminator) memcpy(dest, source, source_length * sizeof(char_t)); - dest[source_length] = 0; + dest[source_length] = '\0'; return true; } @@ -2394,7 +2396,7 @@ PUGI__NS_BEGIN // copy the string (including zero terminator) memcpy(buf, source, source_length * sizeof(char_t)); - buf[source_length] = 0; + buf[source_length] = '\0'; // deallocate old buffer (*after* the above to protect against overlapping memory and/or allocation failures) if (header & header_mask) alloc->deallocate_string(dest); @@ -4422,7 +4424,7 @@ PUGI__NS_BEGIN } template - PUGI__FN void node_copy_string(String& dest, Header& header, uintptr_t header_mask, char_t* source, Header& source_header, xml_allocator* alloc) + PUGI__FN void node_copy_string(String& dest, int& len, Header& header, uintptr_t header_mask, char_t* source, Header& source_header, xml_allocator* alloc) { assert(!dest && (header & header_mask) == 0); @@ -4437,14 +4439,14 @@ PUGI__NS_BEGIN source_header |= xml_memory_page_contents_shared_mask; } else - strcpy_insitu(dest, header, header_mask, source, strlength(source)); + strcpy_insitu(dest, len, header, header_mask, source, strlength(source)); } } PUGI__FN void node_copy_contents(xml_node_struct* dn, xml_node_struct* sn, xml_allocator* shared_alloc) { - node_copy_string(dn->name, dn->header, xml_memory_page_name_allocated_mask, sn->name, sn->header, shared_alloc); - node_copy_string(dn->value, dn->header, xml_memory_page_value_allocated_mask, sn->value, sn->header, shared_alloc); + node_copy_string(dn->name, dn->name_len, dn->header, xml_memory_page_name_allocated_mask, sn->name, sn->header, shared_alloc); + node_copy_string(dn->value, dn->value_len, dn->header, xml_memory_page_value_allocated_mask, sn->value, sn->header, shared_alloc); for (xml_attribute_struct* sa = sn->first_attribute; sa; sa = sa->next_attribute) { @@ -4452,8 +4454,8 @@ PUGI__NS_BEGIN if (da) { - node_copy_string(da->name, da->header, xml_memory_page_name_allocated_mask, sa->name, sa->header, shared_alloc); - node_copy_string(da->value, da->header, xml_memory_page_value_allocated_mask, sa->value, sa->header, shared_alloc); + node_copy_string(da->name, da->name_len, da->header, xml_memory_page_name_allocated_mask, sa->name, sa->header, shared_alloc); + node_copy_string(da->value, da->value_len, da->header, xml_memory_page_value_allocated_mask, sa->value, sa->header, shared_alloc); } } } @@ -4517,8 +4519,8 @@ PUGI__NS_BEGIN xml_allocator& alloc = get_allocator(da); xml_allocator* shared_alloc = (&alloc == &get_allocator(sa)) ? &alloc : 0; - node_copy_string(da->name, da->header, xml_memory_page_name_allocated_mask, sa->name, sa->header, shared_alloc); - node_copy_string(da->value, da->header, xml_memory_page_value_allocated_mask, sa->value, sa->header, shared_alloc); + node_copy_string(da->name, da->name_len, da->header, xml_memory_page_name_allocated_mask, sa->name, sa->header, shared_alloc); + node_copy_string(da->value, da->value_len, da->header, xml_memory_page_value_allocated_mask, sa->value, sa->header, shared_alloc); } inline bool is_text_node(xml_node_struct* node) @@ -4682,7 +4684,7 @@ PUGI__NS_BEGIN // set value with conversion functions template - PUGI__FN bool set_value_ascii(String& dest, Header& header, uintptr_t header_mask, char* buf, size_t len) + PUGI__FN bool set_value_ascii(String& dest, int& dest_len, Header& header, uintptr_t header_mask, char* buf, size_t len) { #ifdef PUGIXML_WCHAR_MODE (void)len; @@ -4692,44 +4694,44 @@ PUGI__NS_BEGIN size_t offset = 0; for (; buf[offset]; ++offset) wbuf[offset] = buf[offset]; - return strcpy_insitu(dest, header, header_mask, wbuf, offset); + return strcpy_insitu(dest, dest_len, header, header_mask, wbuf, offset); #else - return strcpy_insitu(dest, header, header_mask, buf, len); + return strcpy_insitu(dest, dest_len, header, header_mask, buf, len); #endif } template - PUGI__FN bool set_value_integer(String& dest, Header& header, uintptr_t header_mask, U value, bool negative) + PUGI__FN bool set_value_integer(String& dest, int& dest_len, Header& header, uintptr_t header_mask, U value, bool negative) { char_t buf[64]; char_t* end = buf + sizeof(buf) / sizeof(buf[0]); char_t* begin = integer_to_string(buf, end, value, negative); - return strcpy_insitu(dest, header, header_mask, begin, end - begin); + return strcpy_insitu(dest, dest_len, header, header_mask, begin, end - begin); } template - PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, float value, int precision) + PUGI__FN bool set_value_convert(String& dest, int& dest_len, Header& header, uintptr_t header_mask, float value, int precision) { char buf[128]; int n = PUGI__SNPRINTF(buf, "%.*g", precision, double(value)); - return set_value_ascii(dest, header, header_mask, buf, n); + return set_value_ascii(dest, dest_len, header, header_mask, buf, n); } template - PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, double value, int precision) + PUGI__FN bool set_value_convert(String& dest, int& dest_len, Header& header, uintptr_t header_mask, double value, int precision) { char buf[128]; int n = PUGI__SNPRINTF(buf, "%.*g", precision, value); - return set_value_ascii(dest, header, header_mask, buf, n); + return set_value_ascii(dest, dest_len, header, header_mask, buf, n); } template - PUGI__FN bool set_value_bool(String& dest, Header& header, uintptr_t header_mask, bool value) + PUGI__FN bool set_value_bool(String& dest, int& dest_len, Header& header, uintptr_t header_mask, bool value) { - return strcpy_insitu(dest, header, header_mask, value ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"), value ? 4 : 5); + return strcpy_insitu(dest, dest_len, header, header_mask, value ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"), value ? 4 : 5); } PUGI__FN xml_parse_result load_buffer_impl(xml_document_struct* doc, xml_node_struct* root, void* contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own, char_t** out_buffer) @@ -5374,77 +5376,77 @@ namespace pugi { if (!_attr) return false; - return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs.data(), rhs.length(), shallow_copy); + return impl::strcpy_insitu(_attr->name, _attr->name_len, _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, bool shallow_copy) { if (!_attr) return false; - return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs.data(), rhs.length(), shallow_copy); + return impl::strcpy_insitu(_attr->value, _attr->value_len, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs.data(), rhs.length(), shallow_copy); } PUGI__FN bool xml_attribute::set_value(int rhs) { if (!_attr) return false; - return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0); + return impl::set_value_integer(_attr->value, _attr->value_len, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0); } PUGI__FN bool xml_attribute::set_value(unsigned int rhs) { if (!_attr) return false; - return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false); + return impl::set_value_integer(_attr->value, _attr->value_len, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false); } PUGI__FN bool xml_attribute::set_value(long rhs) { if (!_attr) return false; - return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0); + return impl::set_value_integer(_attr->value, _attr->value_len, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0); } PUGI__FN bool xml_attribute::set_value(unsigned long rhs) { if (!_attr) return false; - return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false); + return impl::set_value_integer(_attr->value, _attr->value_len, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false); } PUGI__FN bool xml_attribute::set_value(double rhs) { if (!_attr) return false; - return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, default_double_precision); + return impl::set_value_convert(_attr->value, _attr->value_len, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, default_double_precision); } PUGI__FN bool xml_attribute::set_value(double rhs, int precision) { if (!_attr) return false; - return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, precision); + return impl::set_value_convert(_attr->value, _attr->value_len, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, precision); } PUGI__FN bool xml_attribute::set_value(float rhs) { if (!_attr) return false; - return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, default_float_precision); + return impl::set_value_convert(_attr->value, _attr->value_len, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, default_float_precision); } PUGI__FN bool xml_attribute::set_value(float rhs, int precision) { if (!_attr) return false; - return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, precision); + return impl::set_value_convert(_attr->value, _attr->value_len, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, precision); } PUGI__FN bool xml_attribute::set_value(boolean rhs) { if (!_attr) return false; - return impl::set_value_bool(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); + return impl::set_value_bool(_attr->value, _attr->value_len, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); } #ifdef PUGIXML_HAS_LONG_LONG @@ -5452,14 +5454,14 @@ namespace pugi { if (!_attr) return false; - return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0); + return impl::set_value_integer(_attr->value, _attr->value_len, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0); } PUGI__FN bool xml_attribute::set_value(unsigned long long rhs) { if (!_attr) return false; - return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false); + return impl::set_value_integer(_attr->value, _attr->value_len, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false); } #endif @@ -5761,7 +5763,7 @@ namespace pugi if (type_ != node_element && type_ != node_pi && type_ != node_declaration) return false; - return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs.data(), rhs.length(), shallow_copy); + return impl::strcpy_insitu(_root->name, _root->name_len, _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, bool shallow_copy) @@ -5771,7 +5773,7 @@ namespace pugi if (type_ != node_pcdata && type_ != node_cdata && type_ != node_comment && type_ != node_pi && type_ != node_doctype) return false; - return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs.data(), rhs.length(), shallow_copy); + return impl::strcpy_insitu(_root->value, _root->value_len, _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_, bool shallow_copy) @@ -6635,70 +6637,70 @@ namespace pugi { 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(), shallow_copy) : false; + return dn ? impl::strcpy_insitu(dn->value, dn->value_len, dn->header, impl::xml_memory_page_value_allocated_mask, rhs.data(), rhs.length(), shallow_copy) : false; } PUGI__FN bool xml_text::set(int rhs) { xml_node_struct* dn = _data_new(); - return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false; + return dn ? impl::set_value_integer(dn->value, dn->value_len, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false; } PUGI__FN bool xml_text::set(unsigned int rhs) { xml_node_struct* dn = _data_new(); - return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false; + return dn ? impl::set_value_integer(dn->value, dn->value_len, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false; } PUGI__FN bool xml_text::set(long rhs) { xml_node_struct* dn = _data_new(); - return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false; + return dn ? impl::set_value_integer(dn->value, dn->value_len, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false; } PUGI__FN bool xml_text::set(unsigned long rhs) { xml_node_struct* dn = _data_new(); - return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false; + return dn ? impl::set_value_integer(dn->value, dn->value_len, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false; } PUGI__FN bool xml_text::set(float rhs) { xml_node_struct* dn = _data_new(); - return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, default_float_precision) : false; + return dn ? impl::set_value_convert(dn->value, dn->value_len, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, default_float_precision) : false; } PUGI__FN bool xml_text::set(float rhs, int precision) { xml_node_struct* dn = _data_new(); - return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, precision) : false; + return dn ? impl::set_value_convert(dn->value, dn->value_len, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, precision) : false; } PUGI__FN bool xml_text::set(double rhs) { xml_node_struct* dn = _data_new(); - return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, default_double_precision) : false; + return dn ? impl::set_value_convert(dn->value, dn->value_len, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, default_double_precision) : false; } PUGI__FN bool xml_text::set(double rhs, int precision) { xml_node_struct* dn = _data_new(); - return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, precision) : false; + return dn ? impl::set_value_convert(dn->value, dn->value_len, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, precision) : false; } PUGI__FN bool xml_text::set(boolean rhs) { xml_node_struct* dn = _data_new(); - return dn ? impl::set_value_bool(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; + return dn ? impl::set_value_bool(dn->value, dn->value_len, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; } #ifdef PUGIXML_HAS_LONG_LONG @@ -6706,14 +6708,14 @@ namespace pugi { xml_node_struct* dn = _data_new(); - return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false; + return dn ? impl::set_value_integer(dn->value, dn->value_len, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false; } PUGI__FN bool xml_text::set(unsigned long long rhs) { xml_node_struct* dn = _data_new(); - return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false; + return dn ? impl::set_value_integer(dn->value, dn->value_len, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false; } #endif From b634ea55dfe8288ac899647b12ed205e73a97041 Mon Sep 17 00:00:00 2001 From: halx99 Date: Thu, 23 Dec 2021 17:17:33 +0800 Subject: [PATCH 23/43] Node copy avoid stringlen operation --- src/pugixml.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index 94dc1508..503389d1 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -4424,7 +4424,7 @@ PUGI__NS_BEGIN } template - PUGI__FN void node_copy_string(String& dest, int& len, Header& header, uintptr_t header_mask, char_t* source, Header& source_header, xml_allocator* alloc) + PUGI__FN void node_copy_string(String& dest, int& dest_len, Header& header, uintptr_t header_mask, char_t* source, int source_len, Header& source_header, xml_allocator* alloc) { assert(!dest && (header & header_mask) == 0); @@ -4439,14 +4439,14 @@ PUGI__NS_BEGIN source_header |= xml_memory_page_contents_shared_mask; } else - strcpy_insitu(dest, len, header, header_mask, source, strlength(source)); + strcpy_insitu(dest, dest_len, header, header_mask, source, source_len); } } PUGI__FN void node_copy_contents(xml_node_struct* dn, xml_node_struct* sn, xml_allocator* shared_alloc) { - node_copy_string(dn->name, dn->name_len, dn->header, xml_memory_page_name_allocated_mask, sn->name, sn->header, shared_alloc); - node_copy_string(dn->value, dn->value_len, dn->header, xml_memory_page_value_allocated_mask, sn->value, sn->header, shared_alloc); + node_copy_string(dn->name, dn->name_len, dn->header, xml_memory_page_name_allocated_mask, sn->name, sn->name_len, sn->header, shared_alloc); + node_copy_string(dn->value, dn->value_len, dn->header, xml_memory_page_value_allocated_mask, sn->value, sn->value_len, sn->header, shared_alloc); for (xml_attribute_struct* sa = sn->first_attribute; sa; sa = sa->next_attribute) { @@ -4454,8 +4454,8 @@ PUGI__NS_BEGIN if (da) { - node_copy_string(da->name, da->name_len, da->header, xml_memory_page_name_allocated_mask, sa->name, sa->header, shared_alloc); - node_copy_string(da->value, da->value_len, da->header, xml_memory_page_value_allocated_mask, sa->value, sa->header, shared_alloc); + node_copy_string(da->name, da->name_len, da->header, xml_memory_page_name_allocated_mask, sa->name, sa->name_len, sa->header, shared_alloc); + node_copy_string(da->value, da->value_len, da->header, xml_memory_page_value_allocated_mask, sa->value, sa->value_len, sa->header, shared_alloc); } } } @@ -4519,8 +4519,8 @@ PUGI__NS_BEGIN xml_allocator& alloc = get_allocator(da); xml_allocator* shared_alloc = (&alloc == &get_allocator(sa)) ? &alloc : 0; - node_copy_string(da->name, da->name_len, da->header, xml_memory_page_name_allocated_mask, sa->name, sa->header, shared_alloc); - node_copy_string(da->value, da->value_len, da->header, xml_memory_page_value_allocated_mask, sa->value, sa->header, shared_alloc); + node_copy_string(da->name, da->name_len, da->header, xml_memory_page_name_allocated_mask, sa->name, sa->name_len, sa->header, shared_alloc); + node_copy_string(da->value, da->value_len, da->header, xml_memory_page_value_allocated_mask, sa->value, sa->value_len, sa->header, shared_alloc); } inline bool is_text_node(xml_node_struct* node) From 32cccfe37722f5bb6f7a82ab01465a0f2442171b Mon Sep 17 00:00:00 2001 From: halx99 Date: Thu, 23 Dec 2021 18:44:32 +0800 Subject: [PATCH 24/43] Use string_view for all dom APIs --- src/pugixml.cpp | 199 +++++++++++++++--------------------- src/pugixml.hpp | 60 +++++------ tests/test.cpp | 10 -- tests/test.hpp | 5 +- tests/test_document.cpp | 6 +- tests/test_dom_text.cpp | 2 +- tests/test_dom_traverse.cpp | 4 +- tests/test_parse.cpp | 8 +- 8 files changed, 129 insertions(+), 165 deletions(-) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index 503389d1..68ceaa26 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -1099,6 +1099,22 @@ namespace pugi header = PUGI__GETHEADER_IMPL(this, page, 0); } + inline string_view_t name_sv() const { + return string_view_t(name, name_len); + } + + inline string_view_t value_sv() const { + return string_view_t(value, value_len); + } + + inline bool equals_name(string_view_t rhs) const { + return name && name_sv() == rhs; + } + + inline bool equals_value(string_view_t rhs) const { + return value_sv() == rhs; + } + uintptr_t header; char_t* name; @@ -1118,6 +1134,18 @@ namespace pugi header = PUGI__GETHEADER_IMPL(this, page, type); } + inline string_view_t name_sv() const { + return name ? string_view_t(name, name_len) : string_view_t(PUGIXML_TEXT(""), 0); + } + + inline string_view_t value_sv() const { + return value ? string_view_t(value, value_len) : string_view_t(PUGIXML_TEXT(""), 0); + } + + inline bool equals_name(string_view_t rhs) const { + return name && name_sv() == rhs; + } + uintptr_t header; char_t* name; @@ -4433,6 +4461,7 @@ PUGI__NS_BEGIN if (alloc && (source_header & header_mask) == 0) { dest = source; + dest_len = source_len; // since strcpy_insitu can reuse document buffer memory we need to mark both source and dest as shared header |= xml_memory_page_contents_shared_mask; @@ -5228,14 +5257,9 @@ namespace pugi return _attr && _attr->prev_attribute_c->next_attribute ? xml_attribute(_attr->prev_attribute_c) : xml_attribute(); } - PUGI__FN const char_t* xml_attribute::as_string(const char_t* def) const + PUGI__FN string_view_t xml_attribute::as_string(string_view_t def) const { - return (_attr && _attr->value) ? _attr->value + 0 : def; - } - - PUGI__FN string_view_t xml_attribute::as_string_sv(string_view_t def) const - { - return (_attr && _attr->value) ? string_view_t(_attr->value + 0, _attr->value_len) : def; + return (_attr && _attr->value) ? _attr->value_sv() : def; } PUGI__FN int xml_attribute::as_int(int def) const @@ -5280,24 +5304,14 @@ namespace pugi return !_attr; } - PUGI__FN const char_t* xml_attribute::name() const + PUGI__FN string_view_t xml_attribute::name() const { - return (_attr && _attr->name) ? _attr->name + 0 : PUGIXML_TEXT(""); + return (_attr && _attr->name) ? _attr->name_sv() : string_view_t(PUGIXML_TEXT(""), 0); } - PUGI__FN string_view_t xml_attribute::name_sv() const + PUGI__FN string_view_t xml_attribute::value() const { - return (_attr && _attr->name) ? string_view_t(_attr->name + 0, _attr->name_len) : string_view_t(PUGIXML_TEXT(""), 0); - } - - PUGI__FN const char_t* xml_attribute::value() const - { - return (_attr && _attr->value) ? _attr->value + 0 : PUGIXML_TEXT(""); - } - - PUGI__FN string_view_t xml_attribute::value_sv() const - { - return (_attr && _attr->value) ? string_view_t(_attr->value + 0, _attr->value_len) : string_view_t(PUGIXML_TEXT(""), 0); + return (_attr && _attr->value) ? _attr->value_sv() : string_view_t(PUGIXML_TEXT(""), 0); } PUGI__FN size_t xml_attribute::hash_value() const @@ -5524,7 +5538,7 @@ namespace pugi return xml_object_range(begin(), end()); } - PUGI__FN xml_object_range xml_node::children(const char_t* name_) const + PUGI__FN xml_object_range xml_node::children(string_view_t name_) const { return xml_object_range(xml_named_node_iterator(child(name_)._root, _root, name_), xml_named_node_iterator(0, _root, name_)); } @@ -5569,14 +5583,9 @@ namespace pugi return !_root; } - PUGI__FN const char_t* xml_node::name() const - { - return (_root && _root->name) ? _root->name + 0 : PUGIXML_TEXT(""); - } - - PUGI__FN string_view_t xml_node::name_sv() const + PUGI__FN string_view_t xml_node::name() const { - return (_root && _root->name) ? string_view_t(_root->name + 0, _root->name_len) : string_view_t(PUGIXML_TEXT(""), 0); + return (_root && _root->name) ? _root->name_sv() : string_view_t(PUGIXML_TEXT(""), 0); } PUGI__FN xml_node_type xml_node::type() const @@ -5584,43 +5593,38 @@ namespace pugi return _root ? PUGI__NODETYPE(_root) : node_null; } - PUGI__FN const char_t* xml_node::value() const + PUGI__FN string_view_t xml_node::value() const { - return (_root && _root->value) ? _root->value + 0 : PUGIXML_TEXT(""); + return (_root && _root->value) ? _root->value_sv() : string_view_t(PUGIXML_TEXT(""), 0); } - PUGI__FN string_view_t xml_node::value_sv() const - { - return (_root && _root->value) ? string_view_t(_root->value + 0, _root->value_len) : string_view_t(PUGIXML_TEXT(""), 0); - } - - PUGI__FN xml_node xml_node::child(const char_t* name_) const + PUGI__FN xml_node xml_node::child(const string_view_t name_) const { if (!_root) return xml_node(); for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) - if (i->name && impl::strequal(name_, i->name)) return xml_node(i); + if (i->equals_name(name_)) return xml_node(i); return xml_node(); } - PUGI__FN xml_attribute xml_node::attribute(const char_t* name_) const + PUGI__FN xml_attribute xml_node::attribute(string_view_t name_) const { if (!_root) return xml_attribute(); for (xml_attribute_struct* i = _root->first_attribute; i; i = i->next_attribute) - if (i->name && impl::strequal(name_, i->name)) + if (i->equals_name(name_)) return xml_attribute(i); return xml_attribute(); } - PUGI__FN xml_node xml_node::next_sibling(const char_t* name_) const + PUGI__FN xml_node xml_node::next_sibling(string_view_t name_) const { if (!_root) return xml_node(); for (xml_node_struct* i = _root->next_sibling; i; i = i->next_sibling) - if (i->name && impl::strequal(name_, i->name)) return xml_node(i); + if (i->equals_name(name_)) return xml_node(i); return xml_node(); } @@ -5630,17 +5634,17 @@ namespace pugi return _root ? xml_node(_root->next_sibling) : xml_node(); } - PUGI__FN xml_node xml_node::previous_sibling(const char_t* name_) const + PUGI__FN xml_node xml_node::previous_sibling(string_view_t name_) const { if (!_root) return xml_node(); for (xml_node_struct* i = _root->prev_sibling_c; i->next_sibling; i = i->prev_sibling_c) - if (i->name && impl::strequal(name_, i->name)) return xml_node(i); + if (i->equals_name(name_)) return xml_node(i); return xml_node(); } - PUGI__FN xml_attribute xml_node::attribute(const char_t* name_, xml_attribute& hint_) const + PUGI__FN xml_attribute xml_node::attribute(string_view_t name_, xml_attribute& hint_) const { xml_attribute_struct* hint = hint_._attr; @@ -5651,7 +5655,7 @@ namespace pugi // optimistically search from hint up until the end for (xml_attribute_struct* i = hint; i; i = i->next_attribute) - if (i->name && impl::strequal(name_, i->name)) + if (i->equals_name(name_)) { // update hint to maximize efficiency of searching for consecutive attributes hint_._attr = i->next_attribute; @@ -5662,7 +5666,7 @@ namespace pugi // wrap around and search from the first attribute until the hint // 'j' null pointer check is technically redundant, but it prevents a crash in case the assertion above fails for (xml_attribute_struct* j = _root->first_attribute; j && j != hint; j = j->next_attribute) - if (j->name && impl::strequal(name_, j->name)) + if (j->equals_name(name_)) { // update hint to maximize efficiency of searching for consecutive attributes hint_._attr = j->next_attribute; @@ -5696,46 +5700,26 @@ namespace pugi return xml_text(_root); } - PUGI__FN const char_t* xml_node::child_value() const - { - if (!_root) return PUGIXML_TEXT(""); - - // element nodes can have value if parse_embed_pcdata was used - if (PUGI__NODETYPE(_root) == node_element && _root->value) - return _root->value; - - for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) - if (impl::is_text_node(i) && i->value) - return i->value; - - return PUGIXML_TEXT(""); - } - - PUGI__FN string_view_t xml_node::child_value_sv() const + PUGI__FN string_view_t xml_node::child_value() const { if (!_root) return string_view_t(PUGIXML_TEXT(""), 0); // element nodes can have value if parse_embed_pcdata was used if (PUGI__NODETYPE(_root) == node_element && _root->value) - return string_view_t(_root->value, _root->value_len); + return _root->value_sv(); for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) if (impl::is_text_node(i) && i->value) - return string_view_t(i->value, i->value_len); + return i->value_sv(); return string_view_t(PUGIXML_TEXT(""), 0); } - PUGI__FN const char_t* xml_node::child_value(const char_t* name_) const + PUGI__FN string_view_t xml_node::child_value(string_view_t name_) const { return child(name_).child_value(); } - PUGI__FN string_view_t xml_node::child_value_sv(const char_t* name_) const - { - return child(name_).child_value_sv(); - } - PUGI__FN xml_attribute xml_node::first_attribute() const { return _root ? xml_attribute(_root->first_attribute) : xml_attribute(); @@ -6160,7 +6144,7 @@ namespace pugi return moved; } - PUGI__FN bool xml_node::remove_attribute(const char_t* name_) + PUGI__FN bool xml_node::remove_attribute(string_view_t name_) { return remove_attribute(attribute(name_)); } @@ -6200,7 +6184,7 @@ namespace pugi return true; } - PUGI__FN bool xml_node::remove_child(const char_t* name_) + PUGI__FN bool xml_node::remove_child(string_view_t name_) { return remove_child(child(name_)); } @@ -6274,28 +6258,28 @@ namespace pugi return impl::load_buffer_impl(doc, _root, const_cast(contents), size, options, encoding, false, false, &extra->buffer); } - PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t* name_, const char_t* attr_name, const char_t* attr_value) const + PUGI__FN xml_node xml_node::find_child_by_attribute(string_view_t name_, string_view_t attr_name, string_view_t attr_value) const { if (!_root) return xml_node(); for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) - if (i->name && impl::strequal(name_, i->name)) + if (i->name && i->equals_name(name_)) { for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute) - if (a->name && impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value ? a->value + 0 : PUGIXML_TEXT(""))) + if (a->equals_name(attr_name) && a->equals_value(attr_value)) return xml_node(i); } return xml_node(); } - PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const + PUGI__FN xml_node xml_node::find_child_by_attribute(const string_view_t attr_name, const string_view_t attr_value) const { if (!_root) return xml_node(); for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute) - if (a->name && impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value ? a->value + 0 : PUGIXML_TEXT(""))) + if (a->equals_name(attr_name) && a->equals_value(attr_value)) return xml_node(i); return xml_node(); @@ -6554,32 +6538,18 @@ namespace pugi return _data() == 0; } - PUGI__FN const char_t* xml_text::get() const - { - xml_node_struct* d = _data(); - - return (d && d->value) ? d->value + 0 : PUGIXML_TEXT(""); - } - - PUGI__FN string_view_t xml_text::get_sv() const - { - xml_node_struct* d = _data(); - - return (d && d->value) ? string_view_t(d->value + 0, d->value_len) : string_view_t(PUGIXML_TEXT(""), 0); - } - - PUGI__FN const char_t* xml_text::as_string(const char_t* def) const + PUGI__FN string_view_t xml_text::get() const { xml_node_struct* d = _data(); - return (d && d->value) ? d->value + 0 : def; + return (d && d->value) ? d->value_sv() : string_view_t(PUGIXML_TEXT(""), 0); } - PUGI__FN string_view_t xml_text::as_string_sv(string_view_t def) const + PUGI__FN string_view_t xml_text::as_string(string_view_t def) const { xml_node_struct* d = _data(); - return (d && d->value) ? string_view_t(d->value + 0, d->value_len) : def; + return (d && d->value) ? d->value_sv() : def; } PUGI__FN int xml_text::as_int(int def) const @@ -6920,15 +6890,15 @@ namespace pugi return temp; } - PUGI__FN xml_named_node_iterator::xml_named_node_iterator(): _name(0) + PUGI__FN xml_named_node_iterator::xml_named_node_iterator(): _name(0), _name_len(0) { } - PUGI__FN xml_named_node_iterator::xml_named_node_iterator(const xml_node& node, const char_t* name): _wrap(node), _parent(node.parent()), _name(name) + PUGI__FN xml_named_node_iterator::xml_named_node_iterator(const xml_node& node, string_view_t name): _wrap(node), _parent(node.parent()), _name(name.data()), _name_len(static_cast(name.length())) { } - PUGI__FN xml_named_node_iterator::xml_named_node_iterator(xml_node_struct* ref, xml_node_struct* parent, const char_t* name): _wrap(ref), _parent(parent), _name(name) + PUGI__FN xml_named_node_iterator::xml_named_node_iterator(xml_node_struct* ref, xml_node_struct* parent, string_view_t name): _wrap(ref), _parent(parent), _name(name.data()), _name_len(static_cast(name.length())) { } @@ -6957,7 +6927,7 @@ namespace pugi PUGI__FN xml_named_node_iterator& xml_named_node_iterator::operator++() { assert(_wrap._root); - _wrap = _wrap.next_sibling(_name); + _wrap = _wrap.next_sibling(string_view_t(_name, _name_len)); return *this; } @@ -6970,14 +6940,15 @@ namespace pugi PUGI__FN xml_named_node_iterator& xml_named_node_iterator::operator--() { + string_view_t name = string_view_t(_name, _name_len); if (_wrap._root) - _wrap = _wrap.previous_sibling(_name); + _wrap = _wrap.previous_sibling(name); else { _wrap = _parent.last_child(); - if (!impl::strequal(_wrap.name(), _name)) - _wrap = _wrap.previous_sibling(_name); + if (_wrap.name() != name) + _wrap = _wrap.previous_sibling(name); } return *this; @@ -7929,9 +7900,9 @@ PUGI__NS_BEGIN } public: - static xpath_string from_const(const char_t* str) + static xpath_string from_const(string_view_t str) { - return xpath_string(str, false, 0); + return xpath_string(str.data(), false, 0); } static xpath_string from_heap_preallocated(const char_t* begin, const char_t* end) @@ -8102,7 +8073,7 @@ PUGI__NS_BEGIN xpath_string result; // element nodes can have value if parse_embed_pcdata was used - if (n.value()[0]) + if (!n.value().empty()) result.append(xpath_string::from_const(n.value()), alloc); xml_node cur = n.first_child(); @@ -8558,7 +8529,7 @@ PUGI__NS_BEGIN PUGI__FN const char_t* qualified_name(const xpath_node& node) { - return node.attribute() ? node.attribute().name() : node.node().name(); + return node.attribute() ? node.attribute().name().data() : node.node().name().data(); } PUGI__FN const char_t* local_name(const xpath_node& node) @@ -8584,7 +8555,7 @@ PUGI__NS_BEGIN bool operator()(xml_attribute a) const { - const char_t* name = a.name(); + const char_t* name = a.name().data(); if (!starts_with(name, PUGIXML_TEXT("xmlns"))) return false; @@ -8594,7 +8565,7 @@ PUGI__NS_BEGIN PUGI__FN const char_t* namespace_uri(xml_node node) { - namespace_uri_predicate pred = node.name(); + namespace_uri_predicate pred = node.name().data(); xml_node p = node; @@ -8602,7 +8573,7 @@ PUGI__NS_BEGIN { xml_attribute a = p.find_attribute(pred); - if (a) return a.value(); + if (a) return a.value().data(); p = p.parent(); } @@ -8612,7 +8583,7 @@ PUGI__NS_BEGIN PUGI__FN const char_t* namespace_uri(xml_attribute attr, xml_node parent) { - namespace_uri_predicate pred = attr.name(); + namespace_uri_predicate pred = attr.name().data(); // Default namespace does not apply to attributes if (!pred.prefix) return PUGIXML_TEXT(""); @@ -8623,7 +8594,7 @@ PUGI__NS_BEGIN { xml_attribute a = p.find_attribute(pred); - if (a) return a.value(); + if (a) return a.value().data(); p = p.parent(); } @@ -10506,7 +10477,7 @@ PUGI__NS_BEGIN if (a) { - const char_t* value = a.value(); + const char_t* value = a.value().data(); // strnicmp / strncasecmp is not portable for (const char_t* lit = lang.c_str(); *lit; ++lit) @@ -10528,7 +10499,7 @@ PUGI__NS_BEGIN xml_attribute attr = c.n.node().attribute(_left->_data.nodetest); - return attr && strequal(attr.value(), value) && is_xpath_attribute(attr.name()); + return attr && strequal(attr.value().data(), value) && is_xpath_attribute(attr.name().data()); } case ast_variable: diff --git a/src/pugixml.hpp b/src/pugixml.hpp index a43c0a71..66d50428 100644 --- a/src/pugixml.hpp +++ b/src/pugixml.hpp @@ -202,6 +202,14 @@ namespace pugi { return size(); } + bool empty() const { + return 0 == s; + } + + const Char& operator[](size_t index) const { + return p[index]; + } + operator std::basic_string() const { return std::basic_string(data(), size()); } @@ -519,15 +527,12 @@ namespace pugi bool empty() const; // Get attribute name/value, or "" if attribute is empty - const char_t* name() const; - string_view_t name_sv() const; + string_view_t name() const; - const char_t* value() const; - string_view_t value_sv() const; + string_view_t value() const; // Get attribute value, or the default value if attribute is empty - const char_t* as_string(const char_t* def = PUGIXML_TEXT("")) const; - string_view_t as_string_sv(string_view_t def = string_view_t(PUGIXML_TEXT(""), 0)) const; + string_view_t as_string(string_view_t def = string_view_t(PUGIXML_TEXT(""), 0)) const; // Get attribute value as a number, or the default value if conversion did not succeed or attribute is empty int as_int(int def = 0) const; @@ -635,13 +640,11 @@ namespace pugi xml_node_type type() const; // Get node name, or "" if node is empty or it has no name - const char_t* name() const; - string_view_t name_sv() const; + string_view_t name() const; // Get node value, or "" if node is empty or it has no value // Note: For text node.value() does not return "text"! Use child_value() or text() methods to access text inside nodes. - const char_t* value() const; - string_view_t value_sv() const; + string_view_t value() const; // Get attribute list xml_attribute first_attribute() const; @@ -665,21 +668,19 @@ namespace pugi xml_text text() const; // Get child, attribute or next/previous sibling with the specified name - xml_node child(const char_t* name) const; - xml_attribute attribute(const char_t* name) const; - xml_node next_sibling(const char_t* name) const; - xml_node previous_sibling(const char_t* name) const; + xml_node child(string_view_t name) const; + xml_attribute attribute(string_view_t name) const; + xml_node next_sibling(string_view_t name) const; + xml_node previous_sibling(string_view_t name) const; // Get attribute, starting the search from a hint (and updating hint so that searching for a sequence of attributes is fast) - xml_attribute attribute(const char_t* name, xml_attribute& hint) const; + xml_attribute attribute(string_view_t name, xml_attribute& hint) const; // Get child value of current node; that is, value of the first child node of type PCDATA/CDATA - const char_t* child_value() const; - string_view_t child_value_sv() const; + string_view_t child_value() const; // Get child value of child with specified name. Equivalent to child(name).child_value(). - const char_t* child_value(const char_t* name) const; - string_view_t child_value_sv(const char_t* name) const; + string_view_t child_value(string_view_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) bool set_name(string_view_t rhs, bool shallow_copy = false); @@ -723,14 +724,14 @@ namespace pugi // Remove specified attribute bool remove_attribute(const xml_attribute& a); - bool remove_attribute(const char_t* name); + bool remove_attribute(string_view_t name); // Remove all attributes bool remove_attributes(); // Remove specified child bool remove_child(const xml_node& n); - bool remove_child(const char_t* name); + bool remove_child(string_view_t name); // Remove all children bool remove_children(); @@ -789,8 +790,8 @@ namespace pugi } // Find child node by attribute name/value - xml_node find_child_by_attribute(const char_t* name, const char_t* attr_name, const char_t* attr_value) const; - xml_node find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const; + xml_node find_child_by_attribute(string_view_t name, string_view_t attr_name, string_view_t attr_value) const; + xml_node find_child_by_attribute(string_view_t attr_name, string_view_t attr_value) const; #ifndef PUGIXML_NO_STL // Get the absolute node path from root as a text string. @@ -841,7 +842,7 @@ namespace pugi // Range-based for support xml_object_range children() const; - xml_object_range children(const char_t* name) const; + xml_object_range children(string_view_t name) const; xml_object_range attributes() const; // Get node offset in parsed file/string (in char_t units) for debugging purposes @@ -888,12 +889,10 @@ namespace pugi bool empty() const; // Get text, or "" if object is empty - const char_t* get() const; - string_view_t get_sv() const; + string_view_t get() const; // Get text, or the default value if object is empty - const char_t* as_string(const char_t* def = PUGIXML_TEXT("")) const; - string_view_t as_string_sv(string_view_t def = string_view_t(PUGIXML_TEXT(""), 0)) const; + string_view_t as_string(string_view_t def = string_view_t(PUGIXML_TEXT(""), 0)) const; // Get text as a number, or the default value if conversion did not succeed or object is empty int as_int(int def = 0) const; @@ -1057,7 +1056,7 @@ namespace pugi xml_named_node_iterator(); // Construct an iterator which points to the specified node - xml_named_node_iterator(const xml_node& node, const char_t* name); + xml_named_node_iterator(const xml_node& node, string_view_t name); // Iterator operators bool operator==(const xml_named_node_iterator& rhs) const; @@ -1076,8 +1075,9 @@ namespace pugi mutable xml_node _wrap; xml_node _parent; const char_t* _name; + int _name_len; - xml_named_node_iterator(xml_node_struct* ref, xml_node_struct* parent, const char_t* name); + xml_named_node_iterator(xml_node_struct* ref, xml_node_struct* parent, string_view_t name); }; // Abstract tree walker class (see xml_node::traverse) diff --git a/tests/test.cpp b/tests/test.cpp index a97116ea..21835243 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -42,16 +42,6 @@ static void build_document_order(std::vector& result, pugi::xm } #endif -bool test_string_equal(const pugi::char_t* lhs, const pugi::char_t* rhs) -{ - return (!lhs || !rhs) ? lhs == rhs : - #ifdef PUGIXML_WCHAR_MODE - wcscmp(lhs, rhs) == 0; - #else - strcmp(lhs, rhs) == 0; - #endif -} - bool test_node(const pugi::xml_node& node, const pugi::char_t* contents, const pugi::char_t* indent, unsigned int flags) { xml_writer_string writer; diff --git a/tests/test.hpp b/tests/test.hpp index dd14af68..85cac842 100644 --- a/tests/test.hpp +++ b/tests/test.hpp @@ -34,7 +34,10 @@ struct test_runner static const char* _temp_path; }; -bool test_string_equal(const pugi::char_t* lhs, const pugi::char_t* rhs); +inline bool test_string_equal(pugi::string_view_t lhs, const pugi::char_t* rhs) +{ + return lhs == rhs; +} template inline bool test_node_name_value(const Node& node, const pugi::char_t* name, const pugi::char_t* value) { diff --git a/tests/test_document.cpp b/tests/test_document.cpp index 53790924..493882d2 100644 --- a/tests/test_document.cpp +++ b/tests/test_document.cpp @@ -905,7 +905,7 @@ inline void check_utftest_document(const xml_document& doc) CHECK(static_cast(doc.last_child().last_child().name()[0]) >= 0x80); // check magic string - const char_t* v = doc.last_child().child(STR("Heavy")).previous_sibling().child_value(); + string_view_t v = doc.last_child().child(STR("Heavy")).previous_sibling().child_value(); #ifdef PUGIXML_WCHAR_MODE CHECK(v[0] == 0x4e16 && v[1] == 0x754c && v[2] == 0x6709 && v[3] == 0x5f88 && v[4] == 0x591a && v[5] == wchar_cast(0x8bed) && v[6] == wchar_cast(0x8a00)); @@ -1515,7 +1515,7 @@ TEST(document_load_buffer_utf_truncated) { CHECK(res); - const char_t* name = doc.first_child().name(); + string_view_t name = doc.first_child().name(); #ifdef PUGIXML_WCHAR_MODE CHECK(name[0] == 0x20ac && name[1] == 0); @@ -1560,7 +1560,7 @@ TEST(document_load_stream_truncated) } else { - const char_t* name = doc.first_child().name(); + string_view_t name = doc.first_child().name(); #ifdef PUGIXML_WCHAR_MODE CHECK(name[0] == 0x20ac && name[1] == 0); diff --git a/tests/test_dom_text.cpp b/tests/test_dom_text.cpp index aa131e6f..23b6ebe7 100644 --- a/tests/test_dom_text.cpp +++ b/tests/test_dom_text.cpp @@ -215,7 +215,7 @@ TEST_XML(dom_text_get_no_state, "") xml_text t = node.text(); CHECK(!t); - CHECK(t.get() && *t.get() == 0); + CHECK(t.get().data() && *t.get().data() == 0); CHECK(!node.first_child()); node.append_child(node_pcdata); diff --git a/tests/test_dom_traverse.cpp b/tests/test_dom_traverse.cpp index 4a2403d4..459181b5 100644 --- a/tests/test_dom_traverse.cpp +++ b/tests/test_dom_traverse.cpp @@ -681,9 +681,9 @@ struct find_predicate_prefix { #ifdef PUGIXML_WCHAR_MODE // can't use wcsncmp here because of a bug in DMC - return std::basic_string(obj.name()).compare(0, wcslen(prefix), prefix) == 0; + return std::basic_string(obj.name().data()).compare(0, wcslen(prefix), prefix) == 0; #else - return strncmp(obj.name(), prefix, strlen(prefix)) == 0; + return strncmp(obj.name().data(), prefix, strlen(prefix)) == 0; #endif } }; diff --git a/tests/test_parse.cpp b/tests/test_parse.cpp index 180c70ad..aa70d490 100644 --- a/tests/test_parse.cpp +++ b/tests/test_parse.cpp @@ -474,7 +474,7 @@ TEST(parse_pcdata_trim) xml_document doc; CHECK(doc.load_string(td.source, td.flags | parse_trim_pcdata)); - const char_t* value = doc.child(STR("node")) ? doc.child_value(STR("node")) : doc.text().get(); + string_view_t value = doc.child(STR("node")) ? doc.child_value(STR("node")) : doc.text().get(); CHECK_STRING(value, td.result); } } @@ -1100,7 +1100,7 @@ TEST(parse_bom_fragment_invalid_utf8) CHECK(doc.load_buffer("\xef\xbb\xbb", 3, parse_fragment, encoding_utf8)); - const char_t* value = doc.text().get(); + string_view_t value = doc.text().get(); #ifdef PUGIXML_WCHAR_MODE CHECK(value[0] == wchar_cast(0xfefb) && value[1] == 0); @@ -1115,7 +1115,7 @@ TEST(parse_bom_fragment_invalid_utf16) CHECK(doc.load_buffer("\xff\xfe", 2, parse_fragment, encoding_utf16_be)); - const char_t* value = doc.text().get(); + string_view_t value = doc.text().get(); #ifdef PUGIXML_WCHAR_MODE CHECK(value[0] == wchar_cast(0xfffe) && value[1] == 0); @@ -1130,7 +1130,7 @@ TEST(parse_bom_fragment_invalid_utf32) CHECK(doc.load_buffer("\xff\xff\x00\x00", 4, parse_fragment, encoding_utf32_le)); - const char_t* value = doc.text().get(); + string_view_t value = doc.text().get(); #ifdef PUGIXML_WCHAR_MODE CHECK(value[0] == wchar_cast(0xffff) && value[1] == 0); From 0d87d4f717a77fd536d222a4827e2dbd2a120e74 Mon Sep 17 00:00:00 2001 From: halx99 Date: Thu, 23 Dec 2021 18:52:33 +0800 Subject: [PATCH 25/43] Fix ci & add run test cost --- tests/main.cpp | 7 +++++-- tests/test_parse.cpp | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/main.cpp b/tests/main.cpp index 352b58bb..efdf7b08 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -8,6 +8,8 @@ #include +#include + #ifndef PUGIXML_NO_EXCEPTIONS # include #endif @@ -170,6 +172,7 @@ int main(int, char** argv) #ifdef __BORLANDC__ _control87(MCW_EM | PC_53, MCW_EM | MCW_PC); #endif + clock_t start = clock(); // setup temp path as the executable folder std::string temp = argv[0]; @@ -203,9 +206,9 @@ int main(int, char** argv) unsigned int failed = total - passed; if (failed != 0) - printf("FAILURE: %u out of %u tests failed.\n", failed, total); + printf("FAILURE: %u out of %u tests failed, cost %g(s).\n", failed, total, (clock() - start) / (double)CLOCKS_PER_SEC); else - printf("Success: %u tests passed.\n", total); + printf("Success: %u tests passed, cost %g(s).\n", total, (clock() - start) / (double)CLOCKS_PER_SEC); return failed; } diff --git a/tests/test_parse.cpp b/tests/test_parse.cpp index aa70d490..680dae92 100644 --- a/tests/test_parse.cpp +++ b/tests/test_parse.cpp @@ -563,7 +563,7 @@ TEST(parse_escapes_unicode) CHECK(doc.load_string(STR("γγ𤭢"), parse_minimal | parse_escapes)); #ifdef PUGIXML_WCHAR_MODE - const char_t* v = doc.child_value(STR("node")); + string_view_t v = doc.child_value(STR("node")); size_t wcharsize = sizeof(wchar_t); From 46805e8c08e9544957359a4a7ac3cb8f17dadf17 Mon Sep 17 00:00:00 2001 From: halx99 Date: Thu, 23 Dec 2021 18:54:30 +0800 Subject: [PATCH 26/43] Fix warnings --- tests/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/main.cpp b/tests/main.cpp index efdf7b08..432e3349 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -206,9 +206,9 @@ int main(int, char** argv) unsigned int failed = total - passed; if (failed != 0) - printf("FAILURE: %u out of %u tests failed, cost %g(s).\n", failed, total, (clock() - start) / (double)CLOCKS_PER_SEC); + printf("FAILURE: %u out of %u tests failed, cost %g(s).\n", failed, total, (clock() - start) / static_cast(CLOCKS_PER_SEC)); else - printf("Success: %u tests passed, cost %g(s).\n", total, (clock() - start) / (double)CLOCKS_PER_SEC); + printf("Success: %u tests passed, cost %g(s).\n", total, (clock() - start) / static_cast(CLOCKS_PER_SEC)); return failed; } From f0259eb00aad0a48686db3caddb8e59647b7011a Mon Sep 17 00:00:00 2001 From: halx99 Date: Thu, 23 Dec 2021 19:14:53 +0800 Subject: [PATCH 27/43] Fix ci --- src/pugixml.cpp | 40 ++++++++++++++++++++++++---------------- src/pugixml.hpp | 6 ++++-- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index 68ceaa26..8e8a0397 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -1099,16 +1099,20 @@ namespace pugi header = PUGI__GETHEADER_IMPL(this, page, 0); } - inline string_view_t name_sv() const { + inline string_view_t unsafe_name_sv() const { return string_view_t(name, name_len); } - inline string_view_t value_sv() const { + inline string_view_t unsafe_value_sv() const { return string_view_t(value, value_len); } + inline string_view_t value_sv() const { + return value ? unsafe_value_sv() : PUGIXML_EMPTY_SV; + } + inline bool equals_name(string_view_t rhs) const { - return name && name_sv() == rhs; + return name && unsafe_name_sv() == rhs; } inline bool equals_value(string_view_t rhs) const { @@ -1134,16 +1138,20 @@ namespace pugi header = PUGI__GETHEADER_IMPL(this, page, type); } - inline string_view_t name_sv() const { - return name ? string_view_t(name, name_len) : string_view_t(PUGIXML_TEXT(""), 0); + inline string_view_t unsafe_name_sv() const { + return string_view_t(name, name_len); + } + + inline string_view_t unsafe_value_sv() const { + return string_view_t(value, value_len); } inline string_view_t value_sv() const { - return value ? string_view_t(value, value_len) : string_view_t(PUGIXML_TEXT(""), 0); + return value ? unsafe_value_sv() : PUGIXML_EMPTY_SV; } inline bool equals_name(string_view_t rhs) const { - return name && name_sv() == rhs; + return name && unsafe_name_sv() == rhs; } uintptr_t header; @@ -5259,7 +5267,7 @@ namespace pugi PUGI__FN string_view_t xml_attribute::as_string(string_view_t def) const { - return (_attr && _attr->value) ? _attr->value_sv() : def; + return (_attr && _attr->value) ? _attr->unsafe_value_sv() : def; } PUGI__FN int xml_attribute::as_int(int def) const @@ -5306,12 +5314,12 @@ namespace pugi PUGI__FN string_view_t xml_attribute::name() const { - return (_attr && _attr->name) ? _attr->name_sv() : string_view_t(PUGIXML_TEXT(""), 0); + return (_attr && _attr->name) ? _attr->unsafe_name_sv() : PUGIXML_EMPTY_SV; } PUGI__FN string_view_t xml_attribute::value() const { - return (_attr && _attr->value) ? _attr->value_sv() : string_view_t(PUGIXML_TEXT(""), 0); + return (_attr && _attr->value) ? _attr->unsafe_value_sv() : PUGIXML_EMPTY_SV; } PUGI__FN size_t xml_attribute::hash_value() const @@ -5585,7 +5593,7 @@ namespace pugi PUGI__FN string_view_t xml_node::name() const { - return (_root && _root->name) ? _root->name_sv() : string_view_t(PUGIXML_TEXT(""), 0); + return (_root && _root->name) ? _root->unsafe_name_sv() : PUGIXML_EMPTY_SV; } PUGI__FN xml_node_type xml_node::type() const @@ -5595,7 +5603,7 @@ namespace pugi PUGI__FN string_view_t xml_node::value() const { - return (_root && _root->value) ? _root->value_sv() : string_view_t(PUGIXML_TEXT(""), 0); + return (_root && _root->value) ? _root->unsafe_value_sv() : PUGIXML_EMPTY_SV; } PUGI__FN xml_node xml_node::child(const string_view_t name_) const @@ -5702,7 +5710,7 @@ namespace pugi PUGI__FN string_view_t xml_node::child_value() const { - if (!_root) return string_view_t(PUGIXML_TEXT(""), 0); + if (!_root) return PUGIXML_EMPTY_SV; // element nodes can have value if parse_embed_pcdata was used if (PUGI__NODETYPE(_root) == node_element && _root->value) @@ -5712,7 +5720,7 @@ namespace pugi if (impl::is_text_node(i) && i->value) return i->value_sv(); - return string_view_t(PUGIXML_TEXT(""), 0); + return PUGIXML_EMPTY_SV; } PUGI__FN string_view_t xml_node::child_value(string_view_t name_) const @@ -6542,14 +6550,14 @@ namespace pugi { xml_node_struct* d = _data(); - return (d && d->value) ? d->value_sv() : string_view_t(PUGIXML_TEXT(""), 0); + return (d && d->value) ? d->unsafe_value_sv() : PUGIXML_EMPTY_SV; } PUGI__FN string_view_t xml_text::as_string(string_view_t def) const { xml_node_struct* d = _data(); - return (d && d->value) ? d->value_sv() : def; + return (d && d->value) ? d->unsafe_value_sv() : def; } PUGI__FN int xml_text::as_int(int def) const diff --git a/src/pugixml.hpp b/src/pugixml.hpp index 66d50428..27b5688e 100644 --- a/src/pugixml.hpp +++ b/src/pugixml.hpp @@ -273,6 +273,8 @@ namespace pugi typedef pugi::basic_string_view > string_view_t; } +#define PUGIXML_EMPTY_SV pugi::string_view_t(PUGIXML_TEXT(""), 0) + // The PugiXML namespace namespace pugi { @@ -532,7 +534,7 @@ namespace pugi string_view_t value() const; // Get attribute value, or the default value if attribute is empty - string_view_t as_string(string_view_t def = string_view_t(PUGIXML_TEXT(""), 0)) const; + string_view_t as_string(string_view_t def = PUGIXML_EMPTY_SV) const; // Get attribute value as a number, or the default value if conversion did not succeed or attribute is empty int as_int(int def = 0) const; @@ -892,7 +894,7 @@ namespace pugi string_view_t get() const; // Get text, or the default value if object is empty - string_view_t as_string(string_view_t def = string_view_t(PUGIXML_TEXT(""), 0)) const; + string_view_t as_string(string_view_t def = PUGIXML_EMPTY_SV) const; // Get text as a number, or the default value if conversion did not succeed or object is empty int as_int(int def = 0) const; From d3a8b86f17fd71a3e781c74c270df8af834cf40d Mon Sep 17 00:00:00 2001 From: halx99 Date: Thu, 23 Dec 2021 21:14:51 +0800 Subject: [PATCH 28/43] Add missing commit from shallow_copy branch --- src/pugixml.cpp | 12 ++++++++++-- src/pugixml.hpp | 4 ++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index 8e8a0397..55e84049 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -432,12 +432,14 @@ PUGI__NS_BEGIN #endif // extra metadata bits + static const uintptr_t xml_memory_page_contents_const_mask = 128; 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_value_allocated_mask = 16; static const uintptr_t xml_memory_page_type_mask = 15; // combined masks for string uniqueness + static const uintptr_t xml_memory_page_contents_const_or_shared_mask = xml_memory_page_contents_const_mask | xml_memory_page_contents_shared_mask; static const uintptr_t xml_memory_page_name_allocated_or_shared_mask = xml_memory_page_name_allocated_mask | xml_memory_page_contents_shared_mask; static const uintptr_t xml_memory_page_value_allocated_or_shared_mask = xml_memory_page_value_allocated_mask | xml_memory_page_contents_shared_mask; @@ -2381,7 +2383,7 @@ PUGI__NS_BEGIN inline bool strcpy_insitu_allow(size_t length, const Header& header, uintptr_t header_mask, char_t* target) { // never reuse shared memory - if (header & xml_memory_page_contents_shared_mask) return false; + if (header & xml_memory_page_contents_const_or_shared_mask) return false; size_t target_length = strlength(target); @@ -2410,6 +2412,9 @@ PUGI__NS_BEGIN dest = source_length == 0 ? NULL : const_cast(source); header &= ~header_mask; + // mark dest as shared to avoid reuse document buffer memory + header |= xml_memory_page_contents_const_mask; + return true; } else if (dest && strcpy_insitu_allow(source_length, header, header_mask, dest)) @@ -2441,6 +2446,9 @@ PUGI__NS_BEGIN dest = buf; header |= header_mask; + // remove dest shared mask for continue reuse document buffer memory + header &= ~xml_memory_page_contents_const_mask; + return true; } } @@ -4768,7 +4776,7 @@ PUGI__NS_BEGIN template PUGI__FN bool set_value_bool(String& dest, int& dest_len, Header& header, uintptr_t header_mask, bool value) { - return strcpy_insitu(dest, dest_len, header, header_mask, value ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"), value ? 4 : 5); + return strcpy_insitu(dest, dest_len, header, header_mask, value ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"), value ? 4 : 5, true); } PUGI__FN xml_parse_result load_buffer_impl(xml_document_struct* doc, xml_node_struct* root, void* contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own, char_t** out_buffer) diff --git a/src/pugixml.hpp b/src/pugixml.hpp index 27b5688e..080f61f3 100644 --- a/src/pugixml.hpp +++ b/src/pugixml.hpp @@ -255,8 +255,8 @@ namespace pugi { bool value; operator bool() const { return value; } }; - static const boolean true_value(true); - static const boolean false_value(false); + static const boolean (true_value)(true); + static const boolean (false_value)(false); } // namespace pugi namespace pugi From 3ceb7039356f09d78e3d0007a59a6ded9fca18fa Mon Sep 17 00:00:00 2001 From: deal Date: Fri, 24 Dec 2021 01:54:39 +0800 Subject: [PATCH 29/43] Update pugixml.cpp --- src/pugixml.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index 55e84049..8b4f6a89 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -2409,7 +2409,7 @@ PUGI__NS_BEGIN if (header & header_mask) alloc->deallocate_string(dest); // mark the string as not allocated - dest = source_length == 0 ? NULL : const_cast(source); + dest = source_length == 0 ? NULL : const_cast(source); header &= ~header_mask; // mark dest as shared to avoid reuse document buffer memory From c95044df0580cf4c137f326bd042911b94813568 Mon Sep 17 00:00:00 2001 From: halx99 Date: Fri, 24 Dec 2021 14:01:46 +0800 Subject: [PATCH 30/43] Fix for compact mode --- src/pugixml.cpp | 46 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index 8b4f6a89..2a99f5b4 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -1053,7 +1053,27 @@ namespace pugi { xml_attribute_struct(impl::xml_memory_page* page): header(page, 0), namevalue_base(0) { - PUGI__STATIC_ASSERT(sizeof(xml_attribute_struct) == 8); + PUGI__STATIC_ASSERT(sizeof(xml_attribute_struct) == 8 + 8); + } + + inline string_view_t unsafe_name_sv() const { + return string_view_t(name, name_len); + } + + inline string_view_t unsafe_value_sv() const { + return string_view_t(value, value_len); + } + + inline string_view_t value_sv() const { + return value ? unsafe_value_sv() : PUGIXML_EMPTY_SV; + } + + inline bool equals_name(string_view_t rhs) const { + return name && unsafe_name_sv() == rhs; + } + + inline bool equals_value(string_view_t rhs) const { + return value_sv() == rhs; } impl::compact_header header; @@ -1065,13 +1085,32 @@ namespace pugi impl::compact_pointer prev_attribute_c; impl::compact_pointer next_attribute; + + int name_len; + int value_len; }; struct xml_node_struct { xml_node_struct(impl::xml_memory_page* page, xml_node_type type): header(page, type), namevalue_base(0) { - PUGI__STATIC_ASSERT(sizeof(xml_node_struct) == 12); + PUGI__STATIC_ASSERT(sizeof(xml_node_struct) == 12 + 8); + } + + inline string_view_t unsafe_name_sv() const { + return string_view_t(name, name_len); + } + + inline string_view_t unsafe_value_sv() const { + return string_view_t(value, value_len); + } + + inline string_view_t value_sv() const { + return value ? unsafe_value_sv() : PUGIXML_EMPTY_SV; + } + + inline bool equals_name(string_view_t rhs) const { + return name && unsafe_name_sv() == rhs; } impl::compact_header header; @@ -1089,6 +1128,9 @@ namespace pugi impl::compact_pointer next_sibling; impl::compact_pointer first_attribute; + + int name_len; + int value_len; }; } #else From 3c9111dc8cbb7ced528f9b4d153b2b8f932e21b0 Mon Sep 17 00:00:00 2001 From: deal Date: Fri, 24 Dec 2021 14:21:02 +0800 Subject: [PATCH 31/43] Allow build compact mode --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 52caea47..bf6948b8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,7 +12,7 @@ jobs: matrix: os: [ubuntu, macos] compiler: [g++, clang++] - defines: [standard, PUGIXML_WCHAR_MODE, PUGIXML_NO_EXCEPTIONS] + defines: [standard, PUGIXML_WCHAR_MODE, PUGIXML_COMPACT, PUGIXML_NO_EXCEPTIONS] exclude: - os: macos compiler: g++ @@ -38,7 +38,7 @@ jobs: strategy: matrix: arch: [Win32, x64] - defines: [standard, PUGIXML_WCHAR_MODE, PUGIXML_NO_EXCEPTIONS] + defines: [standard, PUGIXML_WCHAR_MODE, PUGIXML_COMPACT, PUGIXML_NO_EXCEPTIONS] steps: - uses: actions/checkout@v1 - name: cmake configure From d6fac0ac39549710535f4bb661b4827c3a2b3069 Mon Sep 17 00:00:00 2001 From: halx99 Date: Tue, 8 Feb 2022 21:41:28 +0800 Subject: [PATCH 32/43] More string_view --- src/pugixml.cpp | 22 +++++----------------- src/pugixml.hpp | 6 ++---- 2 files changed, 7 insertions(+), 21 deletions(-) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index 2a99f5b4..708df686 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -7440,28 +7440,16 @@ namespace pugi } #ifndef PUGIXML_NO_STL - PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const wchar_t* str) + PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const pugi::wstring_view& str) { - assert(str); - - return impl::as_utf8_impl(str, impl::strlength_wide(str)); + return impl::as_utf8_impl(str.data(), str.length()); } - PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const std::basic_string& str) + PUGI__FN std::wstring PUGIXML_FUNCTION as_wide(const pugi::string_view& str) { - return impl::as_utf8_impl(str.c_str(), str.size()); - } + assert(str.data()); - PUGI__FN std::basic_string PUGIXML_FUNCTION as_wide(const char* str) - { - assert(str); - - return impl::as_wide_impl(str, strlen(str)); - } - - PUGI__FN std::basic_string PUGIXML_FUNCTION as_wide(const std::string& str) - { - return impl::as_wide_impl(str.c_str(), str.size()); + return impl::as_wide_impl(str.data(), str.length()); } #endif diff --git a/src/pugixml.hpp b/src/pugixml.hpp index 080f61f3..bc5d62cc 100644 --- a/src/pugixml.hpp +++ b/src/pugixml.hpp @@ -1561,12 +1561,10 @@ namespace pugi #ifndef PUGIXML_NO_STL // Convert wide string to UTF8 - std::basic_string, std::allocator > PUGIXML_FUNCTION as_utf8(const wchar_t* str); - std::basic_string, std::allocator > PUGIXML_FUNCTION as_utf8(const std::basic_string, std::allocator >& str); + std::string PUGIXML_FUNCTION as_utf8(const pugi::wstring_view& str); // Convert UTF8 to wide string - std::basic_string, std::allocator > PUGIXML_FUNCTION as_wide(const char* str); - std::basic_string, std::allocator > PUGIXML_FUNCTION as_wide(const std::basic_string, std::allocator >& str); + std::wstring PUGIXML_FUNCTION as_wide(const pugi::string_view& str); #endif // Memory allocation function interface; returns pointer to allocated memory or NULL on failure From 6c2bb13a449d659d10b81f50c9a52845aa0fb677 Mon Sep 17 00:00:00 2001 From: halx99 Date: Tue, 8 Feb 2022 21:52:04 +0800 Subject: [PATCH 33/43] Fix ci --- src/pugixml.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pugixml.hpp b/src/pugixml.hpp index bc5d62cc..a3c9177b 100644 --- a/src/pugixml.hpp +++ b/src/pugixml.hpp @@ -153,8 +153,8 @@ namespace pugi { const Char* p; std::size_t s; - basic_string_view(const std::string& r) - : p(r.data()), s(r.size()) { + basic_string_view(const std::basic_string& r) + : p(r.c_str()), s(r.size()) { } basic_string_view(const Char* ptr) : p(ptr), s(Traits::length(ptr)) { From 62e2407c86c848ef6c14e57a059e3d5287f2297d Mon Sep 17 00:00:00 2001 From: TodorHryn Date: Mon, 16 May 2022 13:21:20 +0300 Subject: [PATCH 34/43] Fix memory leak --- src/pugixml.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index 089959c0..b187a11c 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -4836,7 +4836,11 @@ PUGI__NS_BEGIN size_t length = 0; // coverity[var_deref_model] - if (!impl::convert_buffer(buffer, length, buffer_encoding, contents, size, is_mutable)) return impl::make_parse_result(status_out_of_memory); + if (!impl::convert_buffer(buffer, length, buffer_encoding, contents, size, is_mutable)) + { + if (own && contents) impl::xml_memory::deallocate(contents); + return impl::make_parse_result(status_out_of_memory); + } // delete original buffer if we performed a conversion if (own && buffer != contents && contents) impl::xml_memory::deallocate(contents); From 7f2d74df4aa8532d1a47ec52b15db294753a50b6 Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Mon, 16 May 2022 19:10:12 -0700 Subject: [PATCH 35/43] Fix memory leak during OOM in convert_buffer This is the same fix as #497, but we're using auto_deleter instead because if allocation function throws, we can't rely on an explicit call to deallocate. Comes along with two tests that validate the behavior. --- src/pugixml.cpp | 12 +++++++----- tests/test_document.cpp | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index b187a11c..ae8cfde6 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -4831,16 +4831,18 @@ PUGI__NS_BEGIN // get actual encoding xml_encoding buffer_encoding = impl::get_buffer_encoding(encoding, contents, size); + // if convert_buffer below throws bad_alloc, we still need to deallocate contents if we own it + auto_deleter contents_guard(own ? contents : NULL, xml_memory::deallocate); + // get private buffer char_t* buffer = 0; size_t length = 0; // coverity[var_deref_model] - if (!impl::convert_buffer(buffer, length, buffer_encoding, contents, size, is_mutable)) - { - if (own && contents) impl::xml_memory::deallocate(contents); - return impl::make_parse_result(status_out_of_memory); - } + if (!impl::convert_buffer(buffer, length, buffer_encoding, contents, size, is_mutable)) return impl::make_parse_result(status_out_of_memory); + + // after this we either deallocate contents (below) or hold on to it via doc->buffer, so we don't need to guard it + contents_guard.data = NULL; // delete original buffer if we performed a conversion if (own && buffer != contents && contents) impl::xml_memory::deallocate(contents); diff --git a/tests/test_document.cpp b/tests/test_document.cpp index 493882d2..2eb5c869 100644 --- a/tests/test_document.cpp +++ b/tests/test_document.cpp @@ -1817,3 +1817,39 @@ TEST(document_move_assign_empty) CHECK_NODE(doc, STR("")); } #endif + +TEST(document_load_buffer_convert_out_of_memory) +{ + const char* source = "\xe7"; + size_t size = strlen(source); + + test_runner::_memory_fail_threshold = 1; + + xml_document doc; + + xml_parse_result result; + result.status = status_out_of_memory; + CHECK_ALLOC_FAIL(result = doc.load_buffer(source, size, pugi::parse_default, pugi::encoding_latin1)); + + CHECK(result.status == status_out_of_memory); +} + +TEST(document_load_buffer_own_convert_out_of_memory) +{ + const char* source = "\xe7"; + size_t size = strlen(source); + + void* buffer = pugi::get_memory_allocation_function()(size); + CHECK(buffer); + memcpy(buffer, source, size); + + test_runner::_memory_fail_threshold = 1; + + xml_document doc; + + xml_parse_result result; + result.status = status_out_of_memory; + CHECK_ALLOC_FAIL(result = doc.load_buffer_inplace_own(buffer, size, pugi::parse_default, pugi::encoding_latin1)); + + CHECK(result.status == status_out_of_memory); +} From 1c6a55f422bf951a56b08f0a275fec6d1fbdb168 Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Mon, 16 May 2022 19:14:29 -0700 Subject: [PATCH 36/43] Use more idiomatic code in this codebase --- src/pugixml.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index ae8cfde6..d76d6ec6 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -4832,7 +4832,7 @@ PUGI__NS_BEGIN xml_encoding buffer_encoding = impl::get_buffer_encoding(encoding, contents, size); // if convert_buffer below throws bad_alloc, we still need to deallocate contents if we own it - auto_deleter contents_guard(own ? contents : NULL, xml_memory::deallocate); + auto_deleter contents_guard(own ? contents : 0, xml_memory::deallocate); // get private buffer char_t* buffer = 0; @@ -4842,7 +4842,7 @@ PUGI__NS_BEGIN if (!impl::convert_buffer(buffer, length, buffer_encoding, contents, size, is_mutable)) return impl::make_parse_result(status_out_of_memory); // after this we either deallocate contents (below) or hold on to it via doc->buffer, so we don't need to guard it - contents_guard.data = NULL; + contents_guard.release(); // delete original buffer if we performed a conversion if (own && buffer != contents && contents) impl::xml_memory::deallocate(contents); From 4bec1e8a9c0a52440a6040f1b988ae23123a6931 Mon Sep 17 00:00:00 2001 From: halx99 Date: Wed, 5 Oct 2022 10:49:18 +0800 Subject: [PATCH 37/43] C++20 compiler support --- src/pugixml.hpp | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/src/pugixml.hpp b/src/pugixml.hpp index 8f9049e2..7704a9a1 100644 --- a/src/pugixml.hpp +++ b/src/pugixml.hpp @@ -38,15 +38,30 @@ # include #endif -#if (defined(__cplusplus) && __cplusplus == 201703L) || (defined(_MSC_VER) && _MSC_VER > 1900 && ((defined(_HAS_CXX17) && _HAS_CXX17 == 1) || (defined(_MSVC_LANG) && (_MSVC_LANG > 201402L)))) -#ifndef PUGI_CXX17_FEATURES -#define PUGI_CXX17_FEATURES 1 -#endif // C++17 features macro -#endif // C++17 features check - -#if defined(PUGI_CXX17_FEATURES) && PUGI_CXX17_FEATURES -#include -#endif // C++17 features +// Tests whether compiler has c++17 support +#if (defined(__cplusplus) && __cplusplus >= 201703L) || \ + (defined(_MSC_VER) && _MSC_VER > 1900 && \ + ((defined(_HAS_CXX17) && _HAS_CXX17 == 1) || \ + (defined(_MSVC_LANG) && (_MSVC_LANG > 201402L)))) +# ifndef PUGI_CXX_STD +# define PUGI_CXX_STD 17 +# endif // C++17 features macro +#endif // C++17 features check + +// Tests whether compiler has c++20 support +#if (defined(__cplusplus) && __cplusplus > 201703L) || \ + (defined(_MSC_VER) && _MSC_VER > 1900 && \ + ((defined(_HAS_CXX20) && _HAS_CXX20 == 1) || \ + (defined(_MSVC_LANG) && (_MSVC_LANG > 201703L)))) +# ifdef PUGI_CXX_STD +# undef PUGI_CXX_STD +# define PUGI_CXX_STD 20 +# endif // C++20 features macro +#endif // C++20 features check + +#if !defined(PUGI_CXX_STD) +# define PUGI_CXX_STD 11 +#endif // Macro for deprecated features #ifndef PUGIXML_DEPRECATED @@ -142,7 +157,7 @@ // The string_view namespace pugi { -#if defined(PUGI_CXX17_FEATURES) && PUGI_CXX17_FEATURES +#if PUGI_CXX_STD >= 17 template > using basic_string_view = std::basic_string_view; typedef std::string_view string_view; From 72e32013fcbae69a49c183259ee677ef281d8720 Mon Sep 17 00:00:00 2001 From: halx99 Date: Wed, 5 Oct 2022 10:55:57 +0800 Subject: [PATCH 38/43] c++ 20 compiler support --- tests/test_memory.cpp | 2 +- tests/test_unicode.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_memory.cpp b/tests/test_memory.cpp index 32587362..790ce979 100644 --- a/tests/test_memory.cpp +++ b/tests/test_memory.cpp @@ -110,7 +110,7 @@ TEST(memory_large_allocations) // grow for (node = doc.first_child(); node; node = node.next_sibling()) { - std::basic_string s = node.value(); + std::basic_string s{ node.value() }; CHECK(node.set_value((s + s).c_str())); } diff --git a/tests/test_unicode.cpp b/tests/test_unicode.cpp index 4cb61142..82bf2829 100644 --- a/tests/test_unicode.cpp +++ b/tests/test_unicode.cpp @@ -146,7 +146,7 @@ TEST(as_utf8_invalid) TEST(as_utf8_string) { - std::basic_string s = L"abcd"; + std::wstring s = L"abcd"; CHECK(as_utf8(s) == "abcd"); } From 377a2a91fd5ca882154d2486fe8a5116efa2f1ec Mon Sep 17 00:00:00 2001 From: halx99 Date: Wed, 5 Oct 2022 10:58:55 +0800 Subject: [PATCH 39/43] c++20 compiler support --- src/pugixml.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pugixml.hpp b/src/pugixml.hpp index 7704a9a1..f3b78a79 100644 --- a/src/pugixml.hpp +++ b/src/pugixml.hpp @@ -55,8 +55,8 @@ (defined(_MSVC_LANG) && (_MSVC_LANG > 201703L)))) # ifdef PUGI_CXX_STD # undef PUGI_CXX_STD +# endif # define PUGI_CXX_STD 20 -# endif // C++20 features macro #endif // C++20 features check #if !defined(PUGI_CXX_STD) From 5d8dbac43ca5955eb6a03379f64dc7138465be59 Mon Sep 17 00:00:00 2001 From: halx99 Date: Wed, 5 Oct 2022 11:00:48 +0800 Subject: [PATCH 40/43] Fix ci --- tests/test_memory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_memory.cpp b/tests/test_memory.cpp index 790ce979..0085cf19 100644 --- a/tests/test_memory.cpp +++ b/tests/test_memory.cpp @@ -110,7 +110,7 @@ TEST(memory_large_allocations) // grow for (node = doc.first_child(); node; node = node.next_sibling()) { - std::basic_string s{ node.value() }; + std::basic_string s(node.value()); CHECK(node.set_value((s + s).c_str())); } From f79549cc09f1750d312c526ffa410018aa91689c Mon Sep 17 00:00:00 2001 From: halx99 Date: Sat, 4 Feb 2023 14:03:05 +0800 Subject: [PATCH 41/43] 1.13 ABI compatible --- src/pugixml.cpp | 53 +++++++++++++++++++++++++++++++------------------ src/pugixml.hpp | 29 +++++++++++++++------------ 2 files changed, 50 insertions(+), 32 deletions(-) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index 9bde50df..1555b0c0 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -2457,7 +2457,7 @@ PUGI__NS_BEGIN } template - PUGI__FN bool strcpy_insitu(String& dest, int& dest_len, Header& header, uintptr_t header_mask, const char_t* source, size_t source_length, bool shallow_copy = false) + PUGI__FN bool strcpy_insitu(String& dest, int& dest_len, Header& header, uintptr_t header_mask, const char_t* source, size_t source_length, boolean shallow_copy = pugi::false_value) { dest_len = static_cast(source_length); @@ -4836,7 +4836,7 @@ PUGI__NS_BEGIN template PUGI__FN bool set_value_bool(String& dest, int& dest_len, Header& header, uintptr_t header_mask, bool value) { - return strcpy_insitu(dest, dest_len, header, header_mask, value ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"), value ? 4 : 5, true); + return strcpy_insitu(dest, dest_len, header, header_mask, value ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"), value ? 4 : 5, true_value); } PUGI__FN xml_parse_result load_buffer_impl(xml_document_struct* doc, xml_node_struct* root, void* contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own, char_t** out_buffer) @@ -5485,20 +5485,25 @@ namespace pugi } #endif - PUGI__FN bool xml_attribute::set_name(string_view_t rhs, bool shallow_copy) + PUGI__FN bool xml_attribute::set_name(string_view_t rhs, boolean shallow_copy) { if (!_attr) return false; return impl::strcpy_insitu(_attr->name, _attr->name_len, _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, bool shallow_copy) + PUGI__FN bool xml_attribute::set_value(string_view_t rhs, boolean shallow_copy) { if (!_attr) return false; return impl::strcpy_insitu(_attr->value, _attr->value_len, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs.data(), rhs.length(), shallow_copy); } + PUGI__FN bool xml_attribute::set_value(char_t* rhs, size_t sz) + { + return set_value(string_view_t{rhs, sz }); + } + PUGI__FN bool xml_attribute::set_value(int rhs) { if (!_attr) return false; @@ -5847,7 +5852,7 @@ namespace pugi return first ? xml_node(first->prev_sibling_c) : xml_node(); } - PUGI__FN bool xml_node::set_name(string_view_t rhs, bool shallow_copy) + PUGI__FN bool xml_node::set_name(string_view_t rhs, boolean shallow_copy) { xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null; @@ -5857,7 +5862,7 @@ namespace pugi return impl::strcpy_insitu(_root->name, _root->name_len, _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, bool shallow_copy) + PUGI__FN bool xml_node::set_value(string_view_t rhs, boolean shallow_copy) { xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null; @@ -5867,7 +5872,12 @@ namespace pugi return impl::strcpy_insitu(_root->value, _root->value_len, _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_, bool shallow_copy) + PUGI__FN bool xml_node::set_value(char_t* rhs, size_t sz) + { + return set_value(string_view_t{ rhs, sz }); + } + + PUGI__FN xml_attribute xml_node::append_attribute(string_view_t name_, boolean shallow_copy) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); @@ -5884,7 +5894,7 @@ namespace pugi return a; } - PUGI__FN xml_attribute xml_node::prepend_attribute(string_view_t name_, bool shallow_copy) + PUGI__FN xml_attribute xml_node::prepend_attribute(string_view_t name_, boolean shallow_copy) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); @@ -5901,7 +5911,7 @@ namespace pugi return a; } - PUGI__FN xml_attribute xml_node::insert_attribute_after(string_view_t name_, const xml_attribute& attr, bool shallow_copy) + PUGI__FN xml_attribute xml_node::insert_attribute_after(string_view_t name_, const xml_attribute& attr, boolean shallow_copy) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); @@ -5919,7 +5929,7 @@ namespace pugi return a; } - PUGI__FN xml_attribute xml_node::insert_attribute_before(string_view_t name_, const xml_attribute& attr, bool shallow_copy) + PUGI__FN xml_attribute xml_node::insert_attribute_before(string_view_t name_, const xml_attribute& attr, boolean shallow_copy) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); @@ -6019,7 +6029,7 @@ namespace pugi impl::append_node(n._root, _root); - if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"), true); + if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"), true_value); return n; } @@ -6036,7 +6046,7 @@ namespace pugi impl::prepend_node(n._root, _root); - if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"), true); + if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"), true_value); return n; } @@ -6054,7 +6064,7 @@ namespace pugi impl::insert_node_before(n._root, node._root); - if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"), true); + if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"), true_value); return n; } @@ -6072,12 +6082,12 @@ namespace pugi impl::insert_node_after(n._root, node._root); - if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"), true); + if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"), true_value); return n; } - PUGI__FN xml_node xml_node::append_child(string_view_t name_, bool shallow_copy) + PUGI__FN xml_node xml_node::append_child(string_view_t name_, boolean shallow_copy) { xml_node result = append_child(node_element); @@ -6086,7 +6096,7 @@ namespace pugi return result; } - PUGI__FN xml_node xml_node::prepend_child(string_view_t name_, bool shallow_copy) + PUGI__FN xml_node xml_node::prepend_child(string_view_t name_, boolean shallow_copy) { xml_node result = prepend_child(node_element); @@ -6095,7 +6105,7 @@ namespace pugi return result; } - PUGI__FN xml_node xml_node::insert_child_after(string_view_t name_, const xml_node& node, bool shallow_copy) + PUGI__FN xml_node xml_node::insert_child_after(string_view_t name_, const xml_node& node, boolean shallow_copy) { xml_node result = insert_child_after(node_element, node); @@ -6104,7 +6114,7 @@ namespace pugi return result; } - PUGI__FN xml_node xml_node::insert_child_before(string_view_t name_, const xml_node& node, bool shallow_copy) + PUGI__FN xml_node xml_node::insert_child_before(string_view_t name_, const xml_node& node, boolean shallow_copy) { xml_node result = insert_child_before(node_element, node); @@ -6720,13 +6730,18 @@ namespace pugi } #endif - PUGI__FN bool xml_text::set(string_view_t rhs, bool shallow_copy) + PUGI__FN bool xml_text::set(string_view_t rhs, boolean shallow_copy) { xml_node_struct* dn = _data_new(); return dn ? impl::strcpy_insitu(dn->value, dn->value_len, dn->header, impl::xml_memory_page_value_allocated_mask, rhs.data(), rhs.length(), shallow_copy) : false; } + PUGI__FN bool xml_text::set(char_t* rhs, size_t sz) + { + return set(string_view_t{ rhs, sz }); + } + PUGI__FN bool xml_text::set(int rhs) { xml_node_struct* dn = _data_new(); diff --git a/src/pugixml.hpp b/src/pugixml.hpp index 58dbb787..308271c5 100644 --- a/src/pugixml.hpp +++ b/src/pugixml.hpp @@ -568,8 +568,9 @@ namespace pugi bool as_bool(bool def = false) const; // Set attribute name/value (returns false if attribute is empty or there is not enough memory) - bool set_name(string_view_t rhs, bool shallow_copy = false); - bool set_value(string_view_t rhs, bool shallow_copy = false); + bool set_name(string_view_t rhs, boolean shallow_copy = pugi::false_value); + bool set_value(string_view_t rhs, boolean shallow_copy = pugi::false_value); + bool set_value(char_t*, size_t sz); // 1.13 ABI compatible // Set attribute value with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") bool set_value(int rhs); @@ -702,14 +703,15 @@ namespace pugi string_view_t child_value(string_view_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) - bool set_name(string_view_t rhs, bool shallow_copy = false); - bool set_value(string_view_t rhs, bool shallow_copy = false); + bool set_name(string_view_t rhs, boolean shallow_copy = pugi::false_value); + bool set_value(string_view_t rhs, boolean shallow_copy = pugi::false_value); + bool set_value(char_t* rhs, size_t sz); // 1.13 ABI compatible // Add attribute with specified name. Returns added attribute, or empty attribute on errors. - xml_attribute append_attribute(string_view_t name, bool shallow_copy = false); - 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, bool shallow_copy = false); - xml_attribute insert_attribute_before(string_view_t name, const xml_attribute& attr, bool shallow_copy = false); + xml_attribute append_attribute(string_view_t name, boolean shallow_copy = pugi::false_value); + xml_attribute prepend_attribute(string_view_t name, boolean shallow_copy = pugi::false_value); + xml_attribute insert_attribute_after(string_view_t name, const xml_attribute& attr, boolean shallow_copy = pugi::false_value); + xml_attribute insert_attribute_before(string_view_t name, const xml_attribute& attr, boolean shallow_copy = pugi::false_value); // Add a copy of the specified attribute. Returns added attribute, or empty attribute on errors. xml_attribute append_copy(const xml_attribute& proto); @@ -724,10 +726,10 @@ namespace pugi 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. - xml_node append_child(string_view_t name, bool shallow_copy = false); - 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, bool shallow_copy = false); - xml_node insert_child_before(string_view_t name, const xml_node& node, bool shallow_copy = false); + xml_node append_child(string_view_t name, boolean shallow_copy = pugi::false_value); + xml_node prepend_child(string_view_t name, boolean shallow_copy = pugi::false_value); + xml_node insert_child_after(string_view_t name, const xml_node& node, boolean shallow_copy = pugi::false_value); + xml_node insert_child_before(string_view_t name, const xml_node& node, boolean shallow_copy = pugi::false_value); // 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); @@ -931,7 +933,8 @@ namespace pugi bool as_bool(bool def = false) const; // Set text (returns false if object is empty or there is not enough memory) - bool set(string_view_t rhs, bool shallow_copy = false); + bool set(string_view_t rhs, boolean shallow_copy = pugi::false_value); + bool set(char_t* rhs, size_t sz); // 1.13 ABI compatible // Set text with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") bool set(int rhs); From a328bb527b331757b5707fa21a8eb04a98e4a0ff Mon Sep 17 00:00:00 2001 From: halx99 Date: Sat, 4 Feb 2023 14:36:01 +0800 Subject: [PATCH 42/43] Fix ci --- src/pugixml.cpp | 6 +++--- src/pugixml.hpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index 1555b0c0..a648e04e 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -5499,7 +5499,7 @@ namespace pugi return impl::strcpy_insitu(_attr->value, _attr->value_len, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs.data(), rhs.length(), shallow_copy); } - PUGI__FN bool xml_attribute::set_value(char_t* rhs, size_t sz) + PUGI__FN bool xml_attribute::set_value(const char_t* rhs, size_t sz) { return set_value(string_view_t{rhs, sz }); } @@ -5872,7 +5872,7 @@ namespace pugi return impl::strcpy_insitu(_root->value, _root->value_len, _root->header, impl::xml_memory_page_value_allocated_mask, rhs.data(), rhs.length(), shallow_copy); } - PUGI__FN bool xml_node::set_value(char_t* rhs, size_t sz) + PUGI__FN bool xml_node::set_value(const char_t* rhs, size_t sz) { return set_value(string_view_t{ rhs, sz }); } @@ -6737,7 +6737,7 @@ namespace pugi return dn ? impl::strcpy_insitu(dn->value, dn->value_len, dn->header, impl::xml_memory_page_value_allocated_mask, rhs.data(), rhs.length(), shallow_copy) : false; } - PUGI__FN bool xml_text::set(char_t* rhs, size_t sz) + PUGI__FN bool xml_text::set(const char_t* rhs, size_t sz) { return set(string_view_t{ rhs, sz }); } diff --git a/src/pugixml.hpp b/src/pugixml.hpp index 308271c5..8adbb6fc 100644 --- a/src/pugixml.hpp +++ b/src/pugixml.hpp @@ -570,7 +570,7 @@ namespace pugi // Set attribute name/value (returns false if attribute is empty or there is not enough memory) bool set_name(string_view_t rhs, boolean shallow_copy = pugi::false_value); bool set_value(string_view_t rhs, boolean shallow_copy = pugi::false_value); - bool set_value(char_t*, size_t sz); // 1.13 ABI compatible + bool set_value(const char_t*, size_t sz); // 1.13 ABI compatible // Set attribute value with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") bool set_value(int rhs); @@ -705,7 +705,7 @@ namespace pugi // 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, boolean shallow_copy = pugi::false_value); bool set_value(string_view_t rhs, boolean shallow_copy = pugi::false_value); - bool set_value(char_t* rhs, size_t sz); // 1.13 ABI compatible + bool set_value(const char_t* rhs, size_t sz); // 1.13 ABI compatible // Add attribute with specified name. Returns added attribute, or empty attribute on errors. xml_attribute append_attribute(string_view_t name, boolean shallow_copy = pugi::false_value); @@ -934,7 +934,7 @@ namespace pugi // Set text (returns false if object is empty or there is not enough memory) bool set(string_view_t rhs, boolean shallow_copy = pugi::false_value); - bool set(char_t* rhs, size_t sz); // 1.13 ABI compatible + bool set(const char_t* rhs, size_t sz); // 1.13 ABI compatible // Set text with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") bool set(int rhs); From 66e143022eb7209f7ca71ff37a585d7e9dfc8cb6 Mon Sep 17 00:00:00 2001 From: halx99 Date: Sat, 4 Feb 2023 14:38:13 +0800 Subject: [PATCH 43/43] Fix ci --- src/pugixml.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index a648e04e..f316b299 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -5501,7 +5501,7 @@ namespace pugi PUGI__FN bool xml_attribute::set_value(const char_t* rhs, size_t sz) { - return set_value(string_view_t{rhs, sz }); + return set_value(string_view_t(rhs, sz )); } PUGI__FN bool xml_attribute::set_value(int rhs) @@ -5874,7 +5874,7 @@ namespace pugi PUGI__FN bool xml_node::set_value(const char_t* rhs, size_t sz) { - return set_value(string_view_t{ rhs, sz }); + return set_value(string_view_t( rhs, sz )); } PUGI__FN xml_attribute xml_node::append_attribute(string_view_t name_, boolean shallow_copy) @@ -6739,7 +6739,7 @@ namespace pugi PUGI__FN bool xml_text::set(const char_t* rhs, size_t sz) { - return set(string_view_t{ rhs, sz }); + return set(string_view_t( rhs, sz )); } PUGI__FN bool xml_text::set(int rhs)