From bddd33270d2cadea1ba68661aab67b18b9173ceb Mon Sep 17 00:00:00 2001 From: Zhongxian Li Date: Thu, 14 Nov 2024 15:15:15 +0800 Subject: [PATCH 1/2] aggregate to yaml and refactor yaml_writer --- iguana/yaml_util.hpp | 2 + iguana/yaml_writer.hpp | 192 ++++++++++++++++++----------------------- test/test_yaml.cpp | 17 ++++ 3 files changed, 105 insertions(+), 106 deletions(-) diff --git a/iguana/yaml_util.hpp b/iguana/yaml_util.hpp index 920a9918..96ba881a 100644 --- a/iguana/yaml_util.hpp +++ b/iguana/yaml_util.hpp @@ -1,7 +1,9 @@ #pragma once #include "detail/pb_type.hpp" +#include "ylt/reflection/template_string.hpp" #include "util.hpp" +#include "ylt/reflection/member_names.hpp" namespace iguana { diff --git a/iguana/yaml_writer.hpp b/iguana/yaml_writer.hpp index 1feed6d4..edfd2c86 100644 --- a/iguana/yaml_writer.hpp +++ b/iguana/yaml_writer.hpp @@ -4,86 +4,59 @@ #include "yaml_util.hpp" 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); - template , int> = 0> -IGUANA_INLINE void render_yaml_value(Stream &ss, T &&t, size_t min_spaces) { - ss.push_back('\n'); - to_yaml(std::forward(t), ss, min_spaces); -} - -template , int> = 0> -IGUANA_INLINE void render_yaml_value(Stream &ss, T &&t, size_t min_spaces) { + std::enable_if_t, int> = 0> +IGUANA_INLINE void render_yaml_value(Stream &ss, T &&t, char c = '\n') { if constexpr (Is_writing_escape) { ss.push_back('"'); write_string_with_escape(t.data(), t.size(), ss); ss.push_back('"'); - } - else { + } else { ss.append(t.data(), t.size()); } - if constexpr (appendLf) - ss.push_back('\n'); + ss.push_back(c); } -template , int> = 0> -IGUANA_INLINE void render_yaml_value(Stream &ss, T value, size_t min_spaces) { +template , int> = 0> +IGUANA_INLINE void render_yaml_value(Stream &ss, T value, char c = '\n') { char temp[65]; auto p = detail::to_chars(temp, value); ss.append(temp, p - temp); - if constexpr (appendLf) - ss.push_back('\n'); + ss.push_back(c); } -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 , int> = 0> +IGUANA_INLINE void render_yaml_value(Stream &ss, T value, char c = '\n') { + render_yaml_value(ss, value.val, c); } -template -IGUANA_INLINE void render_yaml_value(Stream &ss, char value, - size_t min_spaces) { +template +IGUANA_INLINE void render_yaml_value(Stream &ss, char value, char c = '\n') { ss.push_back(value); - if constexpr (appendLf) - ss.push_back('\n'); + ss.push_back(c); } -template -IGUANA_INLINE void render_yaml_value(Stream &ss, bool value, - size_t min_spaces) { +template +IGUANA_INLINE void render_yaml_value(Stream &ss, bool value, char c = '\n') { ss.append(value ? "true" : "false"); - if constexpr (appendLf) - ss.push_back('\n'); + ss.push_back(c); } -template , int> = 0> -IGUANA_INLINE void render_yaml_value(Stream &ss, T value, size_t min_spaces) { +template , int> = 0> +IGUANA_INLINE void render_yaml_value(Stream &ss, T value, char c = '\n') { static constexpr auto enum_to_str = get_enum_map>(); if constexpr (bool_v) { render_yaml_value( - ss, static_cast>(value), min_spaces); - } - else { + ss, static_cast>(value), c); + } else { auto it = enum_to_str.find(value); - if (it != enum_to_str.end()) - IGUANA_LIKELY { + if (it != enum_to_str.end()) IGUANA_LIKELY { auto str = it->second; render_yaml_value( - ss, std::string_view(str.data(), str.size()), min_spaces); + ss, std::string_view(str.data(), str.size()), c); } else { throw std::runtime_error( @@ -93,114 +66,121 @@ IGUANA_INLINE void render_yaml_value(Stream &ss, T value, size_t min_spaces) { } } -template , int> = 0> -IGUANA_INLINE void render_yaml_value(Stream &ss, const T &val, - size_t min_spaces); - -template , int> = 0> -IGUANA_INLINE void render_yaml_value(Stream &ss, const T &val, - size_t min_spaces); +template +IGUANA_INLINE void to_yaml(T &&t, Stream &s, size_t min_spaces = 0); template , int> = 0> -IGUANA_INLINE void render_yaml_value(Stream &ss, const T &t, - size_t min_spaces) { +IGUANA_INLINE void render_yaml_wrapper(Stream &ss, const T &t, + size_t min_spaces) { ss.push_back('\n'); for (const auto &v : t) { ss.append(min_spaces, ' '); ss.append("- "); - render_yaml_value(ss, v, min_spaces + 1); + to_yaml(v, ss, min_spaces + 1); } } template , int> = 0> -IGUANA_INLINE void render_yaml_value(Stream &ss, T &&t, size_t min_spaces) { +IGUANA_INLINE void render_yaml_wrapper(Stream &ss, T &&t, size_t min_spaces) { ss.push_back('\n'); for_each(std::forward(t), [&ss, min_spaces](auto &v, auto i) IGUANA__INLINE_LAMBDA { ss.append(min_spaces, ' '); ss.append("- "); - render_yaml_value(ss, v, min_spaces + 1); + to_yaml(v, ss, min_spaces + 1); }); } +template +IGUANA_INLINE void render_key_value(T &&t, Stream &s, size_t min_spaces, + U &&name) { + s.append(min_spaces, ' '); + render_yaml_value(s, name, ':'); // key must be plaint type + s.append(" "); + to_yaml(t, s, min_spaces + 1); +} + template , int> = 0> -IGUANA_INLINE void render_yaml_value(Stream &ss, const T &t, - size_t min_spaces) { +IGUANA_INLINE void render_yaml_wrapper(Stream &ss, const T &t, + size_t min_spaces) { ss.push_back('\n'); for (const auto &[k, v] : t) { - ss.append(min_spaces, ' '); - render_yaml_value(ss, k, 0); // key must be plaint type - ss.append(": "); - render_yaml_value(ss, v, min_spaces + 1); + render_key_value(v, ss, min_spaces, k); } } template , int>> -IGUANA_INLINE void render_yaml_value(Stream &ss, const T &val, - size_t min_spaces) { + std::enable_if_t, int> = 0> +IGUANA_INLINE void render_yaml_wrapper(Stream &ss, const T &val, + size_t min_spaces) { if (!val) { ss.append("null"); ss.push_back('\n'); - } - else { - render_yaml_value(ss, *val, min_spaces); + } else { + to_yaml(*val, ss, min_spaces); } } template , int>> -IGUANA_INLINE void render_yaml_value(Stream &ss, const T &val, - size_t min_spaces) { + std::enable_if_t, int> = 0> +IGUANA_INLINE void render_yaml_wrapper(Stream &ss, const T &val, + size_t min_spaces) { if (!val) { ss.push_back('\n'); - } - else { - render_yaml_value(ss, *val, min_spaces); + } else { + to_yaml(*val, ss, min_spaces); } } -constexpr auto write_yaml_key = [](auto &s, auto i, - auto &t) IGUANA__INLINE_LAMBDA { - constexpr auto name = get_name(); - s.append(name.data(), name.size()); -}; +template > && + non_refletable_v, int> = 0> +IGUANA_INLINE void render_yaml_struct(Stream &s, T &&t, size_t min_spaces) { + s.push_back('\n'); + using U = std::remove_cvref_t; + constexpr size_t Count = ylt::reflection::members_count_v; + auto tp = ylt::reflection::object_to_tuple(t); + static constexpr auto arr = ylt::reflection::get_member_names(); + + [&](std::index_sequence) mutable { + (render_key_value(std::get(tp), s, min_spaces, + arr[Is]), + ...); + }(std::make_index_sequence{}); +} template , int>> -IGUANA_INLINE void to_yaml(T &&t, Stream &s, size_t min_spaces) { + std::enable_if_t, int> = 0> +IGUANA_INLINE void render_yaml_struct(Stream &s, T &&t, size_t min_spaces) { + s.push_back('\n'); for_each(std::forward(t), [&t, &s, min_spaces](const auto &v, auto i) IGUANA__INLINE_LAMBDA { using M = decltype(iguana_reflect_type(std::forward(t))); constexpr auto Idx = decltype(i)::value; constexpr auto Count = M::value(); static_assert(Idx < Count); - s.append(min_spaces, ' '); - write_yaml_key(s, i, t); - s.append(": "); - if constexpr (!is_reflection>::value) { - render_yaml_value(s, t.*v, min_spaces + 1); - } - else { - s.push_back('\n'); - to_yaml(t.*v, s, min_spaces + 1); - } + [[maybe_unused]] constexpr std::string_view tag_name = + std::string_view(get_name, Idx>().data(), + get_name, Idx>().size()); + render_key_value(t.*v, s, min_spaces, tag_name); }); } -template , int> = 0> -IGUANA_INLINE void to_yaml(T &&t, Stream &s) { +template +IGUANA_INLINE void to_yaml(T &&t, Stream &s, size_t min_spaces) { if constexpr (tuple_v || map_container_v || sequence_container_v || optional_v || smart_ptr_v) - render_yaml_value(s, std::forward(t), 0); - else + render_yaml_wrapper(s, std::forward(t), min_spaces); + else if constexpr (refletable_v || + std::is_aggregate_v>) + render_yaml_struct(s, std::forward(t), min_spaces); + else if constexpr (yaml_not_support_v) static_assert(!sizeof(T), "don't suppport this type"); + else + render_yaml_value(s, t); } template diff --git a/test/test_yaml.cpp b/test/test_yaml.cpp index 80832b58..c99a8f27 100644 --- a/test/test_yaml.cpp +++ b/test/test_yaml.cpp @@ -146,6 +146,23 @@ price: 20 # this is price validator(*op_p2); } +struct my_optional_t { + int a; + std::optional b; + std::optional c; + bool d; + char e; +}; + +TEST_CASE("test aggregate reflect") { + my_optional_t op{1, 2, {}, 0, 'o'}; + + static_assert(std::is_aggregate_v, "err"); + std::string ss; + iguana::to_yaml(op, ss); + std::cout << ss << "\n"; +} + TEST_CASE("test optional") { std::string str = R"()"; std::optional opt; From 56abc4b04c668a93cfcd9f1b098ab41ad808eb01 Mon Sep 17 00:00:00 2001 From: Zhongxian Li Date: Mon, 25 Nov 2024 11:07:03 +0800 Subject: [PATCH 2/2] rename --- iguana/yaml_writer.hpp | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/iguana/yaml_writer.hpp b/iguana/yaml_writer.hpp index edfd2c86..0270c0e2 100644 --- a/iguana/yaml_writer.hpp +++ b/iguana/yaml_writer.hpp @@ -71,7 +71,7 @@ IGUANA_INLINE void to_yaml(T &&t, Stream &s, size_t min_spaces = 0); template , int> = 0> -IGUANA_INLINE void render_yaml_wrapper(Stream &ss, const T &t, +IGUANA_INLINE void render_yaml_value(Stream &ss, const T &t, size_t min_spaces) { ss.push_back('\n'); for (const auto &v : t) { @@ -83,7 +83,7 @@ IGUANA_INLINE void render_yaml_wrapper(Stream &ss, const T &t, template , int> = 0> -IGUANA_INLINE void render_yaml_wrapper(Stream &ss, T &&t, size_t min_spaces) { +IGUANA_INLINE void render_yaml_value(Stream &ss, T &&t, size_t min_spaces) { ss.push_back('\n'); for_each(std::forward(t), [&ss, min_spaces](auto &v, auto i) IGUANA__INLINE_LAMBDA { @@ -104,7 +104,7 @@ IGUANA_INLINE void render_key_value(T &&t, Stream &s, size_t min_spaces, template , int> = 0> -IGUANA_INLINE void render_yaml_wrapper(Stream &ss, const T &t, +IGUANA_INLINE void render_yaml_value(Stream &ss, const T &t, size_t min_spaces) { ss.push_back('\n'); for (const auto &[k, v] : t) { @@ -114,7 +114,7 @@ IGUANA_INLINE void render_yaml_wrapper(Stream &ss, const T &t, template , int> = 0> -IGUANA_INLINE void render_yaml_wrapper(Stream &ss, const T &val, +IGUANA_INLINE void render_yaml_value(Stream &ss, const T &val, size_t min_spaces) { if (!val) { ss.append("null"); @@ -126,7 +126,7 @@ IGUANA_INLINE void render_yaml_wrapper(Stream &ss, const T &val, template , int> = 0> -IGUANA_INLINE void render_yaml_wrapper(Stream &ss, const T &val, +IGUANA_INLINE void render_yaml_value(Stream &ss, const T &val, size_t min_spaces) { if (!val) { ss.push_back('\n'); @@ -138,7 +138,7 @@ IGUANA_INLINE void render_yaml_wrapper(Stream &ss, const T &val, template > && non_refletable_v, int> = 0> -IGUANA_INLINE void render_yaml_struct(Stream &s, T &&t, size_t min_spaces) { +IGUANA_INLINE void render_yaml_value(Stream &s, T &&t, size_t min_spaces) { s.push_back('\n'); using U = std::remove_cvref_t; constexpr size_t Count = ylt::reflection::members_count_v; @@ -154,7 +154,7 @@ IGUANA_INLINE void render_yaml_struct(Stream &s, T &&t, size_t min_spaces) { template , int> = 0> -IGUANA_INLINE void render_yaml_struct(Stream &s, T &&t, size_t min_spaces) { +IGUANA_INLINE void render_yaml_value(Stream &s, T &&t, size_t min_spaces) { s.push_back('\n'); for_each(std::forward(t), [&t, &s, min_spaces](const auto &v, auto i) IGUANA__INLINE_LAMBDA { @@ -172,11 +172,9 @@ IGUANA_INLINE void render_yaml_struct(Stream &s, T &&t, size_t min_spaces) { template IGUANA_INLINE void to_yaml(T &&t, Stream &s, size_t min_spaces) { if constexpr (tuple_v || map_container_v || sequence_container_v || - optional_v || smart_ptr_v) - render_yaml_wrapper(s, std::forward(t), min_spaces); - else if constexpr (refletable_v || - std::is_aggregate_v>) - render_yaml_struct(s, std::forward(t), min_spaces); + optional_v || smart_ptr_v || refletable_v || + std::is_aggregate_v>) + render_yaml_value(s, std::forward(t), min_spaces); else if constexpr (yaml_not_support_v) static_assert(!sizeof(T), "don't suppport this type"); else