From 21f457876631503c8168e74002b609b450ec5762 Mon Sep 17 00:00:00 2001 From: bbbgan <2893129936@qq.com> Date: Mon, 10 Jul 2023 18:16:54 +0800 Subject: [PATCH 1/2] support THROW_UNKNOWN_KEY --- CMakeLists.txt | 3 ++ README.md | 8 +--- iguana/json_writer.hpp | 4 +- iguana/xml_reader.hpp | 30 ++++++++++++++- test/test_xml_nothrow.cpp | 80 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 116 insertions(+), 9 deletions(-) create mode 100644 test/test_xml_nothrow.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3822a92c..b463ae1b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,6 +53,7 @@ set(TEST_YAML test/test_yaml.cpp test/test_yaml_bech.cpp) set(YAMLBENCH benchmark/yaml_benchmark.cpp) set(TEST_NOTHROW test/test_yaml_nothrow.cpp) set(TEST_UTIL test/test_util.cpp) +set(TEST_XMLNOTHROW test/test_xml_nothrow.cpp) add_executable(json_example ${JSON_EXAMPLE}) add_executable(xml_example ${XML_EXAMPLE}) @@ -67,6 +68,7 @@ add_executable(test_yaml ${TEST_YAML}) add_executable(yaml_benchmark ${YAMLBENCH}) add_executable(test_nothrow ${TEST_NOTHROW}) add_executable(test_util ${TEST_UTIL}) +add_executable(test_xml_nothrow ${TEST_XMLNOTHROW}) # unit test option(BUILD_UNIT_TESTS "Build unit tests" ON) @@ -91,3 +93,4 @@ add_test(NAME test_xml COMMAND test_xml) add_test(NAME test_yaml COMMAND test_yaml) add_test(NAME test_nothrow COMMAND test_nothrow) add_test(NAME test_util COMMAND test_util) +add_test(NAME test_xml_nothrow COMMAND test_xml_nothrow) diff --git a/README.md b/README.md index e80960b1..7b3cd433 100644 --- a/README.md +++ b/README.md @@ -96,14 +96,10 @@ person p = {"admin", 20}; iguana::string_stream ss; // here use std::string is also ok iguana::to_xml(ss, p); std::cout << ss.str() << std::endl; -// you can also call iguana::to_xml_pretty to get pretty string -iguana::string_stream s; -iguana::to_xml_pretty(s, p); -std::cout << s.str() << std::endl; // deserialization the structure from the string std::string xml = " buke 30"; -iguana::from_xml(p, xml.data()); +iguana::from_xml(p, xml); ``` #### Serialization of yaml @@ -212,7 +208,7 @@ std::string str = R"( )"; library_t lib; -iguana::from_xml(lib, str.data()); +iguana::from_xml(lib, str); ``` #### yaml diff --git a/iguana/json_writer.hpp b/iguana/json_writer.hpp index 7dd5c770..4134f4f8 100644 --- a/iguana/json_writer.hpp +++ b/iguana/json_writer.hpp @@ -174,12 +174,12 @@ template IGUANA_INLINE void render_json_value(Stream &s, T &&t) { using U = typename std::decay_t; s.push_back('['); - const size_t size = std::tuple_size_v; + constexpr size_t size = std::tuple_size_v; for_each(std::forward(t), [&s, size](auto &v, auto i) IGUANA__INLINE_LAMBDA { render_json_value(s, v); - if (i != size - 1) + if (i != size - 1) [[likely]] s.push_back(','); }); s.push_back(']'); diff --git a/iguana/xml_reader.hpp b/iguana/xml_reader.hpp index 53488d52..0f8b1384 100644 --- a/iguana/xml_reader.hpp +++ b/iguana/xml_reader.hpp @@ -159,6 +159,30 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, parse_item(value.value(), it, end, name); } +// /> or skip and until the +// loose inspection here +template +IGUANA_INLINE void skip_object_value(It &&it, It &&end, std::string_view name) { + skip_till_greater(it, end); + ++it; + if (*(it - 2) == '/') { + // .../> + return; + } + // + size_t size = name.size(); + while (it != end) { + skip_till_greater(it, end); + if (*(it - size - 2) == '<' && *(it - size - 1) == '/' && + (std::string_view{&*(it - size), size} == name)) { + ++it; + return; + } + ++it; + } + throw std::runtime_error("unclosed tag: " + std::string(name)); +} + template IGUANA_INLINE void parse_item(T &value, It &&it, It &&end, std::string_view name) { @@ -241,12 +265,16 @@ IGUANA_INLINE void parse_item(T &value, It &&it, It &&end, "type must be memberptr"); using V = std::remove_reference_t; if constexpr (!cdata_t) { - detail::parse_item(value.*member_ptr, it, end, key); + parse_item(value.*member_ptr, it, end, key); } }, member_it->second); } else [[unlikely]] { +#ifdef THROW_UNKNOWN_KEY throw std::runtime_error("Unknown key: " + std::string(key)); +#else + skip_object_value(it, end, key); +#endif } skip_sapces_and_newline(it, end); } diff --git a/test/test_xml_nothrow.cpp b/test/test_xml_nothrow.cpp new file mode 100644 index 00000000..10d65bd6 --- /dev/null +++ b/test/test_xml_nothrow.cpp @@ -0,0 +1,80 @@ +#define DOCTEST_CONFIG_IMPLEMENT +#include "doctest.h" +#undef THROW_UNKNOWN_KEY +#include "iguana/xml_reader.hpp" +#include "iguana/xml_writer.hpp" +#include +#include +#include +#include +#include +#include + +enum class enum_status { + paid, + unpaid, +}; +struct order_t { + enum_status status; + float total; +}; +REFLECTION(order_t, status, total); + +TEST_CASE("test unkonwn key") { + auto validator = [] (order_t od) { + CHECK(od.status == enum_status::unpaid); + CHECK(od.total == 65.0f); + }; + std::string str = R"( + + 12345 + 1 + + + John + ]]> + Doe +
+ 123 Main St + Anytown + CA + 12345 +
+
+ + + 67890 + Widget A + 2 + 10.00 + + + 98765 + Widget B + 3 + 15.00 + + + ]]> + 65.00 +
+ )"; + order_t od; + iguana::from_xml(od, str); + validator(od); + + std::string ss; + iguana::to_xml(od, ss); + order_t od1; + iguana::from_xml(od1, ss); + validator(od1); +} + + + +// doctest comments +// 'function' : must be 'attribute' - see issue #182 +DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4007) +int main(int argc, char **argv) { return doctest::Context(argc, argv).run(); } +DOCTEST_MSVC_SUPPRESS_WARNING_POP + From e265c979e8c87f9f10e10cddfeeb641b0d373ebd Mon Sep 17 00:00:00 2001 From: bbbgan <2893129936@qq.com> Date: Mon, 10 Jul 2023 18:28:51 +0800 Subject: [PATCH 2/2] update workflows; format --- .github/workflows/clang-format.yml | 4 ++-- .github/workflows/linux-clang.yml | 4 ++-- .github/workflows/linux-gcc.yml | 4 ++-- .github/workflows/mac.yml | 4 ++-- .github/workflows/windows.yml | 4 ++-- test/test_xml_nothrow.cpp | 5 +---- 6 files changed, 11 insertions(+), 14 deletions(-) diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml index e3be5eb1..078402ae 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/clang-format.yml @@ -2,9 +2,9 @@ name: Clang Format Diff on: push: - branches: [ master, fullsupport_xml] + branches: [ master, improve_xml] pull_request: - branches: [ master, fullsupport_xml] + branches: [ master, improve_xml] jobs: build: diff --git a/.github/workflows/linux-clang.yml b/.github/workflows/linux-clang.yml index e2e7f01c..401c8570 100644 --- a/.github/workflows/linux-clang.yml +++ b/.github/workflows/linux-clang.yml @@ -2,9 +2,9 @@ name: Ubuntu (clang) on: push: - branches: [ master, fullsupport_xml] + branches: [ master, improve_xml] pull_request: - branches: [ master, fullsupport_xml] + branches: [ master, improve_xml] jobs: build: diff --git a/.github/workflows/linux-gcc.yml b/.github/workflows/linux-gcc.yml index caaba1ef..1e0596f8 100644 --- a/.github/workflows/linux-gcc.yml +++ b/.github/workflows/linux-gcc.yml @@ -2,9 +2,9 @@ name: Ubuntu (gcc) on: push: - branches: [ master, fullsupport_xml] + branches: [ master, improve_xml] pull_request: - branches: [ master, fullsupport_xml] + branches: [ master, improve_xml] jobs: build: diff --git a/.github/workflows/mac.yml b/.github/workflows/mac.yml index 035f72de..c334ff00 100644 --- a/.github/workflows/mac.yml +++ b/.github/workflows/mac.yml @@ -2,9 +2,9 @@ name: macOS Monterey 12 on: push: - branches: [ master, fullsupport_xml] + branches: [ master, improve_xml] pull_request: - branches: [ master, fullsupport_xml] + branches: [ master, improve_xml] jobs: build: diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index a93d8f62..6a9583d8 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -2,9 +2,9 @@ name: Windows Server 2022 on: push: - branches: [ master, fullsupport_xml] + branches: [ master, improve_xml] pull_request: - branches: [ master, fullsupport_xml] + branches: [ master, improve_xml] jobs: build: diff --git a/test/test_xml_nothrow.cpp b/test/test_xml_nothrow.cpp index 10d65bd6..c5941136 100644 --- a/test/test_xml_nothrow.cpp +++ b/test/test_xml_nothrow.cpp @@ -21,7 +21,7 @@ struct order_t { REFLECTION(order_t, status, total); TEST_CASE("test unkonwn key") { - auto validator = [] (order_t od) { + auto validator = [](order_t od) { CHECK(od.status == enum_status::unpaid); CHECK(od.total == 65.0f); }; @@ -70,11 +70,8 @@ TEST_CASE("test unkonwn key") { validator(od1); } - - // doctest comments // 'function' : must be 'attribute' - see issue #182 DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4007) int main(int argc, char **argv) { return doctest::Context(argc, argv).run(); } DOCTEST_MSVC_SUPPRESS_WARNING_POP -