From 15697a7b8600d93b141e0ccb4349364252895f64 Mon Sep 17 00:00:00 2001 From: halx99 Date: Wed, 29 Sep 2021 10:37:52 +0800 Subject: [PATCH] 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 2b365d9..374c8eb 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 ed234fb..2213336 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);