From a8236e65b7b6f4ae126191aea95bdfd022fba6a4 Mon Sep 17 00:00:00 2001 From: qicosmos Date: Mon, 10 Jul 2023 11:07:29 +0800 Subject: [PATCH 1/8] do some improvement --- benchmark/xml_benchmark.cpp | 43 ++++++---- iguana/xml_reader.hpp | 1 - iguana/xml_util.hpp | 151 +++++++++++++++++------------------- 3 files changed, 101 insertions(+), 94 deletions(-) diff --git a/benchmark/xml_benchmark.cpp b/benchmark/xml_benchmark.cpp index 5c378b3a..344b0244 100644 --- a/benchmark/xml_benchmark.cpp +++ b/benchmark/xml_benchmark.cpp @@ -44,16 +44,18 @@ const int iterations = 1000; void bench_de_sample_filelists() { std::string xmlfilelist = xml_file_content("../data/rpm_filelists.xml"); + rapidxml::xml_document<> doc; { ScopedTimer timer("rapidxml fastest parse rpm_filelists.xml"); for (int i = 0; i < iterations; ++i) { - rapidxml::xml_document<> doc; doc.parse(xmlfilelist.data()); + doc.clear(); } } + + filelists_t filelist; { ScopedTimer timer("iguana_xml deserialize rpm_filelists.xml"); - filelists_t filelist; for (int i = 0; i < iterations; ++i) { iguana::from_xml(filelist, xmlfilelist.begin(), xmlfilelist.end()); filelist.package.clear(); @@ -63,16 +65,18 @@ void bench_de_sample_filelists() { void bench_de_sample_rss() { std::string xmlrss = xml_file_content("../data/sample_rss.xml"); + rapidxml::xml_document<> doc; { ScopedTimer timer("rapidxml fastest parse sample_rss.xml"); for (int i = 0; i < iterations; ++i) { - rapidxml::xml_document<> doc; doc.parse(xmlrss.data()); + doc.clear(); } } + + rss_t rss; { ScopedTimer timer("iguana_xml deserialize sample_rss.xml"); - rss_t rss; for (int i = 0; i < iterations; ++i) { iguana::from_xml(rss, xmlrss.begin(), xmlrss.end()); rss.channel.item.clear(); @@ -82,28 +86,41 @@ void bench_de_sample_rss() { void bench_num() { std::string xmlnum = xml_file_content("../data/bench_num.xml"); + + store_t s; { ScopedTimer timer("iguana_xml deserialize bench_num.xml"); for (int i = 0; i < iterations; ++i) { - store_t s; iguana::from_xml(s, xmlnum); + s.goods.clear(); } } - store_t store; - iguana::from_xml(store, xmlnum); - std::string ss; - ss.reserve(xmlnum.size()); + + rapidxml::xml_document<> doc; { - ScopedTimer timer("iguana_xml serialize bench_num.xml"); + ScopedTimer timer("rapidxml fastest parse bench_num.xml"); for (int i = 0; i < iterations; ++i) { - iguana::to_xml(store, ss); - ss.clear(); + + doc.parse(xmlnum.data()); + doc.clear(); } } + + // store_t store; + // iguana::from_xml(store, xmlnum); + // std::string ss; + // ss.reserve(xmlnum.size()); + // { + // ScopedTimer timer("iguana_xml serialize bench_num.xml"); + // for (int i = 0; i < iterations; ++i) { + // iguana::to_xml(store, ss); + // ss.clear(); + // } + // } } int main() { bench_de_sample_filelists(); bench_de_sample_rss(); - // bench_num(); + bench_num(); } diff --git a/iguana/xml_reader.hpp b/iguana/xml_reader.hpp index a3aabe37..f8a21ee2 100644 --- a/iguana/xml_reader.hpp +++ b/iguana/xml_reader.hpp @@ -134,7 +134,6 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, skip_sapces_and_newline(it, end); auto value_begin = it; auto value_end = skip_pass_smaller(it, end); - ; if (value_begin == value_end) { match_close_tag(it, end, name); return; diff --git a/iguana/xml_util.hpp b/iguana/xml_util.hpp index eda70fec..7c83f91d 100644 --- a/iguana/xml_util.hpp +++ b/iguana/xml_util.hpp @@ -16,18 +16,18 @@ namespace iguana { template -concept char_t = std::same_as < std::decay_t, -char > || std::same_as, char16_t> || - std::same_as, char32_t> || - std::same_as, wchar_t>; +concept char_t = std::same_as, char> || + std::same_as, char16_t> || + std::same_as, char32_t> || + std::same_as, wchar_t>; template -concept bool_t = std::same_as < std::decay_t, -bool > || std::same_as, std::vector::reference>; +concept bool_t = std::same_as, bool> || + std::same_as, std::vector::reference>; template -concept int_t = - std::integral> && !char_t> && !bool_t; +concept int_t = std::integral> && ! +char_t> && !bool_t; template concept float_t = std::floating_point>; @@ -47,8 +47,8 @@ template concept str_view_t = is_basic_string_view>; template -concept str_t = - std::convertible_to, std::string_view> && !str_view_t; +concept str_t = std::convertible_to, std::string_view> && ! +str_view_t; template concept string_t = std::convertible_to, std::string_view>; @@ -62,30 +62,30 @@ concept sequence_container_t = template concept unique_ptr_t = requires(Type ptr) { - ptr.operator*(); - typename std::remove_cvref_t::element_type; -} -&&!requires(Type ptr, Type ptr2) { ptr = ptr2; }; + ptr.operator*(); + typename std::remove_cvref_t::element_type; + } && !requires(Type ptr, Type ptr2) { ptr = ptr2; }; template concept optional_t = requires(Type optional) { - optional.value(); - optional.has_value(); - optional.operator*(); - typename std::remove_cvref_t::value_type; -}; + optional.value(); + optional.has_value(); + optional.operator*(); + typename std::remove_cvref_t::value_type; + }; template concept container = requires(Type container) { - typename std::remove_cvref_t::value_type; - container.size(); - container.begin(); - container.end(); -}; + typename std::remove_cvref_t::value_type; + container.size(); + container.begin(); + container.end(); + }; template -concept map_container = container && requires(Type container) { - typename std::remove_cvref_t::mapped_type; -}; +concept map_container = + container && requires(Type container) { + typename std::remove_cvref_t::mapped_type; + }; template concept plain_t = @@ -93,24 +93,25 @@ concept plain_t = template concept c_array = std::is_array_v> && - std::extent_v> > -0; + std::extent_v> > 0; template concept array = requires(Type arr) { - arr.size(); - std::tuple_size>{}; -}; + arr.size(); + std::tuple_size>{}; + }; template -concept tuple = !array && requires(Type tuple) { - std::get<0>(tuple); - sizeof(std::tuple_size>); -}; +concept tuple = ! +array &&requires(Type tuple) { + std::get<0>(tuple); + sizeof(std::tuple_size>); + }; template -concept non_refletable = container || c_array || tuple || - optional_t || unique_ptr_t || std::is_fundamental_v; +concept non_refletable = + container || c_array || tuple || optional_t || + unique_ptr_t || std::is_fundamental_v; template > @@ -165,6 +166,35 @@ template struct string_literal { constexpr const std::string_view sv() const noexcept { return {value, size}; } }; +inline constexpr auto has_zero = [](uint64_t chunk) IGUANA__INLINE_LAMBDA { + return (((chunk - 0x0101010101010101) & ~chunk) & 0x8080808080808080); +}; + +inline constexpr auto has_greater = [](uint64_t chunk) IGUANA__INLINE_LAMBDA { + return has_zero( + chunk ^ + 0b0011111000111110001111100011111000111110001111100011111000111110); +}; + +inline constexpr auto has_space = [](uint64_t chunk) IGUANA__INLINE_LAMBDA { + return has_zero( + chunk ^ + 0b0010000000100000001000000010000000100000001000000010000000100000); +}; + +inline constexpr auto has_smaller = [](uint64_t chunk) IGUANA__INLINE_LAMBDA { + return has_zero( + chunk ^ + 0b0011110000111100001111000011110000111100001111000011110000111100); +}; + +inline constexpr auto has_square_bracket = + [](uint64_t chunk) IGUANA__INLINE_LAMBDA { + return has_zero( + chunk ^ + 0b0101110101011101010111010101110101011101010111010101110101011101); + }; + IGUANA_INLINE void skip_sapces_and_newline(auto &&it, auto &&end) { while (it != end && (*it < 33)) { ++it; @@ -227,9 +257,9 @@ IGUANA_INLINE void match_close_tag(auto &&it, auto &&end, if (it == end || (*it++) != '/') [[unlikely]] { throw std::runtime_error("unclosed tag: " + std::string(key)); } - auto size = key.size(); - if ((std::distance(it, end) <= size) || (std::string_view{&*it, size} != key)) - [[unlikely]] { + size_t size = key.size(); + if (static_cast(std::distance(it, end)) <= size || + std::string_view{&*it, size} != key) [[unlikely]] { throw std::runtime_error("unclosed tag: " + std::string(key)); } it += size; @@ -243,15 +273,6 @@ IGUANA_INLINE void match_close_tag(auto &&it, auto &&end, IGUANA_INLINE void skip_till_greater(auto &&it, auto &&end) { static_assert(std::contiguous_iterator>); - auto has_zero = [](uint64_t chunk) { - return (((chunk - 0x0101010101010101) & ~chunk) & 0x8080808080808080); - }; - auto has_greater = [&](uint64_t chunk) { - return has_zero( - chunk ^ - 0b0011111000111110001111100011111000111110001111100011111000111110); - }; - if (std::distance(it, end) >= 7) [[likely]] { const auto end_m7 = end - 7; for (; it < end_m7; it += 8) { @@ -279,19 +300,6 @@ IGUANA_INLINE void skip_till_greater(auto &&it, auto &&end) { IGUANA_INLINE void skip_till_greater_or_space(auto &&it, auto &&end) { static_assert(std::contiguous_iterator>); - auto has_zero = [](uint64_t chunk) { - return (((chunk - 0x0101010101010101) & ~chunk) & 0x8080808080808080); - }; - auto has_greater = [&](uint64_t chunk) { - return has_zero( - chunk ^ - 0b0011111000111110001111100011111000111110001111100011111000111110); - }; - auto has_space = [&](uint64_t chunk) { - return has_zero( - chunk ^ - 0b0010000000100000001000000010000000100000001000000010000000100000); - }; if (std::distance(it, end) >= 7) [[likely]] { const auto end_m7 = end - 7; for (; it < end_m7; it += 8) { @@ -320,15 +328,6 @@ IGUANA_INLINE void skip_till_greater_or_space(auto &&it, auto &&end) { IGUANA_INLINE void skip_till_smaller(auto &&it, auto &&end) { static_assert(std::contiguous_iterator>); - auto has_zero = [](uint64_t chunk) { - return (((chunk - 0x0101010101010101) & ~chunk) & 0x8080808080808080); - }; - auto has_smaller = [&](uint64_t chunk) { - return has_zero( - chunk ^ - 0b0011110000111100001111000011110000111100001111000011110000111100); - }; - if (std::distance(it, end) >= 7) [[likely]] { const auto end_m7 = end - 7; for (; it < end_m7; it += 8) { @@ -356,14 +355,6 @@ IGUANA_INLINE void skip_till_smaller(auto &&it, auto &&end) { IGUANA_INLINE void skip_till_square_bracket(auto &&it, auto &&end) { static_assert(std::contiguous_iterator>); - auto has_zero = [](uint64_t chunk) { - return (((chunk - 0x0101010101010101) & ~chunk) & 0x8080808080808080); - }; - auto has_square_bracket = [&](uint64_t chunk) { - return has_zero( - chunk ^ - 0b0101110101011101010111010101110101011101010111010101110101011101); - }; if (std::distance(it, end) >= 7) [[likely]] { const auto end_m7 = end - 7; for (; it < end_m7; it += 8) { From b484c9a1c37452df492cd06371fd37ddf914e450 Mon Sep 17 00:00:00 2001 From: qicosmos Date: Mon, 10 Jul 2023 11:30:23 +0800 Subject: [PATCH 2/8] bench bum --- benchmark/xml_bench.hpp | 14 +++++++------- benchmark/xml_benchmark.cpp | 11 ++++++++--- iguana/xml_reader.hpp | 6 ++++++ 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/benchmark/xml_bench.hpp b/benchmark/xml_bench.hpp index 16827dbe..95774951 100644 --- a/benchmark/xml_bench.hpp +++ b/benchmark/xml_bench.hpp @@ -96,13 +96,13 @@ REFLECTION(rss_t, channel); // ************ struct for bench_num.xml **************** struct goods_t { - int id; - int sales; - int inventory; - double weight; - double price; - double rating; - double discount; + std::string_view id; + std::string_view sales; + std::string_view inventory; + std::string_view weight; + std::string_view price; + std::string_view rating; + std::string_view discount; }; REFLECTION(goods_t, id, sales, inventory, weight, price, rating, discount); struct storeowner_t { diff --git a/benchmark/xml_benchmark.cpp b/benchmark/xml_benchmark.cpp index 344b0244..9baf26cf 100644 --- a/benchmark/xml_benchmark.cpp +++ b/benchmark/xml_benchmark.cpp @@ -88,6 +88,12 @@ void bench_num() { std::string xmlnum = xml_file_content("../data/bench_num.xml"); store_t s; + iguana::from_xml(s, xmlnum); + auto good = s.goods[1]; + std::cout << iguana::get_number(good.sales) << ", " + << iguana::get_number(good.weight) << "\n"; + s.goods.clear(); + { ScopedTimer timer("iguana_xml deserialize bench_num.xml"); for (int i = 0; i < iterations; ++i) { @@ -100,7 +106,6 @@ void bench_num() { { ScopedTimer timer("rapidxml fastest parse bench_num.xml"); for (int i = 0; i < iterations; ++i) { - doc.parse(xmlnum.data()); doc.clear(); } @@ -120,7 +125,7 @@ void bench_num() { } int main() { - bench_de_sample_filelists(); - bench_de_sample_rss(); + // bench_de_sample_filelists(); + // bench_de_sample_rss(); bench_num(); } diff --git a/iguana/xml_reader.hpp b/iguana/xml_reader.hpp index f8a21ee2..53488d52 100644 --- a/iguana/xml_reader.hpp +++ b/iguana/xml_reader.hpp @@ -298,4 +298,10 @@ IGUANA_INLINE void from_xml(U &value, const View &view) { from_xml(value, std::begin(view), std::end(view)); } +template IGUANA_INLINE Num get_number(std::string_view str) { + Num num; + detail::parse_value(num, str.begin(), str.end()); + return num; +} + } // namespace iguana \ No newline at end of file From ecf8c1452f2205bcc53289a86828ecd2fb115e0f Mon Sep 17 00:00:00 2001 From: qicosmos Date: Mon, 10 Jul 2023 11:45:47 +0800 Subject: [PATCH 3/8] revert some --- benchmark/xml_benchmark.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/benchmark/xml_benchmark.cpp b/benchmark/xml_benchmark.cpp index 9baf26cf..7e5260e5 100644 --- a/benchmark/xml_benchmark.cpp +++ b/benchmark/xml_benchmark.cpp @@ -125,7 +125,7 @@ void bench_num() { } int main() { - // bench_de_sample_filelists(); - // bench_de_sample_rss(); + bench_de_sample_filelists(); + bench_de_sample_rss(); bench_num(); } From 473c934826bce0d0f1ffe207d570e91d70ac918b Mon Sep 17 00:00:00 2001 From: qicosmos Date: Mon, 10 Jul 2023 14:11:07 +0800 Subject: [PATCH 4/8] use memcpy --- benchmark/xml_benchmark.cpp | 1 + frozen/string.h | 8 ++------ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/benchmark/xml_benchmark.cpp b/benchmark/xml_benchmark.cpp index 7e5260e5..e5dd563a 100644 --- a/benchmark/xml_benchmark.cpp +++ b/benchmark/xml_benchmark.cpp @@ -1,5 +1,6 @@ #include "../rapidxml/rapidxml.hpp" #include "xml_bench.hpp" +#include class ScopedTimer { public: diff --git a/frozen/string.h b/frozen/string.h index ccdef751..bf44868c 100644 --- a/frozen/string.h +++ b/frozen/string.h @@ -28,6 +28,7 @@ #include "frozen/bits/hash_string.h" #include "frozen/bits/version.h" +#include #include #ifdef FROZEN_LETITGO_HAS_STRING_VIEW @@ -61,12 +62,7 @@ template class basic_string { constexpr chr_t operator[](std::size_t i) const { return data_[i]; } constexpr bool operator==(basic_string other) const { - if (size_ != other.size_) - return false; - for (std::size_t i = 0; i < size_; ++i) - if (data_[i] != other.data_[i]) - return false; - return true; + return std::memcmp(data_, other.data_, size_) == 0; } constexpr bool operator<(const basic_string &other) const { From e39bd60f20e80bf59f5369ec868ae0f4d42ec9f6 Mon Sep 17 00:00:00 2001 From: qicosmos Date: Mon, 10 Jul 2023 14:19:37 +0800 Subject: [PATCH 5/8] revert --- frozen/string.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/frozen/string.h b/frozen/string.h index bf44868c..cad92bbe 100644 --- a/frozen/string.h +++ b/frozen/string.h @@ -62,7 +62,12 @@ template class basic_string { constexpr chr_t operator[](std::size_t i) const { return data_[i]; } constexpr bool operator==(basic_string other) const { - return std::memcmp(data_, other.data_, size_) == 0; + if (size_ != other.size_) + return false; + for (std::size_t i = 0; i < size_; ++i) + if (data_[i] != other.data_[i]) + return false; + return true; } constexpr bool operator<(const basic_string &other) const { From a0642bb6d3cef3cc039785bdd37c0562b9f23276 Mon Sep 17 00:00:00 2001 From: qicosmos Date: Mon, 10 Jul 2023 14:41:11 +0800 Subject: [PATCH 6/8] format --- iguana/xml_util.hpp | 77 ++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 39 deletions(-) diff --git a/iguana/xml_util.hpp b/iguana/xml_util.hpp index 7c83f91d..8f73f27e 100644 --- a/iguana/xml_util.hpp +++ b/iguana/xml_util.hpp @@ -16,18 +16,18 @@ namespace iguana { template -concept char_t = std::same_as, char> || - std::same_as, char16_t> || - std::same_as, char32_t> || - std::same_as, wchar_t>; +concept char_t = std::same_as < std::decay_t, +char > || std::same_as, char16_t> || + std::same_as, char32_t> || + std::same_as, wchar_t>; template -concept bool_t = std::same_as, bool> || - std::same_as, std::vector::reference>; +concept bool_t = std::same_as < std::decay_t, +bool > || std::same_as, std::vector::reference>; template -concept int_t = std::integral> && ! -char_t> && !bool_t; +concept int_t = + std::integral> && !char_t> && !bool_t; template concept float_t = std::floating_point>; @@ -47,8 +47,8 @@ template concept str_view_t = is_basic_string_view>; template -concept str_t = std::convertible_to, std::string_view> && ! -str_view_t; +concept str_t = + std::convertible_to, std::string_view> && !str_view_t; template concept string_t = std::convertible_to, std::string_view>; @@ -62,30 +62,30 @@ concept sequence_container_t = template concept unique_ptr_t = requires(Type ptr) { - ptr.operator*(); - typename std::remove_cvref_t::element_type; - } && !requires(Type ptr, Type ptr2) { ptr = ptr2; }; + ptr.operator*(); + typename std::remove_cvref_t::element_type; +} +&&!requires(Type ptr, Type ptr2) { ptr = ptr2; }; template concept optional_t = requires(Type optional) { - optional.value(); - optional.has_value(); - optional.operator*(); - typename std::remove_cvref_t::value_type; - }; + optional.value(); + optional.has_value(); + optional.operator*(); + typename std::remove_cvref_t::value_type; +}; template concept container = requires(Type container) { - typename std::remove_cvref_t::value_type; - container.size(); - container.begin(); - container.end(); - }; + typename std::remove_cvref_t::value_type; + container.size(); + container.begin(); + container.end(); +}; template -concept map_container = - container && requires(Type container) { - typename std::remove_cvref_t::mapped_type; - }; +concept map_container = container && requires(Type container) { + typename std::remove_cvref_t::mapped_type; +}; template concept plain_t = @@ -93,25 +93,24 @@ concept plain_t = template concept c_array = std::is_array_v> && - std::extent_v> > 0; + std::extent_v> > +0; template concept array = requires(Type arr) { - arr.size(); - std::tuple_size>{}; - }; + arr.size(); + std::tuple_size>{}; +}; template -concept tuple = ! -array &&requires(Type tuple) { - std::get<0>(tuple); - sizeof(std::tuple_size>); - }; +concept tuple = !array && requires(Type tuple) { + std::get<0>(tuple); + sizeof(std::tuple_size>); +}; template -concept non_refletable = - container || c_array || tuple || optional_t || - unique_ptr_t || std::is_fundamental_v; +concept non_refletable = container || c_array || tuple || + optional_t || unique_ptr_t || std::is_fundamental_v; template > 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 7/8] 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 8/8] 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 -