Skip to content

Commit 4865197

Browse files
authored
Merge pull request #216 from Siapran/force_opt-fix
Enable writing to force_opt lens with non-opt value.
2 parents 338ed6b + db24eb1 commit 4865197

File tree

2 files changed

+34
-7
lines changed

2 files changed

+34
-7
lines changed

lager/lenses/optional.hpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,14 @@ struct add_opt
7070
using type = std::optional<std::decay_t<T>>;
7171
};
7272

73+
template <typename T>
74+
struct is_optional : std::false_type
75+
{};
76+
77+
template <typename T>
78+
struct is_optional<std::optional<T>> : std::true_type
79+
{};
80+
7381
} // namespace detail
7482

7583
//! @defgroup lenses
@@ -110,7 +118,7 @@ auto value_or(T&& t)
110118
{
111119
return zug::comp([t = std::forward<T>(t)](auto&& f) {
112120
return [&, f = LAGER_FWD(f)](auto&& whole) {
113-
return f(LAGER_FWD(whole).value_or(std::move(t)))(
121+
return f(LAGER_FWD(whole).value_or(t))(
114122
[&](auto&& x) { return LAGER_FWD(x); });
115123
};
116124
});
@@ -141,8 +149,13 @@ ZUG_INLINE_CONSTEXPR auto or_default = value_or();
141149
ZUG_INLINE_CONSTEXPR auto force_opt = zug::comp([](auto&& f) {
142150
return [f = LAGER_FWD(f)](auto&& p) {
143151
using opt_t = std::optional<std::decay_t<decltype(p)>>;
144-
return f(opt_t{LAGER_FWD(p)})(
145-
[&](auto&& x) { return LAGER_FWD(x).value_or(LAGER_FWD(p)); });
152+
auto opt = opt_t{LAGER_FWD(p)};
153+
return f(std::move(opt))([&](auto&& x) -> decltype(auto) {
154+
if constexpr (detail::is_optional<std::decay_t<decltype(x)>>::value)
155+
return LAGER_FWD(x).value_or(*std::move(opt));
156+
else
157+
return LAGER_FWD(x);
158+
});
146159
};
147160
});
148161

test/lenses.cpp

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121
#include <lager/lenses/at_or.hpp>
2222
#include <lager/lenses/attr.hpp>
2323
#include <lager/lenses/optional.hpp>
24-
#include <lager/lenses/variant.hpp>
2524
#include <lager/lenses/tuple.hpp>
25+
#include <lager/lenses/variant.hpp>
2626

2727
#include <array>
2828

@@ -423,6 +423,21 @@ TEST_CASE("lenses, bind_opt")
423423
}
424424
}
425425

426+
427+
TEST_CASE("lenses::force_opt with bind_opt", "[lenses][force_opt][bind_opt]")
428+
{
429+
auto opt_member_lens = attr(&yearday::day) | force_opt;
430+
auto bound_opt_member = bind_opt(opt_member_lens);
431+
432+
CHECK(view(bound_opt_member, std::optional{yearday{1, 1}}) ==
433+
std::optional{1});
434+
CHECK(view(bound_opt_member, std::optional<yearday>{}) == std::nullopt);
435+
CHECK(set(bound_opt_member, std::optional{yearday{1, 1}}, 1)->day == 1);
436+
CHECK(set(bound_opt_member, std::optional{yearday{1, 1}}, std::optional{1})
437+
->day == 1);
438+
CHECK(!set(bound_opt_member, std::optional<yearday>{}, std::nullopt));
439+
}
440+
426441
TEST_CASE("lenses::zip pair", "[lenses][zip][pair]")
427442
{
428443
struct foo
@@ -433,9 +448,8 @@ TEST_CASE("lenses::zip pair", "[lenses][zip][pair]")
433448
std::pair<foo, int> baz{{42}, 256};
434449
auto zipped = zip(attr(&foo::value), lager::identity);
435450

436-
baz = over(zipped, baz, [](auto x) {
437-
return std::pair{x.second, x.first};
438-
});
451+
baz =
452+
over(zipped, baz, [](auto x) { return std::pair{x.second, x.first}; });
439453

440454
CHECK(baz.first.value == 256);
441455
CHECK(baz.second == 42);

0 commit comments

Comments
 (0)