From 716de7b6fdce722f0a09d338349d968a39d5ae9e Mon Sep 17 00:00:00 2001 From: Manuel Bellersen Date: Fri, 8 Nov 2024 13:39:08 +0100 Subject: [PATCH] =?UTF-8?q?Emplace=20into=20optional=20to=20be=20able=20to?= =?UTF-8?q?=20visit=20variant=20containers=20containi=E2=80=A6=20(#234)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/rfl/TaggedUnion.hpp | 6 + include/rfl/Variant.hpp | 71 +++--------- .../call_destructors_where_necessary.hpp | 3 +- include/rfl/visit.hpp | 108 +++--------------- .../json/test_rfl_variant_visit_move_only.cpp | 25 +++- 5 files changed, 64 insertions(+), 149 deletions(-) diff --git a/include/rfl/TaggedUnion.hpp b/include/rfl/TaggedUnion.hpp index a512c88b..c5cc0963 100644 --- a/include/rfl/TaggedUnion.hpp +++ b/include/rfl/TaggedUnion.hpp @@ -113,6 +113,12 @@ struct TaggedUnion { VariantType variant_; }; +template +concept TaggedUnionBased = requires(T t) { + []( + TaggedUnion<_discriminator, Args...> const&) {}(t); +}; + template struct PossibleTags; diff --git a/include/rfl/Variant.hpp b/include/rfl/Variant.hpp index 59b12f7c..5b648281 100644 --- a/include/rfl/Variant.hpp +++ b/include/rfl/Variant.hpp @@ -2,7 +2,6 @@ #define RFL_VARIANT_HPP_ #include -#include #include #include #include @@ -14,7 +13,6 @@ #include "internal/nth_element_t.hpp" #include "internal/variant/find_max_size.hpp" #include "internal/variant/is_alternative_type.hpp" -#include "internal/variant/is_convertible_to.hpp" #include "internal/variant/result_t.hpp" namespace rfl { @@ -152,80 +150,40 @@ class Variant { } template - result_t visit(F& _f) { + result_t visit(F&& _f) { using ResultType = result_t; if constexpr (std::is_same_v) { bool visited = false; - do_visit_no_result(_f, &visited, + do_visit_no_result(std::forward(_f), &visited, std::make_integer_sequence()); } else if constexpr (std::is_reference_v) { std::remove_reference_t* res = nullptr; - do_visit_with_reference(_f, &res, + do_visit_with_reference(std::forward(_f), &res, std::make_integer_sequence()); return *res; } else { auto res = std::optional(); - do_visit_with_result(_f, &res, + do_visit_with_result(std::forward(_f), &res, std::make_integer_sequence()); return std::move(*res); } } template - result_t visit(F& _f) const { + result_t visit(F&& _f) const { using ResultType = result_t; if constexpr (std::is_same_v) { bool visited = false; - do_visit_no_result(_f, &visited, + do_visit_no_result(std::forward(_f), &visited, std::make_integer_sequence()); } else if constexpr (std::is_reference_v) { std::remove_reference_t* res = nullptr; - do_visit_with_reference(_f, &res, + do_visit_with_reference(std::forward(_f), &res, std::make_integer_sequence()); return *res; } else { auto res = std::optional(); - do_visit_with_result(_f, &res, - std::make_integer_sequence()); - return std::move(*res); - } - } - - template - result_t visit(const F& _f) { - using ResultType = std::remove_reference_t>; - if constexpr (std::is_same_v) { - bool visited = false; - do_visit_no_result(_f, &visited, - std::make_integer_sequence()); - } else if constexpr (std::is_reference_v) { - std::remove_reference_t* res = nullptr; - do_visit_with_reference(_f, &res, - std::make_integer_sequence()); - return *res; - } else { - auto res = std::optional(); - do_visit_with_result(_f, &res, - std::make_integer_sequence()); - return std::move(*res); - } - } - - template - result_t visit(const F& _f) const { - using ResultType = result_t; - if constexpr (std::is_same_v) { - bool visited = false; - do_visit_no_result(_f, &visited, - std::make_integer_sequence()); - } else if constexpr (std::is_reference_v) { - std::remove_reference_t* res = nullptr; - do_visit_with_reference(_f, &res, - std::make_integer_sequence()); - return *res; - } else { - auto res = std::optional(); - do_visit_with_result(_f, &res, + do_visit_with_result(std::forward(_f), &res, std::make_integer_sequence()); return std::move(*res); } @@ -330,7 +288,7 @@ class Variant { std::optional* _res, Index<_i>) { if (!*_res && index_ == _i) { - *_res = _f(get_alternative<_i>()); + _res->emplace(_f(get_alternative<_i>())); } }; (visit_one(_f, _res, Index<_is>{}), ...); @@ -343,7 +301,7 @@ class Variant { std::optional* _res, Index<_i>) { if (!*_res && index_ == _i) { - *_res = _f(get_alternative<_i>()); + _res->emplace(_f(get_alternative<_i>())); } }; (visit_one(_f, _res, Index<_is>{}), ...); @@ -356,7 +314,7 @@ class Variant { std::optional* _res, Index<_i>) { if (!*_res && index_ == _i) { - *_res = _f(get_alternative<_i>()); + _res->emplace(_f(get_alternative<_i>())); } }; (visit_one(_f, _res, Index<_is>{}), ...); @@ -369,7 +327,7 @@ class Variant { std::optional* _res, Index<_i>) { if (!*_res && index_ == _i) { - *_res = _f(get_alternative<_i>()); + _res->emplace(_f(get_alternative<_i>())); } }; (visit_one(_f, _res, Index<_is>{}), ...); @@ -460,6 +418,11 @@ class Variant { alignas(AlternativeTypes...) DataType data_; }; +template +concept VariantBased = requires(std::decay_t v) { + [](Variant const&) {}(v); +}; + template constexpr T* get_if(Variant* _v) noexcept { const auto get = [](auto& _v) -> T* { diff --git a/include/rfl/parsing/call_destructors_where_necessary.hpp b/include/rfl/parsing/call_destructors_where_necessary.hpp index 0ac07c57..3862afaf 100644 --- a/include/rfl/parsing/call_destructors_where_necessary.hpp +++ b/include/rfl/parsing/call_destructors_where_necessary.hpp @@ -49,8 +49,7 @@ void call_destructors_where_necessary(const std::array& _set, [&](std::integer_sequence) { (call_destructor_on_one_if_necessary(_set, _view), ...); - } - (std::make_integer_sequence()); + }(std::make_integer_sequence()); } } // namespace rfl::parsing diff --git a/include/rfl/visit.hpp b/include/rfl/visit.hpp index 2d98067d..86efc965 100644 --- a/include/rfl/visit.hpp +++ b/include/rfl/visit.hpp @@ -1,14 +1,13 @@ #ifndef RFL_VISIT_HPP_ #define RFL_VISIT_HPP_ -#include +#include #include "Literal.hpp" #include "TaggedUnion.hpp" #include "internal/StringLiteral.hpp" #include "internal/VisitTree.hpp" #include "internal/VisitorWrapper.hpp" -#include "internal/variant/result_t.hpp" namespace rfl { @@ -22,104 +21,29 @@ inline auto visit(const Visitor& _visitor, const Literal<_fields...> _literal, wrapper, _literal.value(), _args...); } -template -inline internal::variant::result_t visit( - F& _f, Variant& _v) { - return _v.visit(_f); +template +inline auto visit(F&& _f, V&& _v) + -> decltype(std::declval().visit(std::declval())) { + return std::forward(_v).visit(std::forward(_f)); } -template -inline internal::variant::result_t visit( - F& _f, Variant&& _v) { - return _v.visit(_f); -} - -template -inline internal::variant::result_t visit( - F& _f, const Variant& _v) { - return _v.visit(_f); -} - -template -inline internal::variant::result_t visit( - const F& _f, Variant& _v) { - return _v.visit(_f); -} - -template -inline internal::variant::result_t visit( - const F& _f, Variant&& _v) { - return _v.visit(_f); -} - -template -inline internal::variant::result_t visit( - const F& _f, const Variant& _v) { - return _v.visit(_f); -} - -template -inline internal::variant::result_t visit( - F& _f, TaggedUnion<_discriminator, AlternativeTypes...>& _tagged_union) { - return _tagged_union.variant().visit(_f); -} - -template -inline internal::variant::result_t visit( - F& _f, TaggedUnion<_discriminator, AlternativeTypes...>&& _tagged_union) { - return _tagged_union.variant().visit(_f); -} - -template -inline internal::variant::result_t visit( - F& _f, - const TaggedUnion<_discriminator, AlternativeTypes...>& _tagged_union) { - return _tagged_union.variant().visit(_f); -} - -template -inline internal::variant::result_t visit( - const F& _f, - TaggedUnion<_discriminator, AlternativeTypes...>& _tagged_union) { - return _tagged_union.variant().visit(_f); -} - -template -inline internal::variant::result_t visit( - const F& _f, - TaggedUnion<_discriminator, AlternativeTypes...>&& _tagged_union) { - return _tagged_union.variant().visit(_f); -} - -template -inline internal::variant::result_t visit( - const F& _f, - const TaggedUnion<_discriminator, AlternativeTypes...>& _tagged_union) { - return _tagged_union.variant().visit(_f); -} - -template -inline auto visit(F& _f, Head& _head, Tail&... _tail) { - const auto f_outer = [&](auto& _h) { - const auto f_inner = [&](auto&... _t) { return _f(_h, _t...); }; - return visit(f_inner, _tail...); - }; - return _head.visit(f_outer); +inline auto visit( + F&& _f, TaggedUnion<_discriminator, AlternativeTypes...>&& _tagged_union) + -> decltype(std::declval().variant().visit(std::declval())) { + return std::forward(_tagged_union).variant().visit(std::forward(_f)); } template -inline auto visit(const F& _f, Head& _head, Tail&... _tail) { +inline auto visit(F&& _f, Head&& _head, Tail&&... _tail) { const auto f_outer = [&](auto& _h) { - const auto f_inner = [&](auto&... _t) { return _f(_h, _t...); }; - return visit(f_inner, _tail...); + const auto f_inner = [&](auto&... _t) { + return std::forward(_f)(_h, _t...); + }; + return visit(f_inner, std::forward(_tail)...); }; - return _head.visit(f_outer); + return std::forward(_head).visit(f_outer); } } // namespace rfl diff --git a/tests/json/test_rfl_variant_visit_move_only.cpp b/tests/json/test_rfl_variant_visit_move_only.cpp index 5418ddec..1cc70f2e 100644 --- a/tests/json/test_rfl_variant_visit_move_only.cpp +++ b/tests/json/test_rfl_variant_visit_move_only.cpp @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -19,6 +18,10 @@ struct Square { std::unique_ptr width; }; +struct Circle { + double const radius; +}; + using Shapes = rfl::Variant; TEST(json, test_rfl_variant_visit_move_only) { @@ -29,4 +32,24 @@ TEST(json, test_rfl_variant_visit_move_only) { }; EXPECT_EQ(*rfl::visit(get_width, r), 5.0); } + +TEST(json, test_rfl_variant_visit_return_move_only_const) { + auto const circle = Circle{.radius = 10}; + auto const variant = rfl::Variant{circle}; + const auto get_radius = [](const auto& object) -> const double& { + return object.radius; + }; + auto const result = rfl::visit(get_radius, variant); + EXPECT_EQ(result, circle.radius); +} + +TEST(json, test_rfl_variant_visit_return_move_only) { + auto circle = Circle{.radius = 10}; + auto variant = rfl::Variant{circle}; + auto const get_radius = [](auto& object) -> double const& { + return object.radius; + }; + auto result = rfl::visit(get_radius, variant); + EXPECT_EQ(result, circle.radius); +} } // namespace test_rfl_variant_visit_move_only