From db24eb199431341d2a32a3dbcf4ca5b2406f539c Mon Sep 17 00:00:00 2001 From: twomice Date: Tue, 12 Nov 2024 20:20:09 -0500 Subject: [PATCH] Enable writing to force_opt lens with non-opt value. --- lager/lenses/optional.hpp | 19 ++++++++++++++++--- test/lenses.cpp | 22 ++++++++++++++++++---- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/lager/lenses/optional.hpp b/lager/lenses/optional.hpp index c4f4f28f..fda878fd 100644 --- a/lager/lenses/optional.hpp +++ b/lager/lenses/optional.hpp @@ -70,6 +70,14 @@ struct add_opt using type = std::optional>; }; +template +struct is_optional : std::false_type +{}; + +template +struct is_optional> : std::true_type +{}; + } // namespace detail //! @defgroup lenses @@ -110,7 +118,7 @@ auto value_or(T&& t) { return zug::comp([t = std::forward(t)](auto&& f) { return [&, f = LAGER_FWD(f)](auto&& whole) { - return f(LAGER_FWD(whole).value_or(std::move(t)))( + return f(LAGER_FWD(whole).value_or(t))( [&](auto&& x) { return LAGER_FWD(x); }); }; }); @@ -141,8 +149,13 @@ ZUG_INLINE_CONSTEXPR auto or_default = value_or(); ZUG_INLINE_CONSTEXPR auto force_opt = zug::comp([](auto&& f) { return [f = LAGER_FWD(f)](auto&& p) { using opt_t = std::optional>; - return f(opt_t{LAGER_FWD(p)})( - [&](auto&& x) { return LAGER_FWD(x).value_or(LAGER_FWD(p)); }); + auto opt = opt_t{LAGER_FWD(p)}; + return f(std::move(opt))([&](auto&& x) -> decltype(auto) { + if constexpr (detail::is_optional>::value) + return LAGER_FWD(x).value_or(*std::move(opt)); + else + return LAGER_FWD(x); + }); }; }); diff --git a/test/lenses.cpp b/test/lenses.cpp index 8b159f87..d00ad0fc 100644 --- a/test/lenses.cpp +++ b/test/lenses.cpp @@ -21,8 +21,8 @@ #include #include #include -#include #include +#include #include @@ -423,6 +423,21 @@ TEST_CASE("lenses, bind_opt") } } + +TEST_CASE("lenses::force_opt with bind_opt", "[lenses][force_opt][bind_opt]") +{ + auto opt_member_lens = attr(&yearday::day) | force_opt; + auto bound_opt_member = bind_opt(opt_member_lens); + + CHECK(view(bound_opt_member, std::optional{yearday{1, 1}}) == + std::optional{1}); + CHECK(view(bound_opt_member, std::optional{}) == std::nullopt); + CHECK(set(bound_opt_member, std::optional{yearday{1, 1}}, 1)->day == 1); + CHECK(set(bound_opt_member, std::optional{yearday{1, 1}}, std::optional{1}) + ->day == 1); + CHECK(!set(bound_opt_member, std::optional{}, std::nullopt)); +} + TEST_CASE("lenses::zip pair", "[lenses][zip][pair]") { struct foo @@ -433,9 +448,8 @@ TEST_CASE("lenses::zip pair", "[lenses][zip][pair]") std::pair baz{{42}, 256}; auto zipped = zip(attr(&foo::value), lager::identity); - baz = over(zipped, baz, [](auto x) { - return std::pair{x.second, x.first}; - }); + baz = + over(zipped, baz, [](auto x) { return std::pair{x.second, x.first}; }); CHECK(baz.first.value == 256); CHECK(baz.second == 42);