FTL: Add Optional<T>::and_then

Bug: 185536303
Test: ftl_test
Change-Id: Ic907a662a2090ad1363bd329e7d758b2acef55ad
diff --git a/include/ftl/optional.h b/include/ftl/optional.h
index daf4502..a0a95c4 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.
@@ -37,30 +38,59 @@
   // 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();
   }
 };