Skip to content

Commit

Permalink
Pick up in-progress PR from brandl-muc zeux#627
Browse files Browse the repository at this point in the history
  • Loading branch information
Dan Ignatoff committed Oct 22, 2024
1 parent 3b17184 commit afab50c
Show file tree
Hide file tree
Showing 7 changed files with 251 additions and 4 deletions.
12 changes: 10 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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++
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
7 changes: 5 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
5 changes: 5 additions & 0 deletions src/pugiconfig.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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

/**
Expand Down
51 changes: 51 additions & 0 deletions src/pugixml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5441,6 +5441,15 @@ namespace pugi
return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs, size);
}

#ifdef PUGI_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;
Expand All @@ -5455,6 +5464,15 @@ namespace pugi
return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, size);
}

#ifdef PUGI_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;
Expand Down Expand Up @@ -5848,6 +5866,18 @@ namespace pugi
return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs, size);
}

#ifdef PUGI_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;
Expand All @@ -5868,6 +5898,18 @@ namespace pugi
return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs, size);
}

#ifdef PUGI_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();
Expand Down Expand Up @@ -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 PUGI_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();
Expand Down
34 changes: 34 additions & 0 deletions src/pugixml.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 PUGI_HAS_STRING_VIEW
# elif defined(_MSVC_LANG) && _MSVC_LANG >= 201703L
# define PUGI_HAS_STRING_VIEW
# endif
#endif

// Include string_view if appropriate
#ifdef PUGI_HAS_STRING_VIEW
# include <string_view>
#endif

// Macro for deprecated features
#ifndef PUGIXML_DEPRECATED
# if defined(__GNUC__)
Expand Down Expand Up @@ -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 PUGI_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
Expand Down Expand Up @@ -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 PUGI_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 PUGI_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);
Expand Down Expand Up @@ -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 PUGI_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 PUGI_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);
Expand Down Expand Up @@ -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 PUGI_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);
Expand Down
56 changes: 56 additions & 0 deletions tests/test_dom_modify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,23 @@ TEST_XML(dom_attr_set_name_with_size, "<node attr='value' />")
CHECK_NODE(doc, STR("<node n=\"value\"/>"));
}

#ifdef PUGI_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"));
Expand Down Expand Up @@ -225,6 +242,25 @@ TEST_XML(dom_node_set_name_with_size, "<node>text</node>")
CHECK_NODE(doc, STR("<n>text</n>"));
}

#ifdef PUGI_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")));
Expand Down Expand Up @@ -252,6 +288,26 @@ TEST_XML(dom_node_set_value_with_size, "<node>text</node>")
CHECK_NODE(doc, STR("<node>no text</node>"));
}

#ifdef PUGI_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")));
Expand Down
Loading

0 comments on commit afab50c

Please sign in to comment.