From f05e5c9871accf81628166c91aad8dd7d9e8c9e4 Mon Sep 17 00:00:00 2001 From: qicosmos Date: Fri, 19 May 2023 16:43:27 +0800 Subject: [PATCH] update struct_json and struct_xml (#289) --- .../iguana/iguana/detail/dragonbox_to_chars.h | 7 +- thirdparty/iguana/iguana/error_code.h | 2 +- thirdparty/iguana/iguana/json_reader.hpp | 191 ++++++++++-------- thirdparty/iguana/iguana/json_writer.hpp | 24 ++- thirdparty/iguana/iguana/reflection.hpp | 68 +++++++ thirdparty/iguana/iguana/type_traits.hpp | 1 - thirdparty/iguana/iguana/value.hpp | 36 ++-- thirdparty/iguana/iguana/xml_reader.hpp | 145 ++++++++----- thirdparty/iguana/iguana/xml_writer.hpp | 8 +- 9 files changed, 320 insertions(+), 162 deletions(-) diff --git a/thirdparty/iguana/iguana/detail/dragonbox_to_chars.h b/thirdparty/iguana/iguana/detail/dragonbox_to_chars.h index 1abeb47ec..decb6f25c 100644 --- a/thirdparty/iguana/iguana/detail/dragonbox_to_chars.h +++ b/thirdparty/iguana/iguana/detail/dragonbox_to_chars.h @@ -287,9 +287,8 @@ JKJ_FORCEINLINE static void print_9_digits(std::uint32_t s32, int &exponent, } template <> -char *to_chars>(std::uint32_t s32, - int exponent, - char *buffer) noexcept { +inline char *to_chars>( + std::uint32_t s32, int exponent, char *buffer) noexcept { // Print significand. print_9_digits(s32, exponent, buffer); @@ -317,7 +316,7 @@ char *to_chars>(std::uint32_t s32, } template <> -char *to_chars>( +inline char *to_chars>( std::uint64_t const significand, int exponent, char *buffer) noexcept { // Print significand by decomposing it into a 9-digit block and a 8-digit // block. diff --git a/thirdparty/iguana/iguana/error_code.h b/thirdparty/iguana/iguana/error_code.h index f43650ee2..d9c5b9419 100644 --- a/thirdparty/iguana/iguana/error_code.h +++ b/thirdparty/iguana/iguana/error_code.h @@ -83,7 +83,7 @@ class iguana_dom_category : public std::error_category { std::map detail_msg_map_; }; -iguana::iguana_dom_category &dom_category() { +inline iguana::iguana_dom_category &dom_category() { static iguana::iguana_dom_category instance; return instance; } diff --git a/thirdparty/iguana/iguana/json_reader.hpp b/thirdparty/iguana/iguana/json_reader.hpp index 4d6b7bab7..14ae48082 100644 --- a/thirdparty/iguana/iguana/json_reader.hpp +++ b/thirdparty/iguana/iguana/json_reader.hpp @@ -35,8 +35,18 @@ concept num_t = std::floating_point> || int_t; template concept enum_type_t = std::is_enum_v>; +template +constexpr inline bool is_basic_string_view = false; + +template +constexpr inline bool is_basic_string_view> = true; + +template +concept str_view_t = is_basic_string_view>; + template -concept str_t = std::convertible_to, std::string_view>; +concept str_t = + std::convertible_to, std::string_view> && !str_view_t; template constexpr inline bool is_std_vector_v = false; @@ -122,6 +132,44 @@ template void from_json(T &value, It &&it, It &&end); namespace detail { + +template +IGUANA_INLINE void parse_escape(U &value, It &&it, It &&end) { + if (it == end) + throw std::runtime_error(R"(Expected ")"); + if (*it == 'u') { + ++it; + if (std::distance(it, end) <= 4) + throw std::runtime_error(R"(Expected 4 hexadecimal digits)"); + auto code_point = parse_unicode_hex4(it); + encode_utf8(value, code_point); + } + else if (*it == 'n') { + ++it; + value.push_back('\n'); + } + else if (*it == 't') { + ++it; + value.push_back('\t'); + } + else if (*it == 'r') { + ++it; + value.push_back('\r'); + } + else if (*it == 'b') { + ++it; + value.push_back('\b'); + } + else if (*it == 'f') { + ++it; + value.push_back('\f'); + } + else { + value.push_back(*it); // add the escaped character + ++it; + } +} + template IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) { from_json(value, it, end); @@ -181,47 +229,8 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, bool skip = false) { skip_ws(it, end); match<'"'>(it, end); } - - if constexpr (!std::contiguous_iterator>) { - const auto cend = value.cend(); - for (auto c = value.begin(); c < cend; ++c, ++it) { - if (it == end) [[unlikely]] - throw std::runtime_error(R"(Expected ")"); - switch (*it) { - [[unlikely]] case '\\' : { - if (++it == end) [[unlikely]] - throw std::runtime_error(R"(Expected ")"); - else [[likely]] { - *c = *it; - } - break; - } - [[unlikely]] case '"' : { - ++it; - value.resize(std::distance(value.begin(), c)); - return; - } - [[unlikely]] case 'u' : { - ++it; - auto start = it; - auto code_point = parse_unicode_hex4(it); - std::string str; - encode_utf8(str, code_point); - std::memcpy(value.data(), str.data(), str.size()); - --it; - c += std::distance(start, it) - 1; - - break; - } - [[likely]] default : *c = *it; - } - } - } - - // growth portion + value.clear(); if constexpr (std::contiguous_iterator>) { - value.clear(); // Single append on unescaped strings so overwrite opt isnt - // as important auto start = it; while (it < end) { skip_till_escape_or_qoute(it, end); @@ -232,20 +241,10 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, bool skip = false) { } else { // Must be an escape - // TODO propperly handle this value.append(&*start, static_cast(std::distance(start, it))); ++it; // skip first escape - if (*it == 'u') { - ++it; - auto code_point = parse_unicode_hex4(it); - encode_utf8(value, code_point); - start = it; - } - else { - value.push_back(*it); // add the escaped character - ++it; - start = it; - } + parse_escape(value, it, end); + start = it; } } } @@ -253,11 +252,8 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, bool skip = false) { while (it != end) { switch (*it) { [[unlikely]] case '\\' : { - if (++it == end) [[unlikely]] - throw std::runtime_error(R"(Expected ")"); - else [[likely]] { - value.push_back(*it); - } + ++it; + parse_escape(value, it, end); break; } [[unlikely]] case ']' : { return; } @@ -265,17 +261,35 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, bool skip = false) { ++it; return; } - [[unlikely]] case 'u' : { + [[likely]] default : { + value.push_back(*it); ++it; - auto code_point = parse_unicode_hex4(it); - encode_utf8(value, code_point); - break; } - [[likely]] default : value.push_back(*it); } + } + } +} + +template +IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, bool skip = false) { + static_assert(std::contiguous_iterator>, + "must be contiguous"); + if (!skip) { + skip_ws(it, end); + match<'"'>(it, end); + } + using T = std::decay_t; + auto start = it; + while (it < end) { + skip_till_escape_or_qoute(it, end); + if (*it == '"') { + value = T(&*start, static_cast(std::distance(start, it))); ++it; + return; } + it += 2; } + throw std::runtime_error("Expected \""); // is needed? } template @@ -350,6 +364,7 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) { template IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) { using T = std::remove_reference_t; + using key_type = typename T::key_type; skip_ws(it, end); match<'{'>(it, end); @@ -366,17 +381,17 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) { match<','>(it, end); } - static thread_local std::string key{}; + static thread_local std::string_view key{}; parse_item(key, it, end); skip_ws(it, end); match<':'>(it, end); - if constexpr (std::is_same_v) { - parse_item(value[key], it, end); + if constexpr (str_t || str_view_t) { + parse_item(value[key_type(key)], it, end); } else { - static thread_local typename T::key_type key_value{}; + static thread_local key_type key_value{}; parse_item(key_value, key.begin(), key.end()); parse_item(value[key_value], it, end); } @@ -456,7 +471,7 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) { else { using value_type = typename T::value_type; value_type t; - if constexpr (str_t) { + if constexpr (str_t || str_view_t) { parse_item(t, it, end, true); } else { @@ -558,7 +573,7 @@ IGUANA_INLINE void from_json(T &value, It &&it, It &&end) { } else { static thread_local std::string static_key{}; - detail::parse_item(static_key, it, end, true); + detail::parse_item(static_key, it, end, false); key = static_key; } @@ -643,10 +658,10 @@ IGUANA_INLINE void from_json(T &value, const Byte *data, size_t size, } } -template +template void parse(jvalue &result, It &&it, It &&end); -template +template inline void parse_array(jarray &result, It &&it, It &&end) { skip_ws(it, end); match<'['>(it, end); @@ -660,7 +675,7 @@ inline void parse_array(jarray &result, It &&it, It &&end) { } result.emplace_back(); - parse(result.back(), it, end); + parse(result.back(), it, end); if (*it == ']') [[unlikely]] { ++it; @@ -672,7 +687,7 @@ inline void parse_array(jarray &result, It &&it, It &&end) { throw std::runtime_error("Expected ]"); } -template +template inline void parse_object(jobject &result, It &&it, It &&end) { skip_ws(it, end); match<'{'>(it, end); @@ -696,7 +711,7 @@ inline void parse_object(jobject &result, It &&it, It &&end) { match<':'>(it, end); - parse(emplaced.first->second, it, end); + parse(emplaced.first->second, it, end); if (*it == '}') [[unlikely]] { ++it; @@ -707,7 +722,7 @@ inline void parse_object(jobject &result, It &&it, It &&end) { } } -template +template inline void parse(jvalue &result, It &&it, It &&end) { skip_ws(it, end); switch (*it) { @@ -740,16 +755,22 @@ inline void parse(jvalue &result, It &&it, It &&end) { break; } case '"': - result.template emplace(); - detail::parse_item(std::get(result), it, end); + if constexpr (Is_view) { + result.template emplace(); + detail::parse_item(std::get(result), it, end); + } + else { + result.template emplace(); + detail::parse_item(std::get(result), it, end); + } break; case '[': result.template emplace(); - parse_array(std::get(result), it, end); + parse_array(std::get(result), it, end); break; case '{': { result.template emplace(); - parse_object(std::get(result), it, end); + parse_object(std::get(result), it, end); break; } default: @@ -759,10 +780,10 @@ inline void parse(jvalue &result, It &&it, It &&end) { skip_ws(it, end); } -template +template inline void parse(jvalue &result, It &&it, It &&end, std::error_code &ec) { try { - parse(result, it, end); + parse(result, it, end); ec = {}; } catch (const std::runtime_error &e) { result.template emplace(); @@ -770,15 +791,15 @@ inline void parse(jvalue &result, It &&it, It &&end, std::error_code &ec) { } } -template +template inline void parse(T &result, const View &view) { - parse(result, std::begin(view), std::end(view)); + parse(result, std::begin(view), std::end(view)); } -template +template inline void parse(T &result, const View &view, std::error_code &ec) noexcept { try { - parse(result, view); + parse(result, view); ec = {}; } catch (std::runtime_error &e) { ec = iguana::make_error_code(e.what()); diff --git a/thirdparty/iguana/iguana/json_writer.hpp b/thirdparty/iguana/iguana/json_writer.hpp index 6c9294d81..e5f26af97 100644 --- a/thirdparty/iguana/iguana/json_writer.hpp +++ b/thirdparty/iguana/iguana/json_writer.hpp @@ -7,6 +7,7 @@ #include #include +#include #include "define.h" #include "detail/dragonbox_to_chars.h" @@ -40,6 +41,10 @@ concept sequence_container_t = template concept tuple_t = is_tuple>::value; +template +concept string_container_t = + std::convertible_to, std::string_view>; + template IGUANA_INLINE void join(Stream &ss, InputIt first, InputIt last, const T &delim, const F &f) { @@ -104,10 +109,10 @@ IGUANA_INLINE void render_json_value(Stream &ss, T &value) { ss.append(temp, n); } -template -IGUANA_INLINE void render_json_value(Stream &ss, const std::string &s) { +template +IGUANA_INLINE void render_json_value(Stream &ss, T &&t) { ss.push_back('"'); - ss.append(s.data(), s.size()); + ss.append(t.data(), t.size()); ss.push_back('"'); } @@ -123,9 +128,9 @@ IGUANA_INLINE void render_key(Stream &ss, T &t) { ss.push_back('"'); } -template -IGUANA_INLINE void render_key(Stream &ss, const std::string &s) { - render_json_value(ss, s); +template +IGUANA_INLINE void render_key(Stream &ss, T &&t) { + render_json_value(ss, std::forward(t)); } template @@ -138,7 +143,7 @@ IGUANA_INLINE void render_json_value(Stream &ss, T &&t) { template IGUANA_INLINE void render_json_value(Stream &ss, T val) { - render_json_value(ss, (std::underlying_type_t &)val); + render_json_value(ss, static_cast>(val)); } template @@ -222,6 +227,11 @@ IGUANA_INLINE void to_json(T &&v, Stream &s) { s.push_back(']'); } +template +IGUANA_INLINE void to_json(T &&t, Stream &s) { + render_json_value(s, std::forward(t)); +} + template IGUANA_INLINE void to_json(T &&t, Stream &s) { using U = typename std::decay_t; diff --git a/thirdparty/iguana/iguana/reflection.hpp b/thirdparty/iguana/iguana/reflection.hpp index 168391d2f..76d1e7bc5 100644 --- a/thirdparty/iguana/iguana/reflection.hpp +++ b/thirdparty/iguana/iguana/reflection.hpp @@ -626,6 +626,10 @@ inline constexpr auto get_iguana_struct_map_impl( namespace iguana { inline std::unordered_map> g_iguana_required_map; +inline std::unordered_map< + std::string_view, + std::vector>> + g_iguana_custom_map; template inline constexpr auto get_iguana_struct_map() { using reflect_members = decltype(iguana_reflect_members(std::declval())); @@ -663,6 +667,41 @@ inline int add_required(std::string_view key, std::vector v) { #define REQUIRED(STRUCT_NAME, ...) \ REQUIRED_IMPL(STRUCT_NAME, GET_ARG_COUNT(__VA_ARGS__), __VA_ARGS__) +inline std::string_view trim_sv(std::string_view str) { + std::string_view whitespaces(" \t\f\v\n\r"); + auto first = str.find_first_not_of(whitespaces); + auto last = str.find_last_not_of(whitespaces); + if (first == std::string_view::npos || last == std::string_view::npos) + return std::string_view(); + return str.substr(first, last - first + 1); +} + +inline int add_custom_fields(std::string_view key, + std::vector v) { + std::vector> vec; + for (auto val : v) { + std::string_view str = {val.data() + 1, val.size() - 2}; + size_t pos = str.find(','); + if (pos == std::string_view::npos || pos == str.size() - 1) { + continue; + } + + std::string_view origin = str.substr(0, pos); + std::string_view alias = str.substr(pos + 1); + + vec.push_back(std::make_pair(trim_sv(origin), trim_sv(alias))); + } + g_iguana_custom_map.emplace(key, std::move(vec)); + return 0; +} + +#define CUSTOM_FIELDS_IMPL(STRUCT_NAME, N, ...) \ + inline auto IGUANA_UNIQUE_VARIABLE(STRUCT_NAME) = iguana::add_custom_fields( \ + #STRUCT_NAME, {MARCO_EXPAND(MACRO_CONCAT(CON_STR, N)(__VA_ARGS__))}); + +#define CUSTOM_FIELDS(STRUCT_NAME, ...) \ + CUSTOM_FIELDS_IMPL(STRUCT_NAME, GET_ARG_COUNT(__VA_ARGS__), __VA_ARGS__) + template using Reflect_members = decltype(iguana_reflect_members(std::declval())); @@ -796,6 +835,35 @@ inline bool is_required(std::string_view key) { return r != v.end(); } +template +inline bool has_custom_fields(std::string_view key = "") { + if (key.empty()) { + return !g_iguana_custom_map.empty(); + } + + return g_iguana_custom_map.find(key) != g_iguana_custom_map.end(); +} + +template +inline std::string_view get_custom_fields(std::string_view origin) { + constexpr std::string_view name = get_name(); + auto it = g_iguana_custom_map.find(name); + if (it == g_iguana_custom_map.end()) { + return ""; + } + + auto &vec = it->second; + auto find_it = std::find_if(vec.begin(), vec.end(), [origin](auto &pair) { + return pair.first == origin; + }); + + if (find_it == vec.end()) { + return ""; + } + + return (*find_it).second; +} + template constexpr auto get_index(std::string_view name) { using M = decltype(iguana_reflect_members(std::declval())); diff --git a/thirdparty/iguana/iguana/type_traits.hpp b/thirdparty/iguana/iguana/type_traits.hpp index 3a8062778..0459df7ae 100644 --- a/thirdparty/iguana/iguana/type_traits.hpp +++ b/thirdparty/iguana/iguana/type_traits.hpp @@ -45,5 +45,4 @@ constexpr inline bool is_namespace_v = false; template constexpr inline bool is_namespace_v> = true; - } // namespace iguana diff --git a/thirdparty/iguana/iguana/value.hpp b/thirdparty/iguana/iguana/value.hpp index 28e235bdc..d8124eb3f 100644 --- a/thirdparty/iguana/iguana/value.hpp +++ b/thirdparty/iguana/iguana/value.hpp @@ -25,23 +25,26 @@ enum dom_parse_error { ok, wrong_type }; template struct basic_json_value - : std::variant< - std::monostate, std::nullptr_t, bool, double, int, - std::basic_string, std::vector>, - json_map, basic_json_value>> { + : std::variant, + std::vector>, + json_map, basic_json_value>, + std::basic_string_view> { using string_type = std::basic_string; + using string_view_type = std::basic_string_view; using array_type = std::vector>; using object_type = json_map>; - using base_type = std::variant; + using base_type = + std::variant; using base_type::base_type; inline const static std::unordered_map type_map_ = { - {0, "undefined type"}, {1, "null type"}, {2, "bool type"}, - {3, "double type"}, {4, "int type"}, {5, "string type"}, - {6, "array type"}, {7, "object type"}}; + {0, "undefined type"}, {1, "null type"}, {2, "bool type"}, + {3, "double type"}, {4, "int type"}, {5, "string type"}, + {6, "array type"}, {7, "object type"}, {8, "string_view type"}}; basic_json_value() : base_type(std::in_place_type) {} @@ -62,6 +65,9 @@ struct basic_json_value bool is_string() const { return std::holds_alternative(*this); } bool is_array() const { return std::holds_alternative(*this); } bool is_object() const { return std::holds_alternative(*this); } + bool is_string_view() const { + return std::holds_alternative(*this); + } // if type is not match, will throw exception, if pass std::error_code, won't // throw exception @@ -98,7 +104,6 @@ struct basic_json_value v = get(ec); return ec; } - template T at(const std::string &key) { const auto &map = get(); @@ -165,11 +170,14 @@ struct basic_json_value bool to_bool() const { return get(); } bool to_bool(std::error_code &ec) const { return get(ec); } - std::basic_string to_string() const { - return get>(); + string_type to_string() const { return get(); } + string_type to_string(std::error_code &ec) const { + return get(ec); } - std::basic_string to_string(std::error_code &ec) const { - return get>(ec); + + string_view_type to_string_view() const { return get(); } + string_view_type to_string_view(std::error_code &ec) const { + return get(ec); } }; diff --git a/thirdparty/iguana/iguana/xml_reader.hpp b/thirdparty/iguana/iguana/xml_reader.hpp index b0648a81d..18dad631f 100644 --- a/thirdparty/iguana/iguana/xml_reader.hpp +++ b/thirdparty/iguana/iguana/xml_reader.hpp @@ -26,6 +26,16 @@ constexpr inline size_t find_underline(const char *str) { return c - str; } +template +inline void missing_node_handler(std::string_view name) { + std::cout << name << " not found\n"; + if (iguana::is_required(name)) { + std::string err = "required filed "; + err.append(name).append(" not found!"); + throw std::invalid_argument(err); + } +} + template inline void parse_num(T &num, std::string_view value) { if (value.empty()) { @@ -49,8 +59,7 @@ inline void parse_num(T &num, std::string_view value) { class any_t { public: - explicit any_t(std::string_view value) : value_(value) {} - explicit any_t() {} + explicit any_t(std::string_view value = "") : value_(value) {} template std::pair get() const { if constexpr (std::is_same_v || @@ -58,7 +67,7 @@ class any_t { return std::make_pair(true, T{value_}); } else if constexpr (std::is_arithmetic_v) { - T num; + T num{}; try { parse_num(num, value_); return std::make_pair(true, static_cast(num)); @@ -84,13 +93,23 @@ class namespace_t { public: using value_type = T; explicit namespace_t(T &&value) : value_(std::forward(value)) {} - explicit namespace_t() {} + namespace_t() : value_() {} const T &get() const { return value_; } private: T value_; }; +class cdata_t { + public: + cdata_t() : value_() {} + cdata_t(const char *c, size_t len) : value_(c, len) {} + std::string_view get() const { return value_; } + + private: + std::string_view value_; +}; + template inline void parse_attribute(rapidxml::xml_node *node, T &t) { using U = std::decay_t; @@ -117,6 +136,16 @@ inline void parse_attribute(rapidxml::xml_node *node, T &t) { } } +inline rapidxml::xml_node *find_cdata( + const rapidxml::xml_node *node) { + for (auto cn = node->first_node(); cn; cn = cn->next_sibling()) { + if (cn->type() == rapidxml::node_cdata) { + return cn; + } + } + return nullptr; +} + template inline void parse_item(rapidxml::xml_node *node, T &t, std::string_view value) { @@ -152,7 +181,7 @@ inline void parse_item(rapidxml::xml_node *node, T &t, else if constexpr (is_std_optinal_v) { if (!value.empty()) { using value_type = typename U::value_type; - value_type opt; + value_type opt{}; parse_item(node, opt, value); t = std::move(opt); } @@ -163,7 +192,7 @@ inline void parse_item(rapidxml::xml_node *node, T &t, } else if constexpr (is_namespace_v) { using value_type = typename U::value_type; - value_type ns; + value_type ns{}; if constexpr (is_reflection_v) { do_read(node, ns); } @@ -177,36 +206,72 @@ inline void parse_item(rapidxml::xml_node *node, T &t, } } -template -inline void parse_node(rapidxml::xml_node *n, T &&t, - std::string_view str) { - if constexpr (is_std_optinal_v< - item_type>) { // std::optional> +template +inline void parse_node(rapidxml::xml_node *node, member_type &&t, + std::string_view name) { + using item_type = std::decay_t; + if constexpr (std::is_same_v) { + auto c_node = find_cdata(node); + if (c_node) { + t = cdata_t(c_node->value(), c_node->value_size()); + } + } + else if constexpr ( + is_std_optinal_v) { // std::optional> using op_value_type = typename item_type::value_type; - if constexpr (!is_str_v && - is_container::value) { + if constexpr ((!is_str_v && + is_container::value) || + std::is_same_v) { op_value_type op_val; - parse_node(n, op_val, str); + parse_node(node, op_val, name); t = std::move(op_val); } else { - parse_item(n, t, std::string_view(n->value(), n->value_size())); + auto n = node->first_node(name.data()); + if (n) { + parse_item(n, t, std::string_view(n->value(), n->value_size())); + } } } else if constexpr (!is_str_v && is_container::value) { using value_type = typename item_type::value_type; - while (n) { - if (std::string_view(n->name(), n->name_size()) != str) { - break; + if constexpr (std::is_same_v) { + for (auto c = node->first_node(); c; c = c->next_sibling()) { + if (c->type() == rapidxml::node_cdata) { + t.push_back(value_type(c->value(), c->value_size())); + } + } + } + else { + auto n = node->first_node(name.data()); + if (n) { + while (n) { + if (std::string_view(n->name(), n->name_size()) != name) { + break; + } + value_type item; + parse_item(n, item, std::string_view(n->value(), n->value_size())); + t.push_back(std::move(item)); + n = n->next_sibling(); + } + } + else { + if constexpr (!is_std_optinal_v) { + missing_node_handler(name); + } } - value_type item; - parse_item(n, item, std::string_view(n->value(), n->value_size())); - t.push_back(std::move(item)); - n = n->next_sibling(); } } else { - parse_item(n, t, std::string_view(n->value(), n->value_size())); + auto n = node->first_node(name.data()); + if (n) { + parse_item(n, t, std::string_view(n->value(), n->value_size())); + } + else { + if constexpr (!is_std_optinal_v) { + missing_node_handler(name); + } + } } } @@ -230,32 +295,16 @@ inline void do_read(rapidxml::xml_node *node, T &&t) { if constexpr (is_map_container::value) { parse_attribute(node, t.*member_ptr); } + else if constexpr (is_namespace_v) { + constexpr auto index_ul = find_underline(key.data()); + static_assert(index_ul < key.size(), + "'_' is needed in namesapce_t value name"); + std::string ns(key.data(), key.size()); + ns[index_ul] = ':'; + parse_node(node, t.*member_ptr, ns); + } else { - rapidxml::xml_node *n = nullptr; - if constexpr (is_namespace_v) { - constexpr auto index_ul = find_underline(key.data()); - static_assert(index_ul < key.size(), - "'_' is needed in namesapce_t value name"); - std::string ns(key.data(), key.size()); - ns[index_ul] = ':'; - n = node->first_node(ns.data()); - } - else { - n = node->first_node(str.data()); - } - if (n) { - parse_node(n, t.*member_ptr, str); - } - else { - if constexpr (!is_std_optinal_v) { - std::cout << str << " not found\n"; - if (iguana::is_required(str)) { - std::string err = "required filed "; - err.append(str).append(" not found!"); - throw std::invalid_argument(err); - } - } - } + parse_node(node, t.*member_ptr, str); } } else { diff --git a/thirdparty/iguana/iguana/xml_writer.hpp b/thirdparty/iguana/iguana/xml_writer.hpp index 1ddf07397..239e2fd6f 100644 --- a/thirdparty/iguana/iguana/xml_writer.hpp +++ b/thirdparty/iguana/iguana/xml_writer.hpp @@ -21,6 +21,7 @@ template inline void to_xml_impl(Stream &s, T &&t, std::string_view name = ""); class any_t; +class cdata_t; constexpr inline size_t find_underline(const char *); template @@ -106,6 +107,9 @@ inline void render_xml_node(Stream &ss, std::string_view name, T &&item) { render_xml_value(ss, item.first); render_tail(ss, name.data()); } + else if constexpr (std::is_same_v) { + ss.append(""); + } else { render_head(ss, name.data()); render_xml_value(ss, std::forward(item)); @@ -153,7 +157,7 @@ inline void to_xml_impl(Stream &s, T &&t, std::string_view name) { } else if constexpr (is_namespace_v) { constexpr auto name = get_name(); - auto index_ul = find_underline(name.data()); + constexpr auto index_ul = find_underline(name.data()); std::string ns(name.data(), name.size()); ns[index_ul] = ':'; if constexpr (is_reflection::value) { @@ -172,7 +176,7 @@ inline void to_xml_impl(Stream &s, T &&t, std::string_view name) { render_xml_value0(s, *(t.*v), sv); } else { - render_xml_node(s, get_name().data(), t.*v); + render_xml_node(s, get_name().data(), *(t.*v)); } } }