From 7e8e2ef0be2eebc7f872ea37620dc1b60d62197f Mon Sep 17 00:00:00 2001 From: Steven Le Rouzic Date: Sat, 2 Nov 2024 20:08:07 +0100 Subject: Add option::and_then --- asl/option.hpp | 37 +++++++++++++++++++++++++++++++++++-- asl/tests/option_tests.cpp | 31 ++++++++++++++++++++++++------- 2 files changed, 59 insertions(+), 9 deletions(-) (limited to 'asl') diff --git a/asl/option.hpp b/asl/option.hpp index ab88992..ebb9eef 100644 --- a/asl/option.hpp +++ b/asl/option.hpp @@ -3,6 +3,7 @@ #include "asl/assert.hpp" #include "asl/meta.hpp" #include "asl/maybe_uninit.hpp" +#include "asl/functional.hpp" namespace asl { @@ -334,7 +335,6 @@ public: constexpr bool has_value() const { return m_has_value; } - // @Todo Do we want this on rvalues? Or maybe some kind of unwrap? constexpr T&& value() && { ASL_ASSERT(m_has_value); // @Todo Release assert @@ -389,13 +389,46 @@ public: } template - T& emplace(Args&&... args) & + constexpr T& emplace(Args&&... args) & requires constructible { if (m_has_value) { reset(); } construct(ASL_FWD(args)...); return value(); } + + template + constexpr auto and_then(F&& f) & + requires is_option> + { + if (has_value()) + { + return invoke(ASL_FWD(f), value()); + } + return un_cvref_t>{}; + } + + template + constexpr auto and_then(F&& f) const& + requires is_option> + { + if (has_value()) + { + return invoke(ASL_FWD(f), value()); + } + return un_cvref_t>{}; + } + + template + constexpr auto and_then(F&& f) && + requires is_option> + { + if (has_value()) + { + return invoke(ASL_FWD(f), ASL_MOVE(value())); + } + return un_cvref_t>{}; + } }; template diff --git a/asl/tests/option_tests.cpp b/asl/tests/option_tests.cpp index 73998f8..ea20b98 100644 --- a/asl/tests/option_tests.cpp +++ b/asl/tests/option_tests.cpp @@ -155,18 +155,18 @@ ASL_TEST(convert_copy) asl::option opt8 = uint8_t{8}; asl::option opt16 = opt8; - ASL_TEST_EXPECT(opt16.has_value()); + ASL_TEST_ASSERT(opt16.has_value()); ASL_TEST_EXPECT(opt16.value() == 8); opt8 = uint8_t{10}; - ASL_TEST_EXPECT(opt8.has_value()); + ASL_TEST_ASSERT(opt8.has_value()); ASL_TEST_EXPECT(opt8.value() == 10); opt16 = asl::nullopt; ASL_TEST_EXPECT(!opt16.has_value()); opt16 = opt8; - ASL_TEST_EXPECT(opt16.has_value()); + ASL_TEST_ASSERT(opt16.has_value()); ASL_TEST_EXPECT(opt16.value() == 10); } @@ -175,18 +175,18 @@ ASL_TEST(convert_move) asl::option opt8 = uint8_t{8}; asl::option opt16 = ASL_MOVE(opt8); - ASL_TEST_EXPECT(opt16.has_value()); + ASL_TEST_ASSERT(opt16.has_value()); ASL_TEST_EXPECT(opt16.value() == 8); opt8 = ASL_MOVE(uint8_t{10}); - ASL_TEST_EXPECT(opt8.has_value()); + ASL_TEST_ASSERT(opt8.has_value()); ASL_TEST_EXPECT(opt8.value() == 10); opt16 = asl::nullopt; ASL_TEST_EXPECT(!opt16.has_value()); opt16 = ASL_MOVE(opt8); - ASL_TEST_EXPECT(opt16.has_value()); + ASL_TEST_ASSERT(opt16.has_value()); ASL_TEST_EXPECT(opt16.value() == 10); } @@ -204,7 +204,7 @@ ASL_TEST(emplace) asl::option a = asl::nullopt; a.emplace(42); - ASL_TEST_EXPECT(a.has_value()); + ASL_TEST_ASSERT(a.has_value()); ASL_TEST_EXPECT(a.value() == 42); } @@ -224,3 +224,20 @@ ASL_TEST(emplace_destroys_previous) ASL_TEST_EXPECT(b2); } + +ASL_TEST(and_then) +{ + asl::option a = 5; + asl::option b; + + auto fn = [](int x) -> asl::option { return static_cast(x) + 0.5F; }; + + auto a2 = a.and_then(fn); + static_assert(asl::is_same>); + ASL_TEST_ASSERT(a2.has_value()); + ASL_TEST_EXPECT(a2.value() == 5.5F); + + auto b2 = b.and_then(fn); + static_assert(asl::is_same>); + ASL_TEST_ASSERT(!b2.has_value()); +} -- cgit