mirror of
https://github.com/zeux/pugixml.git
synced 2024-12-25 20:14:10 +08:00
Initial support for std::string_view (#633)
When PUGIXML_STRING_VIEW define is set and C++17 is available, add std::string_view support to a few functions. In the future, string view support will be enabled without the need for an extra define, but for now the support is opt-in to reduce compatibility risks. PR is based on initial contribution by @brandl-muc.
This commit is contained in:
parent
3b17184379
commit
a0db6e2185
12
.github/workflows/build.yml
vendored
12
.github/workflows/build.yml
vendored
@ -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_COMPACT, PUGIXML_NO_EXCEPTIONS, PUGIXML_STRING_VIEW]
|
||||
exclude:
|
||||
- os: macos
|
||||
compiler: g++
|
||||
@ -25,6 +25,7 @@ jobs:
|
||||
export CXX=${{matrix.compiler}}
|
||||
make test cxxstd=c++11 defines=${{matrix.defines}} config=release -j2
|
||||
make test cxxstd=c++98 defines=${{matrix.defines}} config=debug -j2
|
||||
make test cxxstd=c++17 defines=${{matrix.defines}} config=debug -j2
|
||||
make test defines=${{matrix.defines}} config=sanitize -j2
|
||||
- name: make coverage
|
||||
if: ${{!(matrix.os == 'ubuntu' && matrix.compiler == 'clang++')}} # linux/clang produces coverage info gcov can't parse
|
||||
@ -38,7 +39,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [Win32, x64]
|
||||
defines: [standard, PUGIXML_WCHAR_MODE, PUGIXML_COMPACT, PUGIXML_NO_EXCEPTIONS]
|
||||
defines: [standard, PUGIXML_WCHAR_MODE, PUGIXML_COMPACT, PUGIXML_NO_EXCEPTIONS, PUGIXML_STRING_VIEW]
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: cmake configure
|
||||
@ -50,3 +51,10 @@ jobs:
|
||||
Debug/pugixml-check.exe
|
||||
cmake --build . -- -property:Configuration=Release -verbosity:minimal
|
||||
Release/pugixml-check.exe
|
||||
- name: cmake configure (c++17)
|
||||
run: cmake . -DPUGIXML_BUILD_TESTS=ON -DCMAKE_CXX_STANDARD=17 -D${{matrix.defines}}=ON -A ${{matrix.arch}}
|
||||
- name: cmake test (c++17)
|
||||
shell: bash # necessary for fail-fast
|
||||
run: |
|
||||
cmake --build . -- -property:Configuration=Debug -verbosity:minimal
|
||||
Debug/pugixml-check.exe
|
||||
|
@ -48,14 +48,17 @@ option(PUGIXML_INSTALL "Enable installation rules" ON)
|
||||
option(PUGIXML_NO_XPATH "Disable XPath" OFF)
|
||||
option(PUGIXML_NO_STL "Disable STL" OFF)
|
||||
option(PUGIXML_NO_EXCEPTIONS "Disable Exceptions" OFF)
|
||||
mark_as_advanced(PUGIXML_NO_XPATH PUGIXML_NO_STL PUGIXML_NO_EXCEPTIONS)
|
||||
option(PUGIXML_STRING_VIEW "Enable std::string_view overloads" OFF) # requires C++17 and for PUGI_NO_STL to be OFF
|
||||
mark_as_advanced(PUGIXML_NO_XPATH PUGIXML_NO_STL PUGIXML_NO_EXCEPTIONS PUGIXML_STRING_VIEW)
|
||||
|
||||
set(PUGIXML_PUBLIC_DEFINITIONS
|
||||
$<$<BOOL:${PUGIXML_WCHAR_MODE}>:PUGIXML_WCHAR_MODE>
|
||||
$<$<BOOL:${PUGIXML_COMPACT}>:PUGIXML_COMPACT>
|
||||
$<$<BOOL:${PUGIXML_NO_XPATH}>:PUGIXML_NO_XPATH>
|
||||
$<$<BOOL:${PUGIXML_NO_STL}>:PUGIXML_NO_STL>
|
||||
$<$<BOOL:${PUGIXML_NO_EXCEPTIONS}>:PUGIXML_NO_EXCEPTIONS>)
|
||||
$<$<BOOL:${PUGIXML_NO_EXCEPTIONS}>:PUGIXML_NO_EXCEPTIONS>
|
||||
$<$<BOOL:${PUGIXML_STRING_VIEW}>:PUGIXML_STRING_VIEW>
|
||||
)
|
||||
|
||||
# This is used to backport a CMake 3.15 feature, but is also forwards compatible
|
||||
if (NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY)
|
||||
|
@ -49,6 +49,11 @@
|
||||
// Uncomment this to enable long long support
|
||||
// #define PUGIXML_HAS_LONG_LONG
|
||||
|
||||
// Uncomment this to enable support for std::string_view (requires c++17 and for PUGIXML_NO_STL to not be set)
|
||||
// Note: In a future version of pugixml this macro will become obsolete.
|
||||
// Support will then be enabled automatically if the used C++ standard supports it.
|
||||
// #define PUGIXML_STRING_VIEW
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
@ -5441,6 +5441,15 @@ namespace pugi
|
||||
return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs, size);
|
||||
}
|
||||
|
||||
#ifdef PUGIXML_HAS_STRING_VIEW
|
||||
PUGI_IMPL_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.size());
|
||||
}
|
||||
#endif
|
||||
|
||||
PUGI_IMPL_FN bool xml_attribute::set_value(const char_t* rhs)
|
||||
{
|
||||
if (!_attr) return false;
|
||||
@ -5455,6 +5464,15 @@ namespace pugi
|
||||
return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, size);
|
||||
}
|
||||
|
||||
#ifdef PUGIXML_HAS_STRING_VIEW
|
||||
PUGI_IMPL_FN bool xml_attribute::set_value(string_view_t rhs)
|
||||
{
|
||||
if (!_attr) return false;
|
||||
|
||||
return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs.data(), rhs.size());
|
||||
}
|
||||
#endif
|
||||
|
||||
PUGI_IMPL_FN bool xml_attribute::set_value(int rhs)
|
||||
{
|
||||
if (!_attr) return false;
|
||||
@ -5848,6 +5866,18 @@ namespace pugi
|
||||
return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs, size);
|
||||
}
|
||||
|
||||
#ifdef PUGIXML_HAS_STRING_VIEW
|
||||
PUGI_IMPL_FN bool xml_node::set_name(string_view_t rhs)
|
||||
{
|
||||
xml_node_type type_ = _root ? PUGI_IMPL_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.size());
|
||||
}
|
||||
#endif
|
||||
|
||||
PUGI_IMPL_FN bool xml_node::set_value(const char_t* rhs)
|
||||
{
|
||||
xml_node_type type_ = _root ? PUGI_IMPL_NODETYPE(_root) : node_null;
|
||||
@ -5868,6 +5898,18 @@ namespace pugi
|
||||
return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs, size);
|
||||
}
|
||||
|
||||
#ifdef PUGIXML_HAS_STRING_VIEW
|
||||
PUGI_IMPL_FN bool xml_node::set_value(string_view_t rhs)
|
||||
{
|
||||
xml_node_type type_ = _root ? PUGI_IMPL_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.size());
|
||||
}
|
||||
#endif
|
||||
|
||||
PUGI_IMPL_FN xml_attribute xml_node::append_attribute(const char_t* name_)
|
||||
{
|
||||
if (!impl::allow_insert_attribute(type())) return xml_attribute();
|
||||
@ -6757,6 +6799,15 @@ namespace pugi
|
||||
return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, size) : false;
|
||||
}
|
||||
|
||||
#ifdef PUGIXML_HAS_STRING_VIEW
|
||||
PUGI_IMPL_FN bool xml_text::set(string_view_t rhs)
|
||||
{
|
||||
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.size()) : false;
|
||||
}
|
||||
#endif
|
||||
|
||||
PUGI_IMPL_FN bool xml_text::set(int rhs)
|
||||
{
|
||||
xml_node_struct* dn = _data_new();
|
||||
|
@ -38,6 +38,20 @@
|
||||
# include <string>
|
||||
#endif
|
||||
|
||||
// Check if std::string_view is both requested and available
|
||||
#if defined(PUGIXML_STRING_VIEW) && !defined(PUGIXML_NO_STL)
|
||||
# if __cplusplus >= 201703L
|
||||
# define PUGIXML_HAS_STRING_VIEW
|
||||
# elif defined(_MSVC_LANG) && _MSVC_LANG >= 201703L
|
||||
# define PUGIXML_HAS_STRING_VIEW
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Include string_view if appropriate
|
||||
#ifdef PUGIXML_HAS_STRING_VIEW
|
||||
# include <string_view>
|
||||
#endif
|
||||
|
||||
// Macro for deprecated features
|
||||
#ifndef PUGIXML_DEPRECATED
|
||||
# if defined(__GNUC__)
|
||||
@ -140,6 +154,11 @@ namespace pugi
|
||||
// String type used for operations that work with STL string; depends on PUGIXML_WCHAR_MODE
|
||||
typedef std::basic_string<PUGIXML_CHAR> string_t;
|
||||
#endif
|
||||
|
||||
#ifdef PUGIXML_HAS_STRING_VIEW
|
||||
// String view type used for operations that can work with a length delimited string; depends on PUGIXML_WCHAR_MODE
|
||||
typedef std::basic_string_view<PUGIXML_CHAR> string_view_t;
|
||||
#endif
|
||||
}
|
||||
|
||||
// The PugiXML namespace
|
||||
@ -423,8 +442,14 @@ namespace pugi
|
||||
// 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_name(const char_t* rhs, size_t size);
|
||||
#ifdef PUGIXML_HAS_STRING_VIEW
|
||||
bool set_name(string_view_t rhs);
|
||||
#endif
|
||||
bool set_value(const char_t* rhs);
|
||||
bool set_value(const char_t* rhs, size_t size);
|
||||
#ifdef PUGIXML_HAS_STRING_VIEW
|
||||
bool set_value(string_view_t rhs);
|
||||
#endif
|
||||
|
||||
// Set attribute value with type conversion (numbers are converted to strings, boolean is converted to "true"/"false")
|
||||
bool set_value(int rhs);
|
||||
@ -559,8 +584,14 @@ 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(const char_t* rhs);
|
||||
bool set_name(const char_t* rhs, size_t size);
|
||||
#ifdef PUGIXML_HAS_STRING_VIEW
|
||||
bool set_name(string_view_t rhs);
|
||||
#endif
|
||||
bool set_value(const char_t* rhs);
|
||||
bool set_value(const char_t* rhs, size_t size);
|
||||
#ifdef PUGIXML_HAS_STRING_VIEW
|
||||
bool set_value(string_view_t rhs);
|
||||
#endif
|
||||
|
||||
// Add attribute with specified name. Returns added attribute, or empty attribute on errors.
|
||||
xml_attribute append_attribute(const char_t* name);
|
||||
@ -790,6 +821,9 @@ namespace pugi
|
||||
// Set text (returns false if object is empty or there is not enough memory)
|
||||
bool set(const char_t* rhs);
|
||||
bool set(const char_t* rhs, size_t size);
|
||||
#ifdef PUGIXML_HAS_STRING_VIEW
|
||||
bool set(string_view_t rhs);
|
||||
#endif
|
||||
|
||||
// Set text with type conversion (numbers are converted to strings, boolean is converted to "true"/"false")
|
||||
bool set(int rhs);
|
||||
|
@ -56,6 +56,23 @@ TEST_XML(dom_attr_set_name_with_size, "<node attr='value' />")
|
||||
CHECK_NODE(doc, STR("<node n=\"value\"/>"));
|
||||
}
|
||||
|
||||
#ifdef PUGIXML_HAS_STRING_VIEW
|
||||
TEST_XML(dom_attr_set_name_with_string_view, "<node attr='value' />")
|
||||
{
|
||||
xml_attribute attr = doc.child(STR("node")).attribute(STR("attr"));
|
||||
|
||||
CHECK(attr.set_name(string_view_t()));
|
||||
CHECK(!xml_attribute().set_name(string_view_t()));
|
||||
|
||||
CHECK_NODE(doc, STR("<node :anonymous=\"value\"/>"));
|
||||
|
||||
CHECK(attr.set_name(string_view_t(STR("n1234"), 1)));
|
||||
CHECK(!xml_attribute().set_name(string_view_t(STR("nfail"), 1)));
|
||||
|
||||
CHECK_NODE(doc, STR("<node n=\"value\"/>"));
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_XML(dom_attr_set_value, "<node/>")
|
||||
{
|
||||
xml_node node = doc.child(STR("node"));
|
||||
@ -225,6 +242,25 @@ TEST_XML(dom_node_set_name_with_size, "<node>text</node>")
|
||||
CHECK_NODE(doc, STR("<n>text</n>"));
|
||||
}
|
||||
|
||||
#ifdef PUGIXML_HAS_STRING_VIEW
|
||||
TEST_XML(dom_node_set_name_with_string_view, "<node>text</node>")
|
||||
{
|
||||
xml_node node = doc.child(STR("node"));
|
||||
|
||||
CHECK(node.set_name(string_view_t()));
|
||||
CHECK(!node.first_child().set_name(string_view_t(STR("n42"), 1)));
|
||||
CHECK(!xml_node().set_name(string_view_t(STR("nanothername"), 1)));
|
||||
|
||||
CHECK_NODE(doc, STR("<:anonymous>text</:anonymous>"));
|
||||
|
||||
CHECK(node.set_name(string_view_t(STR("nlongname"), 1)));
|
||||
CHECK(!doc.child(STR("node")).first_child().set_name(string_view_t(STR("n42"), 1)));
|
||||
CHECK(!xml_node().set_name(string_view_t(STR("nanothername"), 1)));
|
||||
|
||||
CHECK_NODE(doc, STR("<n>text</n>"));
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_XML(dom_node_set_value, "<node>text</node>")
|
||||
{
|
||||
CHECK(doc.child(STR("node")).first_child().set_value(STR("no text")));
|
||||
@ -252,6 +288,26 @@ TEST_XML(dom_node_set_value_with_size, "<node>text</node>")
|
||||
CHECK_NODE(doc, STR("<node>no text</node>"));
|
||||
}
|
||||
|
||||
#ifdef PUGIXML_HAS_STRING_VIEW
|
||||
TEST_XML(dom_node_set_value_partially_with_string_view, "<node>text</node>")
|
||||
{
|
||||
CHECK(doc.child(STR("node")).first_child().set_value(string_view_t(STR("no text"), 2)));
|
||||
CHECK(!doc.child(STR("node")).set_value(string_view_t(STR("no text"), 2)));
|
||||
CHECK(!xml_node().set_value(string_view_t(STR("no text"), 2)));
|
||||
|
||||
CHECK_NODE(doc, STR("<node>no</node>"));
|
||||
}
|
||||
|
||||
TEST_XML(dom_node_set_value_with_string_view, "<node>text</node>")
|
||||
{
|
||||
CHECK(doc.child(STR("node")).first_child().set_value(string_view_t(STR("no text"), 7)));
|
||||
CHECK(!doc.child(STR("node")).set_value(string_view_t(STR("no text"), 7)));
|
||||
CHECK(!xml_node().set_value(string_view_t(STR("no text"), 7)));
|
||||
|
||||
CHECK_NODE(doc, STR("<node>no text</node>"));
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_XML(dom_node_set_value_allocated, "<node>text</node>")
|
||||
{
|
||||
CHECK(doc.child(STR("node")).first_child().set_value(STR("no text")));
|
||||
|
@ -301,6 +301,69 @@ TEST_XML(dom_text_set_partially_with_size, "<node/>")
|
||||
CHECK_NODE(node, STR("<node></node>"));
|
||||
}
|
||||
|
||||
#ifdef PUGIXML_HAS_STRING_VIEW
|
||||
TEST_XML(dom_text_set_with_string_view, "<node/>")
|
||||
{
|
||||
xml_node node = doc.child(STR("node"));
|
||||
xml_text t = node.text();
|
||||
|
||||
t.set(string_view_t(STR("")));
|
||||
CHECK(node.first_child().type() == node_pcdata);
|
||||
CHECK_NODE(node, STR("<node></node>"));
|
||||
|
||||
t.set(string_view_t(STR("boo")));
|
||||
CHECK(node.first_child().type() == node_pcdata);
|
||||
CHECK(node.first_child() == node.last_child());
|
||||
CHECK_NODE(node, STR("<node>boo</node>"));
|
||||
|
||||
t.set(string_view_t(STR("foobarfoobar")));
|
||||
CHECK(node.first_child().type() == node_pcdata);
|
||||
CHECK(node.first_child() == node.last_child());
|
||||
CHECK_NODE(node, STR("<node>foobarfoobar</node>"));
|
||||
|
||||
t.set(string_view_t(STR("")));
|
||||
CHECK(node.first_child().type() == node_pcdata);
|
||||
CHECK_NODE(node, STR("<node></node>"));
|
||||
|
||||
t.set(string_view_t(STR("something")));
|
||||
CHECK(node.first_child().type() == node_pcdata);
|
||||
CHECK_NODE(node, STR("<node>something</node>"));
|
||||
|
||||
// empty string view (null data pointer)
|
||||
t.set(string_view_t());
|
||||
CHECK(node.first_child().type() == node_pcdata);
|
||||
CHECK_NODE(node, STR("<node></node>"));
|
||||
|
||||
t.set(string_view_t(STR("afternulldata")));
|
||||
CHECK(node.first_child().type() == node_pcdata);
|
||||
CHECK_NODE(node, STR("<node>afternulldata</node>"));
|
||||
}
|
||||
|
||||
TEST_XML(dom_text_set_partially_with_string_view, "<node/>")
|
||||
{
|
||||
xml_node node = doc.child(STR("node"));
|
||||
xml_text t = node.text();
|
||||
|
||||
t.set(string_view_t(STR("foo"), 0));
|
||||
CHECK(node.first_child().type() == node_pcdata);
|
||||
CHECK_NODE(node, STR("<node></node>"));
|
||||
|
||||
t.set(string_view_t(STR("boofoo"), 3));
|
||||
CHECK(node.first_child().type() == node_pcdata);
|
||||
CHECK(node.first_child() == node.last_child());
|
||||
CHECK_NODE(node, STR("<node>boo</node>"));
|
||||
|
||||
t.set(string_view_t(STR("foobarfoobar"), 3));
|
||||
CHECK(node.first_child().type() == node_pcdata);
|
||||
CHECK(node.first_child() == node.last_child());
|
||||
CHECK_NODE(node, STR("<node>foo</node>"));
|
||||
|
||||
t.set(string_view_t(STR("foo"), 0));
|
||||
CHECK(node.first_child().type() == node_pcdata);
|
||||
CHECK_NODE(node, STR("<node></node>"));
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_XML(dom_text_assign, "<node/>")
|
||||
{
|
||||
xml_node node = doc.child(STR("node"));
|
||||
@ -334,6 +397,10 @@ TEST_XML(dom_text_set_value, "<node/>")
|
||||
|
||||
CHECK(node.append_child(STR("text1")).text().set(STR("v1")));
|
||||
CHECK(!xml_text().set(STR("v1")));
|
||||
CHECK(!xml_text().set(STR("v1"), 2));
|
||||
#ifdef PUGIXML_HAS_STRING_VIEW
|
||||
CHECK(!xml_text().set(string_view_t(STR("v1"))));
|
||||
#endif
|
||||
|
||||
CHECK(node.append_child(STR("text2")).text().set(-2147483647));
|
||||
CHECK(node.append_child(STR("text3")).text().set(-2147483647 - 1));
|
||||
@ -470,6 +537,29 @@ TEST_XML(dom_text_middle, "<node><c1>notthisone</c1>text<c2/></node>")
|
||||
CHECK(t.data() == node.last_child());
|
||||
}
|
||||
|
||||
#ifdef PUGIXML_HAS_STRING_VIEW
|
||||
TEST_XML(dom_text_middle_string_view, "<node><c1>notthisone</c1>text<c2/></node>")
|
||||
{
|
||||
xml_node node = doc.child(STR("node"));
|
||||
xml_text t = node.text();
|
||||
|
||||
CHECK_STRING(t.get(), STR("text"));
|
||||
t.set(string_view_t(STR("notext")));
|
||||
|
||||
CHECK_NODE(node, STR("<node><c1>notthisone</c1>notext<c2/></node>"));
|
||||
CHECK(node.remove_child(t.data()));
|
||||
|
||||
CHECK(!t);
|
||||
CHECK_NODE(node, STR("<node><c1>notthisone</c1><c2/></node>"));
|
||||
|
||||
t.set(string_view_t(STR("yestext")));
|
||||
|
||||
CHECK(t);
|
||||
CHECK_NODE(node, STR("<node><c1>notthisone</c1><c2/>yestext</node>"));
|
||||
CHECK(t.data() == node.last_child());
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_XML_FLAGS(dom_text_data, "<node><a>foo</a><b><![CDATA[bar]]></b><c><?pi value?></c><d/></node>", parse_default | parse_pi)
|
||||
{
|
||||
xml_node node = doc.child(STR("node"));
|
||||
|
Loading…
x
Reference in New Issue
Block a user