summaryrefslogtreecommitdiff
path: root/include/ftl/optional.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/ftl/optional.h')
-rw-r--r--include/ftl/optional.h64
1 files changed, 50 insertions, 14 deletions
diff --git a/include/ftl/optional.h b/include/ftl/optional.h
index daf4502bd2..626507fd8f 100644
--- a/include/ftl/optional.h
+++ b/include/ftl/optional.h
@@ -18,9 +18,10 @@
#include <functional>
#include <optional>
-#include <type_traits>
#include <utility>
+#include <ftl/details/optional.h>
+
namespace android::ftl {
// Superset of std::optional<T> with monadic operations, as proposed in https://wg21.link/P0798R8.
@@ -31,41 +32,76 @@ template <typename T>
struct Optional final : std::optional<T> {
using std::optional<T>::optional;
+ // Implicit downcast.
+ Optional(std::optional<T> other) : std::optional<T>(std::move(other)) {}
+
using std::optional<T>::has_value;
using std::optional<T>::value;
// Returns Optional<U> where F is a function that maps T to U.
template <typename F>
constexpr auto transform(F&& f) const& {
- using U = std::remove_cv_t<std::invoke_result_t<F, decltype(value())>>;
- if (has_value()) return Optional<U>(std::invoke(std::forward<F>(f), value()));
- return Optional<U>();
+ using R = details::transform_result_t<F, decltype(value())>;
+ if (has_value()) return R(std::invoke(std::forward<F>(f), value()));
+ return R();
}
template <typename F>
constexpr auto transform(F&& f) & {
- using U = std::remove_cv_t<std::invoke_result_t<F, decltype(value())>>;
- if (has_value()) return Optional<U>(std::invoke(std::forward<F>(f), value()));
- return Optional<U>();
+ using R = details::transform_result_t<F, decltype(value())>;
+ if (has_value()) return R(std::invoke(std::forward<F>(f), value()));
+ return R();
}
template <typename F>
constexpr auto transform(F&& f) const&& {
- using U = std::invoke_result_t<F, decltype(std::move(value()))>;
- if (has_value()) return Optional<U>(std::invoke(std::forward<F>(f), std::move(value())));
- return Optional<U>();
+ using R = details::transform_result_t<F, decltype(std::move(value()))>;
+ if (has_value()) return R(std::invoke(std::forward<F>(f), std::move(value())));
+ return R();
}
template <typename F>
constexpr auto transform(F&& f) && {
- using U = std::invoke_result_t<F, decltype(std::move(value()))>;
- if (has_value()) return Optional<U>(std::invoke(std::forward<F>(f), std::move(value())));
- return Optional<U>();
+ using R = details::transform_result_t<F, decltype(std::move(value()))>;
+ if (has_value()) return R(std::invoke(std::forward<F>(f), std::move(value())));
+ return R();
+ }
+
+ // Returns Optional<U> where F is a function that maps T to Optional<U>.
+ template <typename F>
+ constexpr auto and_then(F&& f) const& {
+ using R = details::and_then_result_t<F, decltype(value())>;
+ if (has_value()) return std::invoke(std::forward<F>(f), value());
+ return R();
+ }
+
+ template <typename F>
+ constexpr auto and_then(F&& f) & {
+ using R = details::and_then_result_t<F, decltype(value())>;
+ if (has_value()) return std::invoke(std::forward<F>(f), value());
+ return R();
+ }
+
+ template <typename F>
+ constexpr auto and_then(F&& f) const&& {
+ using R = details::and_then_result_t<F, decltype(std::move(value()))>;
+ if (has_value()) return std::invoke(std::forward<F>(f), std::move(value()));
+ return R();
+ }
+
+ template <typename F>
+ constexpr auto and_then(F&& f) && {
+ using R = details::and_then_result_t<F, decltype(std::move(value()))>;
+ if (has_value()) return std::invoke(std::forward<F>(f), std::move(value()));
+ return R();
}
};
-// Deduction guide.
+// Deduction guides.
template <typename T>
Optional(T) -> Optional<T>;
+template <typename T>
+Optional(std::optional<T>) -> Optional<T>;
+
} // namespace android::ftl