diff --git a/CMakeLists.txt b/CMakeLists.txt index a9394b3..2deb4fd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,7 @@ set(TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/tests/main.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tests/in_place.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tests/relops.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tests/observers.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/tests/monadic.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/tests/extensions.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tests/constexpr.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tests/nullopt.cpp) diff --git a/docs/index.md b/docs/index.md index aab5c61..993f68f 100644 --- a/docs/index.md +++ b/docs/index.md @@ -177,16 +177,16 @@ public: U map_or(F&& f, U&& u) const &&; template <class F, class U> - U map_or_else(F&& f, U&& u) &; + auto map_or_else(F &&f, U &&u) &; template <class F, class U> - U map_or_else(F&& f, U&& u) &&; + auto map_or_else(F &&f, U &&u) &&; template <class F, class U> - U map_or_else(F&& f, U&& u) const &; + auto map_or_else(F &&f, U &&u) const &; template <class F, class U> - U map_or_else(F&& f, U&& u) const &&; + auto map_or_else(F &&f, U &&u) const &&; template <class U> - constexpr optional<U> conjunction(U&& u) const; + constexpr optional<typename std::decay<U>::type> conjunction(U&& u) const; constexpr optional disjunction(const optional& rhs) &; constexpr optional disjunction(const optional& rhs) const &; @@ -333,16 +333,16 @@ If there is a value stored, then `f` is called with `**this` and the value is re ### Function template `tl::optional::map_or_else`
(1)  template <class F, class U>
-     U map_or_else(F&& f, U&& u) &;
+     auto map_or_else(F &&f, U &&u) &;
 
 (2)  template <class F, class U>
-     U map_or_else(F&& f, U&& u) &&;
+     auto map_or_else(F &&f, U &&u) &&;
 
 (3)  template <class F, class U>
-     U map_or_else(F&& f, U&& u) const &;
+     auto map_or_else(F &&f, U &&u) const &;
 
 (4)  template <class F, class U>
-     U map_or_else(F&& f, U&& u) const &&;
+ auto map_or_else(F &&f, U &&u) const &&; Maps the stored value with `f` if there is one, otherwise calls `u` and returns the result. @@ -351,7 +351,7 @@ If there is a value stored, then `f` is called with `**this` and the value is re ### Function template `tl::optional::conjunction`
template <class U>
-constexpr optional<U> conjunction(U&& u) const;
+constexpr optional<typename std::decay<U>::type> conjunction(U&& u) const; *Returns*: `u` if `*this` has a value, otherwise an empty optional. diff --git a/optional.hpp b/optional.hpp index 8636761..9238f0e 100644 --- a/optional.hpp +++ b/optional.hpp @@ -683,32 +683,42 @@ public: /// \details If there is a value stored, then `f` is called with `**this` and the value is returned. /// Otherwise `std::forward(u)()` is returned. /// \group map_or_else - template U map_or_else(F &&f, U &&u) & { + /// \synopsis template \nauto map_or_else(F &&f, U &&u) &; + template + detail::invoke_result_t map_or_else(F &&f, U &&u) & { return has_value() ? detail::invoke(std::forward(f), **this) : std::forward(u)(); } /// \group map_or_else - template U map_or_else(F &&f, U &&u) && { + /// \synopsis template \nauto map_or_else(F &&f, U &&u) &&; + template + detail::invoke_result_t map_or_else(F &&f, U &&u) && { return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : std::forward(u)(); } /// \group map_or_else - template U map_or_else(F &&f, U &&u) const & { + /// \synopsis template \nauto map_or_else(F &&f, U &&u) const &; + template + detail::invoke_result_t map_or_else(F &&f, U &&u) const & { return has_value() ? detail::invoke(std::forward(f), **this) : std::forward(u)(); } /// \group map_or_else - template U map_or_else(F &&f, U &&u) const && { + /// \synopsis template \nauto map_or_else(F &&f, U &&u) const &&; + template + detail::invoke_result_t map_or_else(F &&f, U &&u) const && { return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : std::forward(u)(); } /// \returns `u` if `*this` has a value, otherwise an empty optional. - template constexpr optional conjunction (U &&u) const { - return has_value() ? u : nullopt; + template + constexpr optional::type> conjunction (U &&u) const { + using result = optional>; + return has_value() ? result{u} : result{nullopt}; } /// \returns `rhs` if `*this` is empty, otherwise the current value. diff --git a/tests/monadic.cpp b/tests/extensions.cpp similarity index 86% rename from tests/monadic.cpp rename to tests/extensions.cpp index 522bdf6..018bbc2 100644 --- a/tests/monadic.cpp +++ b/tests/extensions.cpp @@ -1,5 +1,6 @@ #include "catch.hpp" #include "optional.hpp" +#include #define TOKENPASTE(x, y) x##y #define TOKENPASTE2(x, y) TOKENPASTE(x, y) @@ -339,7 +340,62 @@ SECTION("constexpr and_then") { } SECTION("or else") { - //TODO + tl::optional o1 = 42; + REQUIRE(*(o1.or_else([] { return tl::make_optional(13); })) == 42); + + tl::optional o2; + REQUIRE(*(o2.or_else([] { return tl::make_optional(13); })) == 13); +} + +SECTION("disjunction") { + tl::optional o1 = 42; + tl::optional o2 = 12; + tl::optional o3; + + REQUIRE(*o1.disjunction(o2) == 42); + REQUIRE(*o1.disjunction(o3) == 42); + REQUIRE(*o2.disjunction(o1) == 12); + REQUIRE(*o2.disjunction(o3) == 12); + REQUIRE(*o3.disjunction(o1) == 42); + REQUIRE(*o3.disjunction(o2) == 12); +} + +SECTION("conjunction") { + tl::optional o1 = 42; + REQUIRE(*o1.conjunction(42.0) == 42.0); + REQUIRE(*o1.conjunction(std::string{"hello"}) == std::string{"hello"}); + REQUIRE(!o1.conjunction(tl::nullopt)); + + tl::optional o2; + REQUIRE(!o2.conjunction(42.0)); + REQUIRE(!o2.conjunction(std::string{"hello"})); + REQUIRE(!o2.conjunction(tl::nullopt)); +} + +SECTION("map_or") { + tl::optional o1 = 21; + REQUIRE((o1.map_or([](auto x) { return x * 2; }, 13)) == 42); + + tl::optional o2; + REQUIRE((o2.map_or([](auto x) { return x * 2; }, 13)) == 13); +} + +SECTION("map_or_else") { + tl::optional o1 = 21; + REQUIRE((o1.map_or_else([](auto x) { return x * 2; }, []{return 13;})) == 42); + + tl::optional o2; + REQUIRE((o2.map_or_else([](auto x) { return x * 2; }, []{return 13;})) == 13); +} + +SECTION("take") { + tl::optional o1 = 42; + REQUIRE(*o1.take() == 42); + REQUIRE(!o1); + + tl::optional o2; + REQUIRE(!o2.take()); + REQUIRE(!o2); } } ;