FTL: Yield futures without overhead

ftl::yield, which lifts T to std::future<T>, incurs the cost of
allocating, ref counting, and locking the latter's shared state.

Consolidate the existing std::future extensions into ftl::Future,
and optimize ftl::yield by including static storage for T within.

Bug: 232436803
Test: simpleperf (-31% cycles in postFramebuffer)
Change-Id: I9a7ca7de17e7af10515de97d2f6a0dfa24e35d7a
diff --git a/include/ftl/future.h b/include/ftl/future.h
index dd6358f..c78f9b7 100644
--- a/include/ftl/future.h
+++ b/include/ftl/future.h
@@ -19,18 +19,87 @@
 #include <future>
 #include <type_traits>
 #include <utility>
+#include <variant>
+
+#include <ftl/details/future.h>
 
 namespace android::ftl {
 
-// Creates a future that defers a function call until its result is queried.
+// Thin wrapper around FutureImpl<T> (concretely std::future<T> or std::shared_future<T>) with
+// extensions for pure values (created via ftl::yield) and continuations.
 //
-//   auto future = ftl::defer([](int x) { return x + 1; }, 99);
-//   assert(future.get() == 100);
+// See also SharedFuture<T> shorthand below.
 //
-template <typename F, typename... Args>
-inline auto defer(F&& f, Args&&... args) {
-  return std::async(std::launch::deferred, std::forward<F>(f), std::forward<Args>(args)...);
-}
+template <typename T, template <typename> class FutureImpl = std::future>
+class Future final : public details::BaseFuture<Future<T, FutureImpl>, T, FutureImpl> {
+  using Base = details::BaseFuture<Future, T, FutureImpl>;
+
+  friend Base;                                            // For BaseFuture<...>::self.
+  friend details::BaseFuture<Future<T>, T, std::future>;  // For BaseFuture<...>::share.
+
+ public:
+  // Constructs an invalid future.
+  Future() : future_(std::in_place_type<FutureImpl<T>>) {}
+
+  // Constructs a future from its standard counterpart, implicitly.
+  Future(FutureImpl<T>&& f) : future_(std::move(f)) {}
+
+  bool valid() const {
+    return std::holds_alternative<T>(future_) || std::get<FutureImpl<T>>(future_).valid();
+  }
+
+  // Forwarding functions. Base::share is only defined when FutureImpl is std::future, whereas the
+  // following are defined for either FutureImpl:
+  using Base::get;
+
+  // Attaches a continuation to the future. The continuation is a function that maps T to either R
+  // or ftl::Future<R>. In the former case, the chain wraps the result in a future as if by
+  // ftl::yield.
+  //
+  //   auto future = ftl::yield(123);
+  //   ftl::Future<char> futures[] = {ftl::yield('a'), ftl::yield('b')};
+  //
+  //   auto chain =
+  //       ftl::Future(std::move(future))
+  //           .then([](int x) { return static_cast<std::size_t>(x % 2); })
+  //           .then([&futures](std::size_t i) { return std::move(futures[i]); });
+  //
+  //   assert(chain.get() == 'b');
+  //
+  template <typename F, typename R = std::invoke_result_t<F, T>>
+  auto then(F&& op) && -> Future<details::future_result_t<R>> {
+    return defer(
+        [](auto&& f, F&& op) {
+          R r = op(f.get());
+          if constexpr (std::is_same_v<R, details::future_result_t<R>>) {
+            return r;
+          } else {
+            return r.get();
+          }
+        },
+        std::move(*this), std::forward<F>(op));
+  }
+
+ private:
+  template <typename V>
+  friend Future<V> yield(V&&);
+
+  template <typename V, typename... Args>
+  friend Future<V> yield(Args&&...);
+
+  template <typename... Args>
+  Future(details::ValueTag, Args&&... args)
+      : future_(std::in_place_type<T>, std::forward<Args>(args)...) {}
+
+  std::variant<T, FutureImpl<T>> future_;
+};
+
+template <typename T>
+using SharedFuture = Future<T, std::shared_future>;
+
+// Deduction guide for implicit conversion.
+template <typename T, template <typename> class FutureImpl>
+Future(FutureImpl<T>&&) -> Future<T, FutureImpl>;
 
 // Creates a future that wraps a value.
 //
@@ -41,69 +110,24 @@
 //   auto future = ftl::yield(std::move(ptr));
 //   assert(*future.get() == '!');
 //
-template <typename T>
-inline std::future<T> yield(T&& v) {
-  return defer([](T&& v) { return std::forward<T>(v); }, std::forward<T>(v));
+template <typename V>
+inline Future<V> yield(V&& value) {
+  return {details::ValueTag{}, std::move(value)};
 }
 
-namespace details {
+template <typename V, typename... Args>
+inline Future<V> yield(Args&&... args) {
+  return {details::ValueTag{}, std::forward<Args>(args)...};
+}
 
-template <typename T>
-struct future_result {
-  using type = T;
-};
-
-template <typename T>
-struct future_result<std::future<T>> {
-  using type = T;
-};
-
-template <typename T>
-using future_result_t = typename future_result<T>::type;
-
-// Attaches a continuation to a future. The continuation is a function that maps T to either R or
-// std::future<R>. In the former case, the chain wraps the result in a future as if by ftl::yield.
+// Creates a future that defers a function call until its result is queried.
 //
-//   auto future = ftl::yield(123);
-//   std::future<char> futures[] = {ftl::yield('a'), ftl::yield('b')};
+//   auto future = ftl::defer([](int x) { return x + 1; }, 99);
+//   assert(future.get() == 100);
 //
-//   std::future<char> chain =
-//       ftl::chain(std::move(future))
-//           .then([](int x) { return static_cast<std::size_t>(x % 2); })
-//           .then([&futures](std::size_t i) { return std::move(futures[i]); });
-//
-//   assert(chain.get() == 'b');
-//
-template <typename T>
-struct Chain {
-  // Implicit conversion.
-  Chain(std::future<T>&& f) : future(std::move(f)) {}
-  operator std::future<T>&&() && { return std::move(future); }
-
-  T get() && { return future.get(); }
-
-  template <typename F, typename R = std::invoke_result_t<F, T>>
-  auto then(F&& op) && -> Chain<future_result_t<R>> {
-    return defer(
-        [](auto&& f, F&& op) {
-          R r = op(f.get());
-          if constexpr (std::is_same_v<R, future_result_t<R>>) {
-            return r;
-          } else {
-            return r.get();
-          }
-        },
-        std::move(future), std::forward<F>(op));
-  }
-
-  std::future<T> future;
-};
-
-}  // namespace details
-
-template <typename T>
-inline auto chain(std::future<T>&& f) -> details::Chain<T> {
-  return std::move(f);
+template <typename F, typename... Args>
+inline auto defer(F&& f, Args&&... args) {
+  return Future(std::async(std::launch::deferred, std::forward<F>(f), std::forward<Args>(args)...));
 }
 
 }  // namespace android::ftl