From 00343e58b67f02cfcb2f77f4d74217a6d8f43531 Mon Sep 17 00:00:00 2001 From: qicosmos Date: Tue, 11 Jun 2024 11:25:24 +0800 Subject: [PATCH 1/4] dynamic reflection --- benchmark/pb_benchmark.cpp | 1 + iguana/detail/pb_type.hpp | 5 ++ iguana/dynamic.hpp | 89 ++++++++++++++++++++++++++++++++++++ iguana/iguana.hpp | 10 ++++ iguana/json_reader.hpp | 11 +++++ iguana/json_util.hpp | 1 + iguana/json_writer.hpp | 23 ++++++++-- iguana/pb_reader.hpp | 8 +++- iguana/pb_util.hpp | 77 +------------------------------ iguana/pb_writer.hpp | 5 ++ iguana/reflection.hpp | 6 +++ iguana/xml_reader.hpp | 47 +++++++++++++++---- iguana/xml_util.hpp | 1 + iguana/xml_writer.hpp | 44 ++++++++++++++++++ iguana/yaml_reader.hpp | 12 ++--- iguana/yaml_util.hpp | 5 +- test/proto/unittest_proto3.h | 1 + test/test_pb.cpp | 22 +++++++-- test/test_proto3.cpp | 1 + 19 files changed, 270 insertions(+), 99 deletions(-) create mode 100644 iguana/dynamic.hpp create mode 100644 iguana/iguana.hpp diff --git a/benchmark/pb_benchmark.cpp b/benchmark/pb_benchmark.cpp index c73a34b0..8787ad69 100644 --- a/benchmark/pb_benchmark.cpp +++ b/benchmark/pb_benchmark.cpp @@ -1,6 +1,7 @@ #include #define SEQUENTIAL_PARSE #include "../test/proto/unittest_proto3.h" +#include "iguana/iguana.hpp" class ScopedTimer { public: diff --git a/iguana/detail/pb_type.hpp b/iguana/detail/pb_type.hpp index 2ce5f60b..37db25f7 100644 --- a/iguana/detail/pb_type.hpp +++ b/iguana/detail/pb_type.hpp @@ -1,4 +1,5 @@ #pragma once +#include namespace iguana { @@ -87,6 +88,10 @@ inline bool operator<(const sfixed64_t& lhs, const sfixed64_t& rhs) { return lhs.val < rhs.val; } +template +constexpr bool is_pb_type_v = std::is_same_v||std::is_same_v||std::is_same_v|| +std::is_same_v || std::is_same_v|| std::is_same_v; + } // namespace iguana // for key in std::unordered_map diff --git a/iguana/dynamic.hpp b/iguana/dynamic.hpp new file mode 100644 index 00000000..86f0a177 --- /dev/null +++ b/iguana/dynamic.hpp @@ -0,0 +1,89 @@ +#pragma once +#include "reflection.hpp" + +namespace iguana { +using base = detail::base; + +template +IGUANA_INLINE constexpr size_t member_offset(T* t, U T::*member) { + return (char*)&(t->*member) - (char*)t; +} + +template +struct base_impl : public base { + void to_pb(std::string& str) override { + to_pb_adl((iguana_adl_t*)nullptr, *(static_cast(this)), str); + } + + void from_pb(std::string_view str) override { + from_pb_adl((iguana_adl_t*)nullptr, *(static_cast(this)), str); + } + + void to_json(std::string& str) override { + to_json_adl((iguana_adl_t*)nullptr, *(static_cast(this)), str); + } + + void from_json(std::string_view str) override { + from_json_adl((iguana_adl_t*)nullptr, *(static_cast(this)), str); + } + + void to_xml(std::string& str) override { + to_xml_adl((iguana_adl_t*)nullptr, *(static_cast(this)), str); + } + + void from_xml(std::string_view str) override { + from_xml_adl((iguana_adl_t*)nullptr, *(static_cast(this)), str); + } + + iguana::detail::field_info get_field_info(std::string_view name) override { + static constexpr auto map = iguana::get_members(); + iguana::detail::field_info info{}; + for (auto& [no, field] : map) { + if (info.offset > 0) { + break; + } + std::visit( + [&](auto val) { + if (val.field_name == name) { + info.offset = member_offset((T*)this, val.member_ptr); + using value_type = typename decltype(val)::value_type; +#if defined(__clang__) || defined(_MSC_VER) || \ + (defined(__GNUC__) && __GNUC__ > 8) + info.type_name = type_string(); +#endif + } + }, + field); + } + + return info; + } + + std::vector get_fields_name() override { + static constexpr auto map = iguana::get_members(); + std::vector vec; + for (auto [no, val] : map) { + std::visit( + [&](auto& field) { + vec.push_back(std::string_view(field.field_name.data(), + field.field_name.size())); + }, + val); + } + return vec; + } + + virtual ~base_impl() {} + + size_t cache_size = 0; +}; + +IGUANA_INLINE std::shared_ptr create_instance(std::string_view name) { + auto it = iguana::detail::g_pb_map.find(name); + if (it == iguana::detail::g_pb_map.end()) { + throw std::invalid_argument(std::string(name) + + "not inheried from iguana::base_impl"); + } + return it->second(); +} +} // namespace iguana \ No newline at end of file diff --git a/iguana/iguana.hpp b/iguana/iguana.hpp new file mode 100644 index 00000000..77dc2bc5 --- /dev/null +++ b/iguana/iguana.hpp @@ -0,0 +1,10 @@ +#pragma once +#include "iguana/dynamic.hpp" +#include "iguana/json_reader.hpp" +#include "iguana/json_writer.hpp" +#include "iguana/pb_reader.hpp" +#include "iguana/pb_writer.hpp" +#include "iguana/xml_reader.hpp" +#include "iguana/xml_writer.hpp" +#include "iguana/yaml_reader.hpp" +#include "iguana/yaml_writer.hpp" diff --git a/iguana/json_reader.hpp b/iguana/json_reader.hpp index 05018349..d433f017 100644 --- a/iguana/json_reader.hpp +++ b/iguana/json_reader.hpp @@ -86,6 +86,11 @@ IGUANA_INLINE void from_json_impl(U &value, It &&it, It &&end) { } } +template , int> = 0> +IGUANA_INLINE void from_json_impl(U &value, It &&it, It &&end) { + from_json_impl(value.val, it, end); +} + template , int> = 0> IGUANA_INLINE void from_json_impl(U &value, It &&it, It &&end) { skip_ws(it, end); @@ -899,4 +904,10 @@ IGUANA_INLINE void from_json_file(T &value, const std::string &filename, } } +template +IGUANA_INLINE void from_json_adl(iguana_adl_t *p, T &t, + std::string_view pb_str) { + iguana::from_json(t, pb_str); +} + } // namespace iguana diff --git a/iguana/json_util.hpp b/iguana/json_util.hpp index f1bf3a33..5887599f 100644 --- a/iguana/json_util.hpp +++ b/iguana/json_util.hpp @@ -3,6 +3,7 @@ #pragma once +#include "detail/pb_type.hpp" #include "util.hpp" #include "value.hpp" diff --git a/iguana/json_writer.hpp b/iguana/json_writer.hpp index eeaeaa39..498e0a2d 100644 --- a/iguana/json_writer.hpp +++ b/iguana/json_writer.hpp @@ -13,7 +13,7 @@ template -IGUANA_INLINE void to_json_impl(Stream &ss, std::optional &val); +IGUANA_INLINE void to_json_impl(Stream &ss, const std::optional &val); template , int> = 0> @@ -76,6 +76,12 @@ IGUANA_INLINE void to_json_impl(Stream &ss, T value) { ss.append(temp, p - temp); } +template , int> = 0> +IGUANA_INLINE void to_json_impl(Stream &ss, T value) { + to_json_impl(ss, value.val); +} + template , int> = 0> IGUANA_INLINE void to_json_impl(Stream &ss, T v) { @@ -97,12 +103,18 @@ IGUANA_INLINE void to_json_impl(Stream &ss, T &&t) { template , int> = 0> -IGUANA_INLINE void render_key(Stream &ss, T &t) { +IGUANA_INLINE void render_key(Stream &ss, const T &t) { ss.push_back('"'); to_json_impl(ss, t); ss.push_back('"'); } +template , int> = 0> +IGUANA_INLINE void render_key(Stream &ss, const T &t) { + render_key(ss, t.val); +} + template , int> = 0> IGUANA_INLINE void render_key(Stream &ss, T &&t) { @@ -140,7 +152,7 @@ IGUANA_INLINE void to_json_impl(Stream &ss, T val) { } template -IGUANA_INLINE void to_json_impl(Stream &ss, std::optional &val) { +IGUANA_INLINE void to_json_impl(Stream &ss, const std::optional &val) { if (!val) { ss.append("null"); } @@ -282,5 +294,10 @@ IGUANA_INLINE void to_json(T &&t, Stream &s) { to_json_impl(s, t); } +template +IGUANA_INLINE void to_json_adl(iguana_adl_t *p, T &t, std::string &pb_str) { + to_json(t, pb_str); +} + } // namespace iguana #endif // SERIALIZE_JSON_HPP diff --git a/iguana/pb_reader.hpp b/iguana/pb_reader.hpp index 6a0a92d9..83d2425d 100644 --- a/iguana/pb_reader.hpp +++ b/iguana/pb_reader.hpp @@ -3,7 +3,8 @@ #include "pb_util.hpp" namespace iguana { - +template +IGUANA_INLINE void from_pb(T& t, std::string_view pb_str); namespace detail { template @@ -254,4 +255,9 @@ IGUANA_INLINE void from_pb(T& t, std::string_view pb_str) { } } } + +template +IGUANA_INLINE void from_pb_adl(iguana_adl_t* p, T& t, std::string_view pb_str) { + iguana::from_pb(t, pb_str); +} } // namespace iguana diff --git a/iguana/pb_util.hpp b/iguana/pb_util.hpp index b2e46772..5fa7365c 100644 --- a/iguana/pb_util.hpp +++ b/iguana/pb_util.hpp @@ -29,83 +29,8 @@ enum class WireType : uint32_t { Unknown }; -template -IGUANA_INLINE void to_pb(T& t, Stream& out); - template -IGUANA_INLINE void from_pb(T& t, std::string_view pb_str); - -using base = detail::base; - -template -IGUANA_INLINE constexpr size_t member_offset(T* t, U T::*member) { - return (char*)&(t->*member) - (char*)t; -} - -template -struct base_impl : public base { - void to_pb(std::string& str) override { - iguana::to_pb(*(static_cast(this)), str); - } - - void from_pb(std::string_view str) override { - iguana::from_pb(*(static_cast(this)), str); - } - - iguana::detail::field_info get_field_info(std::string_view name) override { - static constexpr auto map = iguana::get_members(); - iguana::detail::field_info info{}; - for (auto [no, field] : map) { - if (info.offset > 0) { - break; - } - std::visit( - [&](auto val) { - if (val.field_name == name) { - info.offset = member_offset((T*)this, val.member_ptr); - using value_type = typename decltype(val)::value_type; -#if defined(__clang__) || defined(_MSC_VER) || \ - (defined(__GNUC__) && __GNUC__ > 8) - info.type_name = type_string(); -#endif - } - }, - field); - } - - return info; - } - - std::vector get_fields_name() override { - static constexpr auto map = iguana::get_members(); - std::vector vec; - for (auto [no, val] : map) { - std::visit( - [&](auto& field) { - vec.push_back(std::string_view(field.field_name.data(), - field.field_name.size())); - }, - val); - } - return vec; - } - - virtual ~base_impl() {} - - size_t cache_size = 0; -}; - -template -constexpr bool inherits_from_base_v = std::is_base_of_v; - -IGUANA_INLINE std::shared_ptr create_instance(std::string_view name) { - auto it = iguana::detail::g_pb_map.find(name); - if (it == iguana::detail::g_pb_map.end()) { - throw std::invalid_argument(std::string(name) + - "not inheried from iguana::base_impl"); - } - return it->second(); -} +constexpr bool inherits_from_base_v = std::is_base_of_v; namespace detail { template diff --git a/iguana/pb_writer.hpp b/iguana/pb_writer.hpp index db2662ab..9e7bbe5e 100644 --- a/iguana/pb_writer.hpp +++ b/iguana/pb_writer.hpp @@ -216,4 +216,9 @@ IGUANA_INLINE void to_pb(T& t, Stream& out) { detail::to_pb_impl<0>(t, &out[0], sz_ptr); } +template +IGUANA_INLINE void to_pb_adl(iguana_adl_t* p, T& t, Stream& out) { + to_pb(t, out); +} + } // namespace iguana diff --git a/iguana/reflection.hpp b/iguana/reflection.hpp index fdefa2bc..e1524e60 100644 --- a/iguana/reflection.hpp +++ b/iguana/reflection.hpp @@ -563,6 +563,10 @@ struct field_info { struct base { virtual void to_pb(std::string &str) {} virtual void from_pb(std::string_view str) {} + virtual void to_xml(std::string &str) {} + virtual void from_xml(std::string_view str) {} + virtual void to_json(std::string &str) {} + virtual void from_json(std::string_view str) {} virtual std::vector get_fields_name() { return {}; } virtual iguana::detail::field_info get_field_info(std::string_view name) { return {}; @@ -756,6 +760,8 @@ namespace iguana { MAKE_META_DATA(STRUCT_NAME, TABLE_NAME, GET_ARG_COUNT(__VA_ARGS__), \ __VA_ARGS__) +struct iguana_adl_t {}; + template inline auto iguana_reflect_type(const T &t); diff --git a/iguana/xml_reader.hpp b/iguana/xml_reader.hpp index 209b4f89..2047eadc 100644 --- a/iguana/xml_reader.hpp +++ b/iguana/xml_reader.hpp @@ -25,7 +25,7 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, std::string_view name); template , int> = 0> -IGUANA_INLINE void parse_value(U &&value, It &&begin, It &&end) { +IGUANA_INLINE void xml_parse_value(U &&value, It &&begin, It &&end) { using T = std::decay_t; if constexpr (string_container_v) { if constexpr (string_view_v) { @@ -70,8 +70,8 @@ IGUANA_INLINE void parse_value(U &&value, It &&begin, It &&end) { static constexpr auto str_to_enum = get_enum_map(); if constexpr (bool_v) { // not defined a specialization template - parse_value(reinterpret_cast &>(value), begin, - end); + xml_parse_value(reinterpret_cast &>(value), + begin, end); } else { auto enum_names = std::string_view( @@ -86,6 +86,12 @@ IGUANA_INLINE void parse_value(U &&value, It &&begin, It &&end) { } } } + +template , int> = 0> +IGUANA_INLINE void xml_parse_value(U &&value, It &&begin, It &&end) { + xml_parse_value(value.val, begin, end); +} + template , int> = 0> IGUANA_INLINE void parse_attr(U &&value, It &&it, It &&end) { @@ -98,7 +104,7 @@ IGUANA_INLINE void parse_attr(U &&value, It &&it, It &&end) { auto key_begin = it; auto key_end = skip_pass<'='>(it, end); key_type key; - parse_value(key, key_begin, key_end); + xml_parse_value(key, key_begin, key_end); skip_sapces_and_newline(it, end); auto value_begin = it + 1; @@ -115,7 +121,7 @@ IGUANA_INLINE void parse_attr(U &&value, It &&it, It &&end) { else IGUANA_UNLIKELY { throw std::runtime_error("expected quote or apos"); } value_type v; - parse_value(v, value_begin, value_end); + xml_parse_value(v, value_begin, value_end); value.emplace(std::move(key), std::move(v)); } } @@ -128,10 +134,16 @@ 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<'<'>(it, end); - parse_value(value, value_begin, value_end); + xml_parse_value(value, value_begin, value_end); match_close_tag(it, end, name); } +template , int> = 0> +IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, + std::string_view name) { + parse_item(value.val, it, end, name); +} + template , int> = 0> IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, @@ -159,6 +171,19 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, } } +template , int> = 0> +IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, + std::string_view name) { + throw std::bad_function_call(); +} + +template , int> = 0> +IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, + std::string_view name) { + throw std::bad_function_call(); +} + template , int>> IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, std::string_view name) { @@ -182,7 +207,7 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, match_close_tag(it, end, name); return; } - parse_value(value.emplace(), value_begin, value_end); + xml_parse_value(value.emplace(), value_begin, value_end); match_close_tag(it, end, name); } else { @@ -494,8 +519,14 @@ IGUANA_INLINE void from_xml(U &value, const View &view) { template , int> = 0> IGUANA_INLINE Num get_number(std::string_view str) { Num num; - detail::parse_value(num, str.begin(), str.end()); + detail::xml_parse_value(num, str.begin(), str.end()); return num; } +template +IGUANA_INLINE void from_xml_adl(iguana_adl_t *p, T &t, + std::string_view pb_str) { + iguana::from_xml(t, pb_str); +} + } // namespace iguana \ No newline at end of file diff --git a/iguana/xml_util.hpp b/iguana/xml_util.hpp index dabd47a3..8259e176 100644 --- a/iguana/xml_util.hpp +++ b/iguana/xml_util.hpp @@ -1,4 +1,5 @@ #pragma once +#include "detail/pb_type.hpp" #include "util.hpp" namespace iguana { diff --git a/iguana/xml_writer.hpp b/iguana/xml_writer.hpp index 94e35f37..f9d5009d 100644 --- a/iguana/xml_writer.hpp +++ b/iguana/xml_writer.hpp @@ -63,6 +63,11 @@ template , int> = 0> +IGUANA_INLINE void render_xml_value(Stream &ss, const T &value, + std::string_view name); + template , int> = 0> IGUANA_INLINE void render_xml_value(Stream &ss, T &&t, std::string_view name); @@ -133,6 +138,12 @@ IGUANA_INLINE void render_value(Stream &ss, const T &value) { } } +template , int> = 0> +IGUANA_INLINE void render_value(Stream &ss, const T &value) { + render_value(ss, value); +} + template , int> = 0> inline void render_xml_attr(Stream &ss, const T &value, std::string_view name) { @@ -160,6 +171,20 @@ IGUANA_INLINE void render_xml_value(Stream &ss, const T &value, render_tail(ss, name); } +template >, int> = 0> +IGUANA_INLINE void render_xml_value(Stream &ss, const T &value, + std::string_view name) { + render_xml_value(ss, value.val, name); +} + +template >, int> = 0> +IGUANA_INLINE void render_xml_value(Stream &ss, const T &value, + std::string_view name) { + throw std::bad_function_call(); +} + template , int> = 0> IGUANA_INLINE void render_xml_value(Stream &ss, const T &value, @@ -209,6 +234,20 @@ IGUANA_INLINE void render_xml_value(Stream &ss, const T &value, } } +template , int>> +IGUANA_INLINE void render_xml_value(Stream &ss, const T &value, + std::string_view name) { + throw std::bad_function_call(); +} + +template , int>> +IGUANA_INLINE void render_xml_value(Stream &ss, const T &value, + std::string_view name) { + throw std::bad_function_call(); +} + template , int>> IGUANA_INLINE void render_xml_value(Stream &ss, T &&t, std::string_view name) { @@ -267,4 +306,9 @@ IGUANA_INLINE void to_xml(T &&t, Stream &s) { render_xml_value(s, std::forward(t), root_name); } +template +IGUANA_INLINE void to_xml_adl(iguana_adl_t *p, T &t, std::string &pb_str) { + to_xml(t, pb_str); +} + } // namespace iguana diff --git a/iguana/yaml_reader.hpp b/iguana/yaml_reader.hpp index 0a0d47fa..49a31953 100644 --- a/iguana/yaml_reader.hpp +++ b/iguana/yaml_reader.hpp @@ -259,7 +259,7 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, size_t min_spaces) { } if constexpr (plain_v) { auto start = it; - auto value_end = skip_till<',', ']'>(it, end); + auto value_end = yaml_skip_till<',', ']'>(it, end); parse_value(value.emplace_back(), start, value_end); if (*(it - 1) == ']') IGUANA_UNLIKELY { return; } @@ -316,7 +316,7 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, size_t min_spaces) { skip_space_and_lines(it, end, min_spaces); if constexpr (plain_v) { auto start = it; - auto value_end = skip_till<',', ']'>(it, end); + auto value_end = yaml_skip_till<',', ']'>(it, end); parse_value(v, start, value_end); } else { @@ -370,13 +370,13 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, size_t min_spaces) { return; } auto start = it; - auto value_end = skip_till<':'>(it, end); + auto value_end = yaml_skip_till<':'>(it, end); key_type key; parse_value(key, start, value_end); subspaces = skip_space_and_lines(it, end, min_spaces); if constexpr (plain_v) { start = it; - value_end = skip_till<',', '}'>(it, end); + value_end = yaml_skip_till<',', '}'>(it, end); parse_value(value[key], start, value_end); if (*(it - 1) == '}') IGUANA_UNLIKELY { return; } @@ -399,7 +399,7 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, size_t min_spaces) { return; } auto start = it; - auto value_end = skip_till<':'>(it, end); + auto value_end = yaml_skip_till<':'>(it, end); key_type key; parse_value(key, start, value_end); subspaces = skip_space_and_lines(it, end, min_spaces); @@ -494,7 +494,7 @@ IGUANA_INLINE void from_yaml(T &value, It &&it, It &&end, size_t min_spaces) { auto spaces = skip_space_and_lines(it, end, min_spaces); while (it != end) { auto start = it; - auto keyend = skip_till<':'>(it, end); + auto keyend = yaml_skip_till<':'>(it, end); std::string_view key = std::string_view{ &*start, static_cast(std::distance(start, keyend))}; static constexpr auto frozen_map = get_iguana_struct_map(); diff --git a/iguana/yaml_util.hpp b/iguana/yaml_util.hpp index 0f2be370..b1b93a6a 100644 --- a/iguana/yaml_util.hpp +++ b/iguana/yaml_util.hpp @@ -1,5 +1,6 @@ #pragma once +#include "detail/pb_type.hpp" #include "util.hpp" namespace iguana { @@ -42,7 +43,7 @@ IGUANA_INLINE auto skip_till_newline(It &&it, It &&end) { } template -IGUANA_INLINE auto skip_till(It &&it, It &&end) { +IGUANA_INLINE auto yaml_skip_till(It &&it, It &&end) { if (it == end) IGUANA_UNLIKELY { return it; } std::decay_t res = it; @@ -93,7 +94,7 @@ IGUANA_INLINE size_t skip_space_and_lines(It &&it, It &&end, size_t minspaces) { // skip the --- line if ((it != end) && (*it == '-')) IGUANA_UNLIKELY { - auto line_end = skip_till(it, end); + auto line_end = yaml_skip_till(it, end); auto line = std::string_view( &*start, static_cast(std::distance(start, line_end))); if (line != "---") { diff --git a/test/proto/unittest_proto3.h b/test/proto/unittest_proto3.h index c1123b7f..4311e986 100644 --- a/test/proto/unittest_proto3.h +++ b/test/proto/unittest_proto3.h @@ -1,4 +1,5 @@ #pragma once +#include "iguana/dynamic.hpp" #include "iguana/pb_reader.hpp" #include "iguana/pb_writer.hpp" #if defined(STRUCT_PB_WITH_PROTO) diff --git a/test/test_pb.cpp b/test/test_pb.cpp index ae5d999b..1e06a492 100644 --- a/test/test_pb.cpp +++ b/test/test_pb.cpp @@ -3,9 +3,7 @@ #define DOCTEST_CONFIG_IMPLEMENT #include "doctest.h" -#include "iguana/pb_reader.hpp" -#include "iguana/pb_writer.hpp" - +#include "iguana/iguana.hpp" #if defined(__clang__) || defined(_MSC_VER) || \ (defined(__GNUC__) && __GNUC__ > 8) void print_hex_str(const std::string &str) { @@ -279,6 +277,24 @@ TEST_CASE("test reflection") { pair_t *st = dynamic_cast(t.get()); CHECK(st->x == t1.x); CHECK(st->y == t1.y); + std::string xml; + st->to_xml(xml); + std::cout << xml << "\n"; + pair_t s; + s.from_xml(xml); + std::cout << s.x << " " << s.y << "\n"; + CHECK(st->x == s.x); + CHECK(st->y == s.y); + + std::string json; + t->to_json(json); + std::cout << json << "\n"; + + s = {}; + s.from_json(json); + std::cout << s.x << " " << s.y << "\n"; + CHECK(st->x == s.x); + CHECK(st->y == s.y); } auto t = iguana::create_instance("numer_st"); t->set_field_value("a", true); diff --git a/test/test_proto3.cpp b/test/test_proto3.cpp index 27da52e7..c5227686 100644 --- a/test/test_proto3.cpp +++ b/test/test_proto3.cpp @@ -1,5 +1,6 @@ #define DOCTEST_CONFIG_IMPLEMENT #include "doctest.h" +#include "iguana/iguana.hpp" #include "proto/unittest_proto3.h" // msg reflection #if defined(STRUCT_PB_WITH_PROTO) From 2fb49a7a31ec21fbbd15579aca87cd5dd59e37a0 Mon Sep 17 00:00:00 2001 From: qicosmos Date: Tue, 11 Jun 2024 11:27:43 +0800 Subject: [PATCH 2/4] format --- iguana/detail/pb_type.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/iguana/detail/pb_type.hpp b/iguana/detail/pb_type.hpp index 37db25f7..1b268cce 100644 --- a/iguana/detail/pb_type.hpp +++ b/iguana/detail/pb_type.hpp @@ -89,8 +89,10 @@ inline bool operator<(const sfixed64_t& lhs, const sfixed64_t& rhs) { } template -constexpr bool is_pb_type_v = std::is_same_v||std::is_same_v||std::is_same_v|| -std::is_same_v || std::is_same_v|| std::is_same_v; +constexpr bool is_pb_type_v = + std::is_same_v || std::is_same_v || + std::is_same_v || std::is_same_v || + std::is_same_v || std::is_same_v; } // namespace iguana From 450f2be31dbac7242489960b05be7a86d2bb31a0 Mon Sep 17 00:00:00 2001 From: bbgan <2893129936@qq.com> Date: Wed, 19 Jun 2024 23:36:24 +0800 Subject: [PATCH 3/4] support dynamic reflection[yaml] --- iguana/detail/pb_type.hpp | 2 +- iguana/dynamic.hpp | 8 +++ iguana/reflection.hpp | 2 + iguana/util.hpp | 4 +- iguana/xml_reader.hpp | 72 +++++++++++----------- iguana/yaml_reader.hpp | 126 ++++++++++++++++++++++++++------------ iguana/yaml_util.hpp | 4 ++ iguana/yaml_writer.hpp | 17 +++++ test/test_pb.cpp | 10 +++ 9 files changed, 167 insertions(+), 78 deletions(-) diff --git a/iguana/detail/pb_type.hpp b/iguana/detail/pb_type.hpp index 1b268cce..2d17cb8e 100644 --- a/iguana/detail/pb_type.hpp +++ b/iguana/detail/pb_type.hpp @@ -88,7 +88,7 @@ inline bool operator<(const sfixed64_t& lhs, const sfixed64_t& rhs) { return lhs.val < rhs.val; } -template +template > constexpr bool is_pb_type_v = std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v || diff --git a/iguana/dynamic.hpp b/iguana/dynamic.hpp index 86f0a177..98fccdd1 100644 --- a/iguana/dynamic.hpp +++ b/iguana/dynamic.hpp @@ -35,6 +35,14 @@ struct base_impl : public base { from_xml_adl((iguana_adl_t*)nullptr, *(static_cast(this)), str); } + void to_yaml(std::string& str) override { + to_yaml_adl((iguana_adl_t*)nullptr, *(static_cast(this)), str); + } + + void from_yaml(std::string_view str) override { + from_yaml_adl((iguana_adl_t*)nullptr, *(static_cast(this)), str); + } + iguana::detail::field_info get_field_info(std::string_view name) override { static constexpr auto map = iguana::get_members(); iguana::detail::field_info info{}; diff --git a/iguana/reflection.hpp b/iguana/reflection.hpp index e1524e60..9579ce8e 100644 --- a/iguana/reflection.hpp +++ b/iguana/reflection.hpp @@ -567,6 +567,8 @@ struct base { virtual void from_xml(std::string_view str) {} virtual void to_json(std::string &str) {} virtual void from_json(std::string_view str) {} + virtual void to_yaml(std::string &str) {} + virtual void from_yaml(std::string_view str) {} virtual std::vector get_fields_name() { return {}; } virtual iguana::detail::field_info get_field_info(std::string_view name) { return {}; diff --git a/iguana/util.hpp b/iguana/util.hpp index 3f6768a9..2d89e74d 100644 --- a/iguana/util.hpp +++ b/iguana/util.hpp @@ -297,8 +297,8 @@ IGUANA_INLINE void write_string_with_escape(const Ch* it, SizeType length, template IGUANA_INLINE constexpr bool has_duplicate(const std::array& arr) { - for (int i = 0; i < arr.size(); i++) { - for (int j = i + 1; j < arr.size(); j++) { + for (size_t i = 0; i < arr.size(); i++) { + for (size_t j = i + 1; j < arr.size(); j++) { if (arr[i] == arr[j]) { return true; } diff --git a/iguana/xml_reader.hpp b/iguana/xml_reader.hpp index 2047eadc..8b9c908f 100644 --- a/iguana/xml_reader.hpp +++ b/iguana/xml_reader.hpp @@ -9,20 +9,20 @@ namespace iguana { namespace detail { template , int> = 0> -IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, - std::string_view name); +IGUANA_INLINE void xml_parse_item(U &value, It &&it, It &&end, + std::string_view name); template , int> = 0> -IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, - std::string_view name); +IGUANA_INLINE void xml_parse_item(U &value, It &&it, It &&end, + std::string_view name); template , int> = 0> -IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, - std::string_view name); +IGUANA_INLINE void xml_parse_item(U &value, It &&it, It &&end, + std::string_view name); template , int> = 0> -IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, - std::string_view name); +IGUANA_INLINE void xml_parse_item(U &value, It &&it, It &&end, + std::string_view name); template , int> = 0> IGUANA_INLINE void xml_parse_value(U &&value, It &&begin, It &&end) { @@ -127,8 +127,8 @@ IGUANA_INLINE void parse_attr(U &&value, It &&it, It &&end) { } template , int> = 0> -IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, - std::string_view name) { +IGUANA_INLINE void xml_parse_item(U &value, It &&it, It &&end, + std::string_view name) { skip_till<'>'>(it, end); ++it; skip_sapces_and_newline(it, end); @@ -139,16 +139,16 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, } template , int> = 0> -IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, - std::string_view name) { - parse_item(value.val, it, end, name); +IGUANA_INLINE void xml_parse_item(U &value, It &&it, It &&end, + std::string_view name) { + xml_parse_item(value.val, it, end, name); } template , int> = 0> -IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, - std::string_view name) { - parse_item(value.emplace_back(), it, end, name); +IGUANA_INLINE void xml_parse_item(U &value, It &&it, It &&end, + std::string_view name) { + xml_parse_item(value.emplace_back(), it, end, name); skip_sapces_and_newline(it, end); while (it != end) { match<'<'>(it, end); @@ -166,27 +166,27 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, it = start - 1; return; } - parse_item(value.emplace_back(), it, end, name); + xml_parse_item(value.emplace_back(), it, end, name); skip_sapces_and_newline(it, end); } } template , int> = 0> -IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, - std::string_view name) { +IGUANA_INLINE void xml_parse_item(U &value, It &&it, It &&end, + std::string_view name) { throw std::bad_function_call(); } template , int> = 0> -IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, - std::string_view name) { +IGUANA_INLINE void xml_parse_item(U &value, It &&it, It &&end, + std::string_view name) { throw std::bad_function_call(); } template , int>> -IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, - std::string_view name) { +IGUANA_INLINE void xml_parse_item(U &value, It &&it, It &&end, + std::string_view name) { using value_type = typename std::remove_reference_t::value_type; skip_till<'>'>(it, end); if (*(it - 1) == '/') @@ -211,13 +211,13 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, match_close_tag(it, end, name); } else { - parse_item(value.emplace(), it, end, name); + xml_parse_item(value.emplace(), it, end, name); } } template , int>> -IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, - std::string_view name) { +IGUANA_INLINE void xml_parse_item(U &value, It &&it, It &&end, + std::string_view name) { if constexpr (unique_ptr_v) { value = std::make_unique::element_type>(); } @@ -225,14 +225,14 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, value = std::make_shared::element_type>(); } - parse_item(*value, it, end, name); + xml_parse_item(*value, it, end, name); } template , int>> -IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, - std::string_view name) { +IGUANA_INLINE void xml_parse_item(U &value, It &&it, It &&end, + std::string_view name) { parse_attr(value.attr(), it, end); - parse_item(value.value(), it, end, name); + xml_parse_item(value.value(), it, end, name); } // /> or skip and until the @@ -393,8 +393,8 @@ IGUANA_INLINE void check_required(std::string_view key_set) { } template , int>> -IGUANA_INLINE void parse_item(T &value, It &&it, It &&end, - std::string_view name) { +IGUANA_INLINE void xml_parse_item(T &value, It &&it, It &&end, + std::string_view name) { using U = std::decay_t; constexpr auto cdata_idx = get_type_index(); skip_till<'>'>(it, end); @@ -425,7 +425,7 @@ IGUANA_INLINE void parse_item(T &value, It &&it, It &&end, if (parse_done || key != st_key) IGUANA_UNLIKELY { return; } if constexpr (!cdata_v) { - parse_item(value.*member_ptr, it, end, key); + xml_parse_item(value.*member_ptr, it, end, key); if constexpr (iguana::has_iguana_required_arr_v) { key_set.append(key).append(", "); } @@ -459,7 +459,7 @@ IGUANA_INLINE void parse_item(T &value, It &&it, It &&end, "type must be memberptr"); using V = std::remove_reference_t; if constexpr (!cdata_v) { - parse_item(value.*member_ptr, it, end, key); + xml_parse_item(value.*member_ptr, it, end, key); if constexpr (iguana::has_iguana_required_arr_v) { key_set.append(key).append(", "); } @@ -497,7 +497,7 @@ IGUANA_INLINE void from_xml(U &value, It &&it, It &&end) { std::string_view key = std::string_view{&*start, static_cast(std::distance(start, it))}; detail::parse_attr(value.attr(), it, end); - detail::parse_item(value.value(), it, end, key); + detail::xml_parse_item(value.value(), it, end, key); } template , int> = 0> @@ -507,7 +507,7 @@ IGUANA_INLINE void from_xml(U &value, It &&it, It &&end) { skip_till_greater_or_space(it, end); std::string_view key = std::string_view{&*start, static_cast(std::distance(start, it))}; - detail::parse_item(value, it, end, key); + detail::xml_parse_item(value, it, end, key); } template , int> = 0> +IGUANA_INLINE void yaml_parse_item(U &value, It &&it, It &&end, + size_t min_spaces) { + throw std::bad_function_call(); +} + +template , int> = 0> +IGUANA_INLINE void yaml_parse_value(U &value, It &&value_begin, + It &&value_end) { + throw std::bad_function_call(); +} + template , int> = 0> IGUANA_INLINE void parse_escape_str(U &value, It &&it, It &&end) { auto start = it; @@ -105,10 +119,12 @@ IGUANA_INLINE void parse_block_str(U &value, It &&it, It &&end, template , int> = 0> -IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, size_t min_spaces); +IGUANA_INLINE void yaml_parse_item(U &value, It &&it, It &&end, + size_t min_spaces); template , int> = 0> -IGUANA_INLINE void parse_value(U &value, It &&value_begin, It &&value_end) { +IGUANA_INLINE void yaml_parse_value(U &value, It &&value_begin, + It &&value_end) { if (value_begin == value_end) IGUANA_UNLIKELY { return; } auto size = std::distance(value_begin, value_end); @@ -116,10 +132,17 @@ IGUANA_INLINE void parse_value(U &value, It &&value_begin, It &&value_end) { detail::from_chars(start, start + size, value); } +template , int> = 0> +IGUANA_INLINE void yaml_parse_value(U &value, It &&value_begin, + It &&value_end) { + yaml_parse_value(value.val, value_begin, value_end); +} + // string_view should be used for string with ' " ? template , int> = 0> -IGUANA_INLINE void parse_value(U &value, It &&value_begin, It &&value_end) { +IGUANA_INLINE void yaml_parse_value(U &value, It &&value_begin, + It &&value_end) { using T = std::decay_t; auto start = value_begin; auto end = value_end; @@ -152,19 +175,21 @@ IGUANA_INLINE void parse_value(U &value, It &&value_begin, It &&value_end) { } template , int> = 0> -IGUANA_INLINE void parse_value(U &value, It &&value_begin, It &&value_end) { +IGUANA_INLINE void yaml_parse_value(U &value, It &&value_begin, + It &&value_end) { if (static_cast(std::distance(value_begin, value_end)) != 1) IGUANA_UNLIKELY { throw std::runtime_error("Expected one character"); } value = *value_begin; } template , int> = 0> -IGUANA_INLINE void parse_value(U &value, It &&value_begin, It &&value_end) { +IGUANA_INLINE void yaml_parse_value(U &value, It &&value_begin, + It &&value_end) { static constexpr auto str_to_enum = get_enum_map>(); if constexpr (bool_v) { // not defined a specialization template using T = std::underlying_type_t>; - parse_value(reinterpret_cast(value), value_begin, value_end); + yaml_parse_value(reinterpret_cast(value), value_begin, value_end); } else { auto enum_names = std::string_view( @@ -181,7 +206,8 @@ IGUANA_INLINE void parse_value(U &value, It &&value_begin, It &&value_end) { } template , int> = 0> -IGUANA_INLINE void parse_value(U &&value, It &&value_begin, It &&value_end) { +IGUANA_INLINE void yaml_parse_value(U &&value, It &&value_begin, + It &&value_end) { auto bool_v = std::string_view( &*value_begin, static_cast(std::distance(value_begin, value_end))); @@ -196,12 +222,14 @@ IGUANA_INLINE void parse_value(U &&value, It &&value_begin, It &&value_end) { } template , int> = 0> -IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, size_t min_spaces) { +IGUANA_INLINE void yaml_parse_item(U &value, It &&it, It &&end, + size_t min_spaces) { from_yaml(value, it, end, min_spaces); } template , int> = 0> -IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, size_t min_spaces) { +IGUANA_INLINE void yaml_parse_item(U &value, It &&it, It &&end, + size_t min_spaces) { using T = std::decay_t; if constexpr (string_v) { if (skip_space_till_end(it, end)) @@ -224,27 +252,36 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, size_t min_spaces) { skip_space_and_lines(it, end, min_spaces); auto start = it; auto value_end = skip_till_newline(it, end); - parse_value(value, start, value_end); + yaml_parse_value(value, start, value_end); } } else { skip_space_and_lines(it, end, min_spaces); auto start = it; auto value_end = skip_till_newline(it, end); - parse_value(value, start, value_end); + yaml_parse_value(value, start, value_end); } } +template , int> = 0> +IGUANA_INLINE void yaml_parse_item(U &value, It &&it, It &&end, + size_t min_spaces) { + yaml_parse_item(value.val, it, end, min_spaces); +} + template , int> = 0> -IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, size_t min_spaces); +IGUANA_INLINE void yaml_parse_item(U &value, It &&it, It &&end, + size_t min_spaces); template , int> = 0> -IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, size_t min_spaces); +IGUANA_INLINE void yaml_parse_item(U &value, It &&it, It &&end, + size_t min_spaces); // minspaces : The minimum indentation template , int> = 0> -IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, size_t min_spaces) { +IGUANA_INLINE void yaml_parse_item(U &value, It &&it, It &&end, + size_t min_spaces) { value.clear(); auto spaces = skip_space_and_lines(it, end, min_spaces); using value_type = typename std::remove_cv_t::value_type; @@ -260,12 +297,12 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, size_t min_spaces) { if constexpr (plain_v) { auto start = it; auto value_end = yaml_skip_till<',', ']'>(it, end); - parse_value(value.emplace_back(), start, value_end); + yaml_parse_value(value.emplace_back(), start, value_end); if (*(it - 1) == ']') IGUANA_UNLIKELY { return; } } else { - parse_item(value.emplace_back(), it, end, spaces + 1); + yaml_parse_item(value.emplace_back(), it, end, spaces + 1); skip_space_and_lines(it, end, min_spaces); if (*it == ',') IGUANA_LIKELY { ++it; } @@ -289,15 +326,15 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, size_t min_spaces) { subspaces = skip_space_and_lines(it, end, spaces + 1); if constexpr (string_v) { // except string_v because of scalar blocks - parse_item(value.emplace_back(), it, end, spaces + 1); + yaml_parse_item(value.emplace_back(), it, end, spaces + 1); } else if constexpr (plain_v) { auto start = it; auto value_end = skip_till_newline(it, end); - parse_value(value.emplace_back(), start, value_end); + yaml_parse_value(value.emplace_back(), start, value_end); } else { - parse_item(value.emplace_back(), it, end, subspaces); + yaml_parse_item(value.emplace_back(), it, end, subspaces); } } } @@ -306,7 +343,8 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, size_t min_spaces) { } template , int> = 0> -IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, size_t min_spaces) { +IGUANA_INLINE void yaml_parse_item(U &value, It &&it, It &&end, + size_t min_spaces) { auto spaces = skip_space_and_lines(it, end, min_spaces); if (*it == '[') { ++it; @@ -317,10 +355,10 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, size_t min_spaces) { if constexpr (plain_v) { auto start = it; auto value_end = yaml_skip_till<',', ']'>(it, end); - parse_value(v, start, value_end); + yaml_parse_value(v, start, value_end); } else { - parse_item(v, it, end, spaces + 1); + yaml_parse_item(v, it, end, spaces + 1); skip_space_and_lines(it, end, min_spaces); ++it; // skip , } @@ -337,15 +375,15 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, size_t min_spaces) { [[maybe_unused]] auto subspaces = skip_space_and_lines(it, end, spaces + 1); if constexpr (string_v) { - parse_item(v, it, end, spaces + 1); + yaml_parse_item(v, it, end, spaces + 1); } else if constexpr (plain_v) { auto start = it; auto value_end = skip_till_newline(it, end); - parse_value(v, start, value_end); + yaml_parse_value(v, start, value_end); } else { - parse_item(v, it, end, subspaces); + yaml_parse_item(v, it, end, subspaces); } }); } @@ -355,7 +393,8 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, size_t min_spaces) { } template , int>> -IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, size_t min_spaces) { +IGUANA_INLINE void yaml_parse_item(U &value, It &&it, It &&end, + size_t min_spaces) { using T = std::remove_reference_t; using key_type = typename T::key_type; using value_type = typename T::mapped_type; @@ -372,17 +411,17 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, size_t min_spaces) { auto start = it; auto value_end = yaml_skip_till<':'>(it, end); key_type key; - parse_value(key, start, value_end); + yaml_parse_value(key, start, value_end); subspaces = skip_space_and_lines(it, end, min_spaces); if constexpr (plain_v) { start = it; value_end = yaml_skip_till<',', '}'>(it, end); - parse_value(value[key], start, value_end); + yaml_parse_value(value[key], start, value_end); if (*(it - 1) == '}') IGUANA_UNLIKELY { return; } } else { - parse_item(value[key], it, end, min_spaces); + yaml_parse_item(value[key], it, end, min_spaces); subspaces = skip_space_and_lines(it, end, min_spaces); if (*it == ',') IGUANA_LIKELY { ++it; } @@ -401,15 +440,15 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, size_t min_spaces) { auto start = it; auto value_end = yaml_skip_till<':'>(it, end); key_type key; - parse_value(key, start, value_end); + yaml_parse_value(key, start, value_end); subspaces = skip_space_and_lines(it, end, min_spaces); if constexpr (plain_v && !string_v) { start = it; value_end = skip_till_newline(it, end); - parse_value(value[key], start, value_end); + yaml_parse_value(value[key], start, value_end); } else { - parse_item(value[key], it, end, spaces + 1); + yaml_parse_item(value[key], it, end, spaces + 1); } subspaces = skip_space_and_lines(it, end, min_spaces); } @@ -417,7 +456,8 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, size_t min_spaces) { } template , int>> -IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, size_t min_spaces) { +IGUANA_INLINE void yaml_parse_item(U &value, It &&it, It &&end, + size_t min_spaces) { using T = std::remove_reference_t; if constexpr (unique_ptr_v) { value = std::make_unique(); @@ -427,11 +467,12 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, size_t min_spaces) { } static_assert(!string_v, "smart_ptr is not allowed"); - parse_item(*value, it, end, min_spaces); + yaml_parse_item(*value, it, end, min_spaces); } template , int>> -IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, size_t min_spaces) { +IGUANA_INLINE void yaml_parse_item(U &value, It &&it, It &&end, + size_t min_spaces) { using T = std::remove_reference_t; using value_type = typename T::value_type; auto spaces = skip_space_and_lines(it, end, min_spaces); @@ -454,7 +495,7 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, size_t min_spaces) { } if constexpr (string_v || !plain_v) { it = start; - parse_item(value.emplace(), it, end, min_spaces); + yaml_parse_item(value.emplace(), it, end, min_spaces); } else { if (value_end == end) @@ -462,7 +503,7 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, size_t min_spaces) { // if value_end isn't touched value_end = skip_till_newline(it, end); } - parse_value(value.emplace(), start, value_end); + yaml_parse_value(value.emplace(), start, value_end); } } @@ -506,7 +547,8 @@ IGUANA_INLINE void from_yaml(T &value, It &&it, It &&end, size_t min_spaces) { [&](auto &&member_ptr) IGUANA__INLINE_LAMBDA { using V = std::decay_t; if constexpr (std::is_member_pointer_v) { - detail::parse_item(value.*member_ptr, it, end, spaces + 1); + detail::yaml_parse_item(value.*member_ptr, it, end, + spaces + 1); } else { static_assert(!sizeof(V), "type not supported"); @@ -535,7 +577,7 @@ IGUANA_INLINE void from_yaml(T &value, It &&it, It &&end, size_t min_spaces) { template , int> = 0> IGUANA_INLINE void from_yaml(T &value, It &&it, It &&end) { - detail::parse_item(value, it, end, 0); + detail::yaml_parse_item(value, it, end, 0); } template @@ -567,4 +609,10 @@ IGUANA_INLINE void from_yaml(T &value, const View &view, } } +template +IGUANA_INLINE void from_yaml_adl(iguana_adl_t *p, T &t, + std::string_view pb_str) { + iguana::from_yaml(t, pb_str); +} + } // namespace iguana diff --git a/iguana/yaml_util.hpp b/iguana/yaml_util.hpp index b1b93a6a..920a9918 100644 --- a/iguana/yaml_util.hpp +++ b/iguana/yaml_util.hpp @@ -4,6 +4,10 @@ #include "util.hpp" namespace iguana { + +template +constexpr inline bool yaml_not_support_v = variant_v; + // return true when it==end template IGUANA_INLINE bool skip_space_till_end(It &&it, It &&end) { diff --git a/iguana/yaml_writer.hpp b/iguana/yaml_writer.hpp index a0794f2c..1feed6d4 100644 --- a/iguana/yaml_writer.hpp +++ b/iguana/yaml_writer.hpp @@ -5,6 +5,12 @@ namespace iguana { +template , int> = 0> +IGUANA_INLINE void render_yaml_value(Stream &ss, T &&t, size_t min_spaces = 0) { + throw std::bad_function_call(); +} + template , int> = 0> IGUANA_INLINE void to_yaml(T &&t, Stream &s, size_t min_spaces = 0); @@ -41,6 +47,12 @@ IGUANA_INLINE void render_yaml_value(Stream &ss, T value, size_t min_spaces) { ss.push_back('\n'); } +template , int> = 0> +IGUANA_INLINE void render_yaml_value(Stream &ss, T value, size_t min_spaces) { + render_yaml_value(ss, value.val, min_spaces); +} + template IGUANA_INLINE void render_yaml_value(Stream &ss, char value, size_t min_spaces) { @@ -191,4 +203,9 @@ IGUANA_INLINE void to_yaml(T &&t, Stream &s) { static_assert(!sizeof(T), "don't suppport this type"); } +template +IGUANA_INLINE void to_yaml_adl(iguana_adl_t *p, const T &t, + std::string &pb_str) { + to_yaml(t, pb_str); +} } // namespace iguana diff --git a/test/test_pb.cpp b/test/test_pb.cpp index 1e06a492..5e919fa8 100644 --- a/test/test_pb.cpp +++ b/test/test_pb.cpp @@ -295,6 +295,16 @@ TEST_CASE("test reflection") { std::cout << s.x << " " << s.y << "\n"; CHECK(st->x == s.x); CHECK(st->y == s.y); + + std::string yaml; + t->to_yaml(yaml); + std::cout << yaml << "\n"; + + s = {}; + s.from_yaml(yaml); + std::cout << s.x << " " << s.y << "\n"; + CHECK(st->x == s.x); + CHECK(st->y == s.y); } auto t = iguana::create_instance("numer_st"); t->set_field_value("a", true); From 03000d4ba8a0a1878df390252d7e6d35cbb1eb73 Mon Sep 17 00:00:00 2001 From: bbgan <2893129936@qq.com> Date: Fri, 21 Jun 2024 22:09:46 +0800 Subject: [PATCH 4/4] add ENABLE_FLAG for dynamic reflection --- iguana/dynamic.hpp | 64 +++++++++++++++++++++++++++++++++++------ lang/struct_pb_intro.md | 2 +- test/test_pb.cpp | 2 +- 3 files changed, 57 insertions(+), 11 deletions(-) diff --git a/iguana/dynamic.hpp b/iguana/dynamic.hpp index 98fccdd1..5bdc43be 100644 --- a/iguana/dynamic.hpp +++ b/iguana/dynamic.hpp @@ -9,38 +9,84 @@ IGUANA_INLINE constexpr size_t member_offset(T* t, U T::*member) { return (char*)&(t->*member) - (char*)t; } -template +constexpr inline uint8_t ENABLE_JSON = 0x01; +constexpr inline uint8_t ENABLE_YAML = 0x02; +constexpr inline uint8_t ENABLE_XML = 0x04; +constexpr inline uint8_t ENABLE_PB = 0x08; +constexpr inline uint8_t ENABLE_ALL = 0x0F; + +template struct base_impl : public base { void to_pb(std::string& str) override { - to_pb_adl((iguana_adl_t*)nullptr, *(static_cast(this)), str); + if constexpr (ENABLE_FLAG & ENABLE_PB) { + to_pb_adl((iguana_adl_t*)nullptr, *(static_cast(this)), str); + } + else { + throw std::runtime_error("Protobuf Disabled"); + } } void from_pb(std::string_view str) override { - from_pb_adl((iguana_adl_t*)nullptr, *(static_cast(this)), str); + if constexpr (ENABLE_FLAG & ENABLE_PB) { + from_pb_adl((iguana_adl_t*)nullptr, *(static_cast(this)), str); + } + else { + throw std::runtime_error("Protobuf Disabled"); + } } void to_json(std::string& str) override { - to_json_adl((iguana_adl_t*)nullptr, *(static_cast(this)), str); + if constexpr (ENABLE_FLAG & ENABLE_JSON) { + to_json_adl((iguana_adl_t*)nullptr, *(static_cast(this)), str); + } + else { + throw std::runtime_error("Json Disabled"); + } } void from_json(std::string_view str) override { - from_json_adl((iguana_adl_t*)nullptr, *(static_cast(this)), str); + if constexpr (ENABLE_FLAG & ENABLE_JSON) { + from_json_adl((iguana_adl_t*)nullptr, *(static_cast(this)), str); + } + else { + throw std::runtime_error("Json Disabled"); + } } void to_xml(std::string& str) override { - to_xml_adl((iguana_adl_t*)nullptr, *(static_cast(this)), str); + if constexpr (ENABLE_FLAG & ENABLE_XML) { + to_xml_adl((iguana_adl_t*)nullptr, *(static_cast(this)), str); + } + else { + throw std::runtime_error("Xml Disabled"); + } } void from_xml(std::string_view str) override { - from_xml_adl((iguana_adl_t*)nullptr, *(static_cast(this)), str); + if constexpr (ENABLE_FLAG & ENABLE_XML) { + from_xml_adl((iguana_adl_t*)nullptr, *(static_cast(this)), str); + } + else { + throw std::runtime_error("Xml Disabled"); + } } void to_yaml(std::string& str) override { - to_yaml_adl((iguana_adl_t*)nullptr, *(static_cast(this)), str); + if constexpr (ENABLE_FLAG & ENABLE_YAML) { + to_yaml_adl((iguana_adl_t*)nullptr, *(static_cast(this)), str); + } + else { + throw std::runtime_error("Yaml Disabled"); + } } void from_yaml(std::string_view str) override { - from_yaml_adl((iguana_adl_t*)nullptr, *(static_cast(this)), str); + if constexpr (ENABLE_FLAG & ENABLE_YAML) { + from_yaml_adl((iguana_adl_t*)nullptr, *(static_cast(this)), str); + } + else { + throw std::runtime_error("Yaml Disabled"); + } } iguana::detail::field_info get_field_info(std::string_view name) override { diff --git a/lang/struct_pb_intro.md b/lang/struct_pb_intro.md index 233d8bbf..a8aa637d 100644 --- a/lang/struct_pb_intro.md +++ b/lang/struct_pb_intro.md @@ -68,7 +68,7 @@ struct my_struct { }; REFLECTION(my_struct, x, y, z); -struct nest1 : public iguana::base_imple { +struct nest1 : public iguana::base_impl { nest1() = default; nest1(std::string s, my_struct t, int d) : name(std::move(s)), value(t), var(d) {} diff --git a/test/test_pb.cpp b/test/test_pb.cpp index 5e919fa8..be29cfd5 100644 --- a/test/test_pb.cpp +++ b/test/test_pb.cpp @@ -103,7 +103,7 @@ struct test_pb_st6 { }; REFLECTION(test_pb_st6, x, y); -struct pair_t PUBLIC(pair_t) { +struct pair_t : public iguana::base_impl { pair_t() = default; pair_t(int a, int b) : x(a), y(b) {} int x;