Ensure curly-braces around control-flow
[folly.git] / folly / futures / Future-inl.h
index 4089a67647ca1ea893f2d8c2fc32120c2696d0a9..70a2c581ee6d228de585a52ed4064480df7d4c37 100644 (file)
 #include <algorithm>
 #include <cassert>
 #include <chrono>
 #include <algorithm>
 #include <cassert>
 #include <chrono>
-#include <random>
 #include <thread>
 #include <thread>
+
 #include <folly/Baton.h>
 #include <folly/Optional.h>
 #include <folly/Baton.h>
 #include <folly/Optional.h>
-#include <folly/Random.h>
-#include <folly/Traits.h>
-#include <folly/futures/detail/Core.h>
+#include <folly/futures/InlineExecutor.h>
 #include <folly/futures/Timekeeper.h>
 #include <folly/futures/Timekeeper.h>
+#include <folly/futures/detail/Core.h>
 
 
+#ifndef FOLLY_FUTURE_USING_FIBER
 #if FOLLY_MOBILE || defined(__APPLE__)
 #define FOLLY_FUTURE_USING_FIBER 0
 #else
 #define FOLLY_FUTURE_USING_FIBER 1
 #include <folly/fibers/Baton.h>
 #endif
 #if FOLLY_MOBILE || defined(__APPLE__)
 #define FOLLY_FUTURE_USING_FIBER 0
 #else
 #define FOLLY_FUTURE_USING_FIBER 1
 #include <folly/fibers/Baton.h>
 #endif
+#endif
 
 namespace folly {
 
 class Timekeeper;
 
 
 namespace folly {
 
 class Timekeeper;
 
+namespace futures {
 namespace detail {
 #if FOLLY_FUTURE_USING_FIBER
 typedef folly::fibers::Baton FutureBatonType;
 #else
 typedef folly::Baton<> FutureBatonType;
 #endif
 namespace detail {
 #if FOLLY_FUTURE_USING_FIBER
 typedef folly::fibers::Baton FutureBatonType;
 #else
 typedef folly::Baton<> FutureBatonType;
 #endif
-}
+} // namespace detail
+} // namespace futures
 
 namespace detail {
 
 namespace detail {
-  std::shared_ptr<Timekeeper> getTimekeeperSingleton();
+std::shared_ptr<Timekeeper> getTimekeeperSingleton();
+} // namespace detail
+
+namespace futures {
+namespace detail {
+//  Guarantees that the stored functor is destructed before the stored promise
+//  may be fulfilled. Assumes the stored functor to be noexcept-destructible.
+template <typename T, typename F>
+class CoreCallbackState {
+ public:
+  template <typename FF>
+  CoreCallbackState(Promise<T>&& promise, FF&& func) noexcept(
+      noexcept(F(std::declval<FF>())))
+      : func_(std::forward<FF>(func)), promise_(std::move(promise)) {
+    assert(before_barrier());
+  }
+
+  CoreCallbackState(CoreCallbackState&& that) noexcept(
+      noexcept(F(std::declval<F>()))) {
+    if (that.before_barrier()) {
+      new (&func_) F(std::move(that.func_));
+      promise_ = that.stealPromise();
+    }
+  }
+
+  CoreCallbackState& operator=(CoreCallbackState&&) = delete;
+
+  ~CoreCallbackState() {
+    if (before_barrier()) {
+      stealPromise();
+    }
+  }
+
+  template <typename... Args>
+  auto invoke(Args&&... args) noexcept(
+      noexcept(std::declval<F&&>()(std::declval<Args&&>()...))) {
+    assert(before_barrier());
+    return std::move(func_)(std::forward<Args>(args)...);
+  }
+
+  template <typename... Args>
+  auto tryInvoke(Args&&... args) noexcept {
+    return makeTryWith([&] { return invoke(std::forward<Args>(args)...); });
+  }
+
+  void setTry(Try<T>&& t) {
+    stealPromise().setTry(std::move(t));
+  }
+
+  void setException(exception_wrapper&& ew) {
+    stealPromise().setException(std::move(ew));
+  }
+
+  Promise<T> stealPromise() noexcept {
+    assert(before_barrier());
+    func_.~F();
+    return std::move(promise_);
+  }
+
+ private:
+  bool before_barrier() const noexcept {
+    return !promise_.isFulfilled();
+  }
+
+  union {
+    F func_;
+  };
+  Promise<T> promise_{Promise<T>::makeEmpty()};
+};
+
+template <typename T, typename F>
+inline auto makeCoreCallbackState(Promise<T>&& p, F&& f) noexcept(
+    noexcept(CoreCallbackState<T, _t<std::decay<F>>>(
+        std::declval<Promise<T>&&>(),
+        std::declval<F&&>()))) {
+  return CoreCallbackState<T, _t<std::decay<F>>>(
+      std::move(p), std::forward<F>(f));
 }
 }
+} // namespace detail
+} // namespace futures
 
 template <class T>
 
 template <class T>
-Future<T>::Future(Future<T>&& other) noexcept : core_(other.core_) {
+SemiFuture<typename std::decay<T>::type> makeSemiFuture(T&& t) {
+  return makeSemiFuture(Try<typename std::decay<T>::type>(std::forward<T>(t)));
+}
+
+// makeSemiFutureWith(SemiFuture<T>()) -> SemiFuture<T>
+template <class F>
+typename std::enable_if<
+    isSemiFuture<typename std::result_of<F()>::type>::value,
+    typename std::result_of<F()>::type>::type
+makeSemiFutureWith(F&& func) {
+  using InnerType =
+      typename isSemiFuture<typename std::result_of<F()>::type>::Inner;
+  try {
+    return std::forward<F>(func)();
+  } catch (std::exception& e) {
+    return makeSemiFuture<InnerType>(
+        exception_wrapper(std::current_exception(), e));
+  } catch (...) {
+    return makeSemiFuture<InnerType>(
+        exception_wrapper(std::current_exception()));
+  }
+}
+
+// makeSemiFutureWith(T()) -> SemiFuture<T>
+// makeSemiFutureWith(void()) -> SemiFuture<Unit>
+template <class F>
+typename std::enable_if<
+    !(isSemiFuture<typename std::result_of<F()>::type>::value),
+    SemiFuture<Unit::LiftT<typename std::result_of<F()>::type>>>::type
+makeSemiFutureWith(F&& func) {
+  using LiftedResult = Unit::LiftT<typename std::result_of<F()>::type>;
+  return makeSemiFuture<LiftedResult>(
+      makeTryWith([&func]() mutable { return std::forward<F>(func)(); }));
+}
+
+template <class T>
+SemiFuture<T> makeSemiFuture(std::exception_ptr const& e) {
+  return makeSemiFuture(Try<T>(e));
+}
+
+template <class T>
+SemiFuture<T> makeSemiFuture(exception_wrapper ew) {
+  return makeSemiFuture(Try<T>(std::move(ew)));
+}
+
+template <class T, class E>
+typename std::
+    enable_if<std::is_base_of<std::exception, E>::value, SemiFuture<T>>::type
+    makeSemiFuture(E const& e) {
+  return makeSemiFuture(Try<T>(make_exception_wrapper<E>(e)));
+}
+
+template <class T>
+SemiFuture<T> makeSemiFuture(Try<T>&& t) {
+  return SemiFuture<T>(new futures::detail::Core<T>(std::move(t)));
+}
+
+template <class T>
+SemiFuture<T> SemiFuture<T>::makeEmpty() {
+  return SemiFuture<T>(futures::detail::EmptyConstruct{});
+}
+
+template <class T>
+SemiFuture<T>::SemiFuture(SemiFuture<T>&& other) noexcept : core_(other.core_) {
   other.core_ = nullptr;
 }
 
 template <class T>
   other.core_ = nullptr;
 }
 
 template <class T>
-Future<T>& Future<T>::operator=(Future<T>&& other) noexcept {
+SemiFuture<T>& SemiFuture<T>::operator=(SemiFuture<T>&& other) noexcept {
+  std::swap(core_, other.core_);
+  return *this;
+}
+
+template <class T>
+SemiFuture<T>::SemiFuture(Future<T>&& other) noexcept : core_(other.core_) {
+  other.core_ = nullptr;
+}
+
+template <class T>
+SemiFuture<T>& SemiFuture<T>::operator=(Future<T>&& other) noexcept {
   std::swap(core_, other.core_);
   return *this;
 }
 
 template <class T>
 template <class T2, typename>
   std::swap(core_, other.core_);
   return *this;
 }
 
 template <class T>
 template <class T2, typename>
-Future<T>::Future(T2&& val)
-    : core_(new detail::Core<T>(Try<T>(std::forward<T2>(val)))) {}
+SemiFuture<T>::SemiFuture(T2&& val)
+    : core_(new futures::detail::Core<T>(Try<T>(std::forward<T2>(val)))) {}
 
 template <class T>
 template <typename T2>
 
 template <class T>
 template <typename T2>
-Future<T>::Future(typename std::enable_if<std::is_same<Unit, T2>::value>::type*)
-    : core_(new detail::Core<T>(Try<T>(T()))) {}
+SemiFuture<T>::SemiFuture(
+    typename std::enable_if<std::is_same<Unit, T2>::value>::type*)
+    : core_(new futures::detail::Core<T>(Try<T>(T()))) {}
 
 template <class T>
 
 template <class T>
-Future<T>::~Future() {
+template <
+    class... Args,
+    typename std::enable_if<std::is_constructible<T, Args&&...>::value, int>::
+        type>
+SemiFuture<T>::SemiFuture(in_place_t, Args&&... args)
+    : core_(
+          new futures::detail::Core<T>(in_place, std::forward<Args>(args)...)) {
+}
+
+template <class T>
+SemiFuture<T>::~SemiFuture() {
   detach();
 }
 
   detach();
 }
 
+// This must be defined after the constructors to avoid a bug in MSVC
+// https://connect.microsoft.com/VisualStudio/feedback/details/3142777/out-of-line-constructor-definition-after-implicit-reference-causes-incorrect-c2244
+inline SemiFuture<Unit> makeSemiFuture() {
+  return makeSemiFuture(Unit{});
+}
+
+template <class T>
+T& SemiFuture<T>::value() & {
+  throwIfInvalid();
+
+  return core_->getTry().value();
+}
+
+template <class T>
+T const& SemiFuture<T>::value() const& {
+  throwIfInvalid();
+
+  return core_->getTry().value();
+}
+
+template <class T>
+T&& SemiFuture<T>::value() && {
+  throwIfInvalid();
+
+  return std::move(core_->getTry().value());
+}
+
+template <class T>
+T const&& SemiFuture<T>::value() const&& {
+  throwIfInvalid();
+
+  return std::move(core_->getTry().value());
+}
+
+template <class T>
+inline Future<T> SemiFuture<T>::via(Executor* executor, int8_t priority) && {
+  throwIfInvalid();
+
+  setExecutor(executor, priority);
+
+  auto newFuture = Future<T>(core_);
+  core_ = nullptr;
+  return newFuture;
+}
+
+template <class T>
+inline Future<T> SemiFuture<T>::via(Executor* executor, int8_t priority) & {
+  throwIfInvalid();
+  Promise<T> p;
+  auto f = p.getFuture();
+  auto func = [p = std::move(p)](Try<T>&& t) mutable {
+    p.setTry(std::move(t));
+  };
+  using R = futures::detail::callableResult<T, decltype(func)>;
+  thenImplementation<decltype(func), R>(std::move(func), typename R::Arg());
+  return std::move(f).via(executor, priority);
+}
+
+template <class T>
+bool SemiFuture<T>::isReady() const {
+  throwIfInvalid();
+  return core_->ready();
+}
+
+template <class T>
+bool SemiFuture<T>::hasValue() {
+  return getTry().hasValue();
+}
+
 template <class T>
 template <class T>
-void Future<T>::detach() {
+bool SemiFuture<T>::hasException() {
+  return getTry().hasException();
+}
+
+template <class T>
+void SemiFuture<T>::detach() {
   if (core_) {
     core_->detachFuture();
     core_ = nullptr;
   if (core_) {
     core_->detachFuture();
     core_ = nullptr;
@@ -86,18 +326,115 @@ void Future<T>::detach() {
 }
 
 template <class T>
 }
 
 template <class T>
-void Future<T>::throwIfInvalid() const {
-  if (!core_)
-    throw NoState();
+Try<T>& SemiFuture<T>::getTry() {
+  throwIfInvalid();
+
+  return core_->getTry();
+}
+
+template <class T>
+void SemiFuture<T>::throwIfInvalid() const {
+  if (!core_) {
+    throwNoState();
+}
+}
+
+template <class T>
+Optional<Try<T>> SemiFuture<T>::poll() {
+  Optional<Try<T>> o;
+  if (core_->ready()) {
+    o = std::move(core_->getTry());
+  }
+  return o;
+}
+
+template <class T>
+void SemiFuture<T>::raise(exception_wrapper exception) {
+  core_->raise(std::move(exception));
 }
 
 template <class T>
 template <class F>
 }
 
 template <class T>
 template <class F>
-void Future<T>::setCallback_(F&& func) {
+void SemiFuture<T>::setCallback_(F&& func) {
   throwIfInvalid();
   core_->setCallback(std::forward<F>(func));
 }
 
   throwIfInvalid();
   core_->setCallback(std::forward<F>(func));
 }
 
+template <class T>
+SemiFuture<T>::SemiFuture(futures::detail::EmptyConstruct) noexcept
+    : core_(nullptr) {}
+
+template <class T>
+Future<T> Future<T>::makeEmpty() {
+  return Future<T>(futures::detail::EmptyConstruct{});
+}
+
+template <class T>
+Future<T>::Future(Future<T>&& other) noexcept
+    : SemiFuture<T>(std::move(other)) {}
+
+template <class T>
+Future<T>& Future<T>::operator=(Future<T>&& other) noexcept {
+  SemiFuture<T>::operator=(SemiFuture<T>{std::move(other)});
+  return *this;
+}
+
+template <class T>
+template <
+    class T2,
+    typename std::enable_if<
+        !std::is_same<T, typename std::decay<T2>::type>::value &&
+            std::is_constructible<T, T2&&>::value &&
+            std::is_convertible<T2&&, T>::value,
+        int>::type>
+Future<T>::Future(Future<T2>&& other)
+    : Future(std::move(other).then([](T2&& v) { return T(std::move(v)); })) {}
+
+template <class T>
+template <
+    class T2,
+    typename std::enable_if<
+        !std::is_same<T, typename std::decay<T2>::type>::value &&
+            std::is_constructible<T, T2&&>::value &&
+            !std::is_convertible<T2&&, T>::value,
+        int>::type>
+Future<T>::Future(Future<T2>&& other)
+    : Future(std::move(other).then([](T2&& v) { return T(std::move(v)); })) {}
+
+template <class T>
+template <
+    class T2,
+    typename std::enable_if<
+        !std::is_same<T, typename std::decay<T2>::type>::value &&
+            std::is_constructible<T, T2&&>::value,
+        int>::type>
+Future<T>& Future<T>::operator=(Future<T2>&& other) {
+  return operator=(
+      std::move(other).then([](T2&& v) { return T(std::move(v)); }));
+}
+
+// TODO: isSemiFuture
+template <class T>
+template <class T2, typename>
+Future<T>::Future(T2&& val) : SemiFuture<T>(std::forward<T2>(val)) {}
+
+template <class T>
+template <typename T2>
+Future<T>::Future(typename std::enable_if<std::is_same<Unit, T2>::value>::type*)
+    : SemiFuture<T>() {}
+
+template <class T>
+template <
+    class... Args,
+    typename std::enable_if<std::is_constructible<T, Args&&...>::value, int>::
+        type>
+Future<T>::Future(in_place_t, Args&&... args)
+    : SemiFuture<T>(in_place, std::forward<Args>(args)...) {}
+
+template <class T>
+Future<T>::~Future() {
+}
+
 // unwrap
 
 template <class T>
 // unwrap
 
 template <class T>
@@ -117,18 +454,20 @@ Future<T>::unwrap() {
 template <class T>
 template <typename F, typename R, bool isTry, typename... Args>
 typename std::enable_if<!R::ReturnsFuture::value, typename R::Return>::type
 template <class T>
 template <typename F, typename R, bool isTry, typename... Args>
 typename std::enable_if<!R::ReturnsFuture::value, typename R::Return>::type
-Future<T>::thenImplementation(F&& func, detail::argResult<isTry, F, Args...>) {
+SemiFuture<T>::thenImplementation(
+    F&& func,
+    futures::detail::argResult<isTry, F, Args...>) {
   static_assert(sizeof...(Args) <= 1, "Then must take zero/one argument");
   typedef typename R::ReturnsFuture::Inner B;
 
   static_assert(sizeof...(Args) <= 1, "Then must take zero/one argument");
   typedef typename R::ReturnsFuture::Inner B;
 
-  throwIfInvalid();
+  this->throwIfInvalid();
 
   Promise<B> p;
 
   Promise<B> p;
-  p.core_->setInterruptHandlerNoLock(core_->getInterruptHandler());
+  p.core_->setInterruptHandlerNoLock(this->core_->getInterruptHandler());
 
   // grab the Future now before we lose our handle on the Promise
   auto f = p.getFuture();
 
   // grab the Future now before we lose our handle on the Promise
   auto f = p.getFuture();
-  f.core_->setExecutorNoLock(getExecutor());
+  f.core_->setExecutorNoLock(this->getExecutor());
 
   /* This is a bit tricky.
 
 
   /* This is a bit tricky.
 
@@ -149,27 +488,27 @@ Future<T>::thenImplementation(F&& func, detail::argResult<isTry, F, Args...>) {
      persist beyond the callback, if it gets moved), and so it is an
      optimization to just make it shared from the get-go.
 
      persist beyond the callback, if it gets moved), and so it is an
      optimization to just make it shared from the get-go.
 
-     Two subtle but important points about this design. detail::Core has no
-     back pointers to Future or Promise, so if Future or Promise get moved
-     (and they will be moved in performant code) we don't have to do
+     Two subtle but important points about this design. futures::detail::Core
+     has no back pointers to Future or Promise, so if Future or Promise get
+     moved (and they will be moved in performant code) we don't have to do
      anything fancy. And because we store the continuation in the
      anything fancy. And because we store the continuation in the
-     detail::Core, not in the Future, we can execute the continuation even
-     after the Future has gone out of scope. This is an intentional design
+     futures::detail::Core, not in the Future, we can execute the continuation
+     even after the Future has gone out of scope. This is an intentional design
      decision. It is likely we will want to be able to cancel a continuation
      in some circumstances, but I think it should be explicit not implicit
      in the destruction of the Future used to create it.
      */
      decision. It is likely we will want to be able to cancel a continuation
      in some circumstances, but I think it should be explicit not implicit
      in the destruction of the Future used to create it.
      */
-  setCallback_(
-      [ func = std::forward<F>(func), pm = std::move(p) ](Try<T> && t) mutable {
+  this->setCallback_(
+      [state = futures::detail::makeCoreCallbackState(
+           std::move(p), std::forward<F>(func))](Try<T>&& t) mutable {
+
         if (!isTry && t.hasException()) {
         if (!isTry && t.hasException()) {
-          pm.setException(std::move(t.exception()));
+          state.setException(std::move(t.exception()));
         } else {
         } else {
-          pm.setWith([&]() {
-            return std::move(func)(t.template get<isTry, Args>()...);
-          });
+          state.setTry(makeTryWith(
+              [&] { return state.invoke(t.template get<isTry, Args>()...); }));
         }
       });
         }
       });
-
   return f;
 }
 
   return f;
 }
 
@@ -178,43 +517,36 @@ Future<T>::thenImplementation(F&& func, detail::argResult<isTry, F, Args...>) {
 template <class T>
 template <typename F, typename R, bool isTry, typename... Args>
 typename std::enable_if<R::ReturnsFuture::value, typename R::Return>::type
 template <class T>
 template <typename F, typename R, bool isTry, typename... Args>
 typename std::enable_if<R::ReturnsFuture::value, typename R::Return>::type
-Future<T>::thenImplementation(F&& func, detail::argResult<isTry, F, Args...>) {
+SemiFuture<T>::thenImplementation(
+    F&& func,
+    futures::detail::argResult<isTry, F, Args...>) {
   static_assert(sizeof...(Args) <= 1, "Then must take zero/one argument");
   typedef typename R::ReturnsFuture::Inner B;
   static_assert(sizeof...(Args) <= 1, "Then must take zero/one argument");
   typedef typename R::ReturnsFuture::Inner B;
-
-  throwIfInvalid();
+  this->throwIfInvalid();
 
   Promise<B> p;
 
   Promise<B> p;
-  p.core_->setInterruptHandlerNoLock(core_->getInterruptHandler());
+  p.core_->setInterruptHandlerNoLock(this->core_->getInterruptHandler());
 
   // grab the Future now before we lose our handle on the Promise
   auto f = p.getFuture();
 
   // grab the Future now before we lose our handle on the Promise
   auto f = p.getFuture();
-  f.core_->setExecutorNoLock(getExecutor());
+  f.core_->setExecutorNoLock(this->getExecutor());
 
 
-  setCallback_([ func = std::forward<F>(func), pm = std::move(p) ](
-      Try<T> && t) mutable {
-    auto ew = [&] {
-      if (!isTry && t.hasException()) {
-        return std::move(t.exception());
-      } else {
-        try {
-          auto f2 = std::move(func)(t.template get<isTry, Args>()...);
-          // that didn't throw, now we can steal p
-          f2.setCallback_([p = std::move(pm)](Try<B> && b) mutable {
-            p.setTry(std::move(b));
-          });
-          return exception_wrapper();
-        } catch (const std::exception& e) {
-          return exception_wrapper(std::current_exception(), e);
-        } catch (...) {
-          return exception_wrapper(std::current_exception());
+  this->setCallback_(
+      [state = futures::detail::makeCoreCallbackState(
+           std::move(p), std::forward<F>(func))](Try<T>&& t) mutable {
+        if (!isTry && t.hasException()) {
+          state.setException(std::move(t.exception()));
+        } else {
+          auto tf2 = state.tryInvoke(t.template get<isTry, Args>()...);
+          if (tf2.hasException()) {
+            state.setException(std::move(tf2.exception()));
+          } else {
+            tf2->setCallback_([p = state.stealPromise()](Try<B> && b) mutable {
+              p.setTry(std::move(b));
+            });
+          }
         }
         }
-      }
-    }();
-    if (ew) {
-      pm.setException(std::move(ew));
-    }
-  });
+      });
 
   return f;
 }
 
   return f;
 }
@@ -223,26 +555,15 @@ template <typename T>
 template <typename R, typename Caller, typename... Args>
   Future<typename isFuture<R>::Inner>
 Future<T>::then(R(Caller::*func)(Args...), Caller *instance) {
 template <typename R, typename Caller, typename... Args>
   Future<typename isFuture<R>::Inner>
 Future<T>::then(R(Caller::*func)(Args...), Caller *instance) {
-  typedef typename std::remove_cv<
-    typename std::remove_reference<
-      typename detail::ArgType<Args...>::FirstArg>::type>::type FirstArg;
+  typedef typename std::remove_cv<typename std::remove_reference<
+      typename futures::detail::ArgType<Args...>::FirstArg>::type>::type
+      FirstArg;
+
   return then([instance, func](Try<T>&& t){
     return (instance->*func)(t.template get<isTry<FirstArg>::value, Args>()...);
   });
 }
 
   return then([instance, func](Try<T>&& t){
     return (instance->*func)(t.template get<isTry<FirstArg>::value, Args>()...);
   });
 }
 
-template <class T>
-template <class Executor, class Arg, class... Args>
-auto Future<T>::then(Executor* x, Arg&& arg, Args&&... args)
-  -> decltype(this->then(std::forward<Arg>(arg),
-                         std::forward<Args>(args)...))
-{
-  auto oldX = getExecutor();
-  setExecutor(x);
-  return this->then(std::forward<Arg>(arg), std::forward<Args>(args)...).
-               via(oldX);
-}
-
 template <class T>
 Future<Unit> Future<T>::then() {
   return then([] () {});
 template <class T>
 Future<Unit> Future<T>::then() {
   return then([] () {});
@@ -252,25 +573,29 @@ Future<Unit> Future<T>::then() {
 template <class T>
 template <class F>
 typename std::enable_if<
 template <class T>
 template <class F>
 typename std::enable_if<
-  !detail::callableWith<F, exception_wrapper>::value &&
-  !detail::Extract<F>::ReturnsFuture::value,
-  Future<T>>::type
+    !futures::detail::callableWith<F, exception_wrapper>::value &&
+        !futures::detail::callableWith<F, exception_wrapper&>::value &&
+        !futures::detail::Extract<F>::ReturnsFuture::value,
+    Future<T>>::type
 Future<T>::onError(F&& func) {
 Future<T>::onError(F&& func) {
-  typedef typename detail::Extract<F>::FirstArg Exn;
+  typedef std::remove_reference_t<
+      typename futures::detail::Extract<F>::FirstArg>
+      Exn;
   static_assert(
   static_assert(
-      std::is_same<typename detail::Extract<F>::RawReturn, T>::value,
+      std::is_same<typename futures::detail::Extract<F>::RawReturn, T>::value,
       "Return type of onError callback must be T or Future<T>");
 
   Promise<T> p;
       "Return type of onError callback must be T or Future<T>");
 
   Promise<T> p;
-  p.core_->setInterruptHandlerNoLock(core_->getInterruptHandler());
+  p.core_->setInterruptHandlerNoLock(this->core_->getInterruptHandler());
   auto f = p.getFuture();
 
   auto f = p.getFuture();
 
-  setCallback_(
-      [ func = std::forward<F>(func), pm = std::move(p) ](Try<T> && t) mutable {
-        if (!t.template withException<Exn>([&](Exn& e) {
-              pm.setWith([&] { return std::move(func)(e); });
-            })) {
-          pm.setTry(std::move(t));
+  this->setCallback_(
+      [state = futures::detail::makeCoreCallbackState(
+           std::move(p), std::forward<F>(func))](Try<T>&& t) mutable {
+        if (auto e = t.template tryGetExceptionObject<Exn>()) {
+          state.setTry(makeTryWith([&] { return state.invoke(*e); }));
+        } else {
+          state.setTry(std::move(t));
         }
       });
 
         }
       });
 
@@ -281,41 +606,38 @@ Future<T>::onError(F&& func) {
 template <class T>
 template <class F>
 typename std::enable_if<
 template <class T>
 template <class F>
 typename std::enable_if<
-  !detail::callableWith<F, exception_wrapper>::value &&
-  detail::Extract<F>::ReturnsFuture::value,
-  Future<T>>::type
+    !futures::detail::callableWith<F, exception_wrapper>::value &&
+        !futures::detail::callableWith<F, exception_wrapper&>::value &&
+        futures::detail::Extract<F>::ReturnsFuture::value,
+    Future<T>>::type
 Future<T>::onError(F&& func) {
   static_assert(
 Future<T>::onError(F&& func) {
   static_assert(
-      std::is_same<typename detail::Extract<F>::Return, Future<T>>::value,
+      std::is_same<typename futures::detail::Extract<F>::Return, Future<T>>::
+          value,
       "Return type of onError callback must be T or Future<T>");
       "Return type of onError callback must be T or Future<T>");
-  typedef typename detail::Extract<F>::FirstArg Exn;
+  typedef std::remove_reference_t<
+      typename futures::detail::Extract<F>::FirstArg>
+      Exn;
 
   Promise<T> p;
   auto f = p.getFuture();
 
 
   Promise<T> p;
   auto f = p.getFuture();
 
-  setCallback_([ pm = std::move(p), func = std::forward<F>(func) ](
-      Try<T> && t) mutable {
-    if (!t.template withException<Exn>([&](Exn& e) {
-          auto ew = [&] {
-            try {
-              auto f2 = std::move(func)(e);
-              f2.setCallback_([pm = std::move(pm)](Try<T> && t2) mutable {
-                pm.setTry(std::move(t2));
-              });
-              return exception_wrapper();
-            } catch (const std::exception& e2) {
-              return exception_wrapper(std::current_exception(), e2);
-            } catch (...) {
-              return exception_wrapper(std::current_exception());
-            }
-          }();
-          if (ew) {
-            pm.setException(std::move(ew));
+  this->setCallback_(
+      [state = futures::detail::makeCoreCallbackState(
+           std::move(p), std::forward<F>(func))](Try<T>&& t) mutable {
+        if (auto e = t.template tryGetExceptionObject<Exn>()) {
+          auto tf2 = state.tryInvoke(*e);
+          if (tf2.hasException()) {
+            state.setException(std::move(tf2.exception()));
+          } else {
+            tf2->setCallback_([p = state.stealPromise()](Try<T> && t3) mutable {
+              p.setTry(std::move(t3));
+            });
           }
           }
-        })) {
-      pm.setTry(std::move(t));
-    }
-  });
+        } else {
+          state.setTry(std::move(t));
+        }
+      });
 
   return f;
 }
 
   return f;
 }
@@ -338,37 +660,32 @@ Future<T> Future<T>::onTimeout(Duration dur, F&& func, Timekeeper* tk) {
 
 template <class T>
 template <class F>
 
 template <class T>
 template <class F>
-typename std::enable_if<detail::callableWith<F, exception_wrapper>::value &&
-                            detail::Extract<F>::ReturnsFuture::value,
-                        Future<T>>::type
+typename std::enable_if<
+    futures::detail::callableWith<F, exception_wrapper>::value &&
+        futures::detail::Extract<F>::ReturnsFuture::value,
+    Future<T>>::type
 Future<T>::onError(F&& func) {
   static_assert(
 Future<T>::onError(F&& func) {
   static_assert(
-      std::is_same<typename detail::Extract<F>::Return, Future<T>>::value,
+      std::is_same<typename futures::detail::Extract<F>::Return, Future<T>>::
+          value,
       "Return type of onError callback must be T or Future<T>");
 
   Promise<T> p;
   auto f = p.getFuture();
       "Return type of onError callback must be T or Future<T>");
 
   Promise<T> p;
   auto f = p.getFuture();
-  setCallback_(
-      [ pm = std::move(p), func = std::forward<F>(func) ](Try<T> t) mutable {
+  this->setCallback_(
+      [state = futures::detail::makeCoreCallbackState(
+           std::move(p), std::forward<F>(func))](Try<T> t) mutable {
         if (t.hasException()) {
         if (t.hasException()) {
-          auto ew = [&] {
-            try {
-              auto f2 = std::move(func)(std::move(t.exception()));
-              f2.setCallback_([pm = std::move(pm)](Try<T> t2) mutable {
-                pm.setTry(std::move(t2));
-              });
-              return exception_wrapper();
-            } catch (const std::exception& e2) {
-              return exception_wrapper(std::current_exception(), e2);
-            } catch (...) {
-              return exception_wrapper(std::current_exception());
-            }
-          }();
-          if (ew) {
-            pm.setException(std::move(ew));
+          auto tf2 = state.tryInvoke(std::move(t.exception()));
+          if (tf2.hasException()) {
+            state.setException(std::move(tf2.exception()));
+          } else {
+            tf2->setCallback_([p = state.stealPromise()](Try<T> && t3) mutable {
+              p.setTry(std::move(t3));
+            });
           }
         } else {
           }
         } else {
-          pm.setTry(std::move(t));
+          state.setTry(std::move(t));
         }
       });
 
         }
       });
 
@@ -379,82 +696,36 @@ Future<T>::onError(F&& func) {
 template <class T>
 template <class F>
 typename std::enable_if<
 template <class T>
 template <class F>
 typename std::enable_if<
-  detail::callableWith<F, exception_wrapper>::value &&
-  !detail::Extract<F>::ReturnsFuture::value,
-  Future<T>>::type
+    futures::detail::callableWith<F, exception_wrapper>::value &&
+        !futures::detail::Extract<F>::ReturnsFuture::value,
+    Future<T>>::type
 Future<T>::onError(F&& func) {
   static_assert(
 Future<T>::onError(F&& func) {
   static_assert(
-      std::is_same<typename detail::Extract<F>::Return, Future<T>>::value,
+      std::is_same<typename futures::detail::Extract<F>::Return, Future<T>>::
+          value,
       "Return type of onError callback must be T or Future<T>");
 
   Promise<T> p;
   auto f = p.getFuture();
       "Return type of onError callback must be T or Future<T>");
 
   Promise<T> p;
   auto f = p.getFuture();
-  setCallback_(
-      [ pm = std::move(p), func = std::forward<F>(func) ](Try<T> t) mutable {
+  this->setCallback_(
+      [state = futures::detail::makeCoreCallbackState(
+           std::move(p), std::forward<F>(func))](Try<T>&& t) mutable {
         if (t.hasException()) {
         if (t.hasException()) {
-          pm.setWith([&] { return std::move(func)(std::move(t.exception())); });
+          state.setTry(makeTryWith(
+              [&] { return state.invoke(std::move(t.exception())); }));
         } else {
         } else {
-          pm.setTry(std::move(t));
+          state.setTry(std::move(t));
         }
       });
 
   return f;
 }
 
         }
       });
 
   return f;
 }
 
-template <class T>
-typename std::add_lvalue_reference<T>::type Future<T>::value() {
-  throwIfInvalid();
-
-  return core_->getTry().value();
-}
-
-template <class T>
-typename std::add_lvalue_reference<const T>::type Future<T>::value() const {
-  throwIfInvalid();
-
-  return core_->getTry().value();
-}
-
-template <class T>
-Try<T>& Future<T>::getTry() {
-  throwIfInvalid();
-
-  return core_->getTry();
-}
-
 template <class T>
 Try<T>& Future<T>::getTryVia(DrivableExecutor* e) {
   return waitVia(e).getTry();
 }
 
 template <class T>
 Try<T>& Future<T>::getTryVia(DrivableExecutor* e) {
   return waitVia(e).getTry();
 }
 
-template <class T>
-Optional<Try<T>> Future<T>::poll() {
-  Optional<Try<T>> o;
-  if (core_->ready()) {
-    o = std::move(core_->getTry());
-  }
-  return o;
-}
-
-template <class T>
-inline Future<T> Future<T>::via(Executor* executor, int8_t priority) && {
-  throwIfInvalid();
-
-  setExecutor(executor, priority);
-
-  return std::move(*this);
-}
-
-template <class T>
-inline Future<T> Future<T>::via(Executor* executor, int8_t priority) & {
-  throwIfInvalid();
-
-  Promise<T> p;
-  auto f = p.getFuture();
-  then([p = std::move(p)](Try<T> && t) mutable { p.setTry(std::move(t)); });
-  return std::move(f).via(executor, priority);
-}
-
 template <class Func>
 auto via(Executor* x, Func&& func)
     -> Future<typename isFuture<decltype(std::declval<Func>()())>::Inner> {
 template <class Func>
 auto via(Executor* x, Func&& func)
     -> Future<typename isFuture<decltype(std::declval<Func>()())>::Inner> {
@@ -463,25 +734,8 @@ auto via(Executor* x, Func&& func)
 }
 
 template <class T>
 }
 
 template <class T>
-bool Future<T>::isReady() const {
-  throwIfInvalid();
-  return core_->ready();
-}
-
-template <class T>
-bool Future<T>::hasValue() {
-  return getTry().hasValue();
-}
-
-template <class T>
-bool Future<T>::hasException() {
-  return getTry().hasException();
-}
-
-template <class T>
-void Future<T>::raise(exception_wrapper exception) {
-  core_->raise(std::move(exception));
-}
+Future<T>::Future(futures::detail::EmptyConstruct) noexcept
+    : SemiFuture<T>(futures::detail::EmptyConstruct{}) {}
 
 // makeFuture
 
 
 // makeFuture
 
@@ -490,8 +744,7 @@ Future<typename std::decay<T>::type> makeFuture(T&& t) {
   return makeFuture(Try<typename std::decay<T>::type>(std::forward<T>(t)));
 }
 
   return makeFuture(Try<typename std::decay<T>::type>(std::forward<T>(t)));
 }
 
-inline // for multiple translation units
-Future<Unit> makeFuture() {
+inline Future<Unit> makeFuture() {
   return makeFuture(Unit{});
 }
 
   return makeFuture(Unit{});
 }
 
@@ -517,10 +770,9 @@ makeFutureWith(F&& func) {
 template <class F>
 typename std::enable_if<
     !(isFuture<typename std::result_of<F()>::type>::value),
 template <class F>
 typename std::enable_if<
     !(isFuture<typename std::result_of<F()>::type>::value),
-    Future<typename Unit::Lift<typename std::result_of<F()>::type>::type>>::type
+    Future<Unit::LiftT<typename std::result_of<F()>::type>>>::type
 makeFutureWith(F&& func) {
 makeFutureWith(F&& func) {
-  using LiftedResult =
-      typename Unit::Lift<typename std::result_of<F()>::type>::type;
+  using LiftedResult = Unit::LiftT<typename std::result_of<F()>::type>;
   return makeFuture<LiftedResult>(
       makeTryWith([&func]() mutable { return std::forward<F>(func)(); }));
 }
   return makeFuture<LiftedResult>(
       makeTryWith([&func]() mutable { return std::forward<F>(func)(); }));
 }
@@ -544,7 +796,7 @@ makeFuture(E const& e) {
 
 template <class T>
 Future<T> makeFuture(Try<T>&& t) {
 
 template <class T>
 Future<T> makeFuture(Try<T>&& t) {
-  return Future<T>(new detail::Core<T>(std::move(t)));
+  return Future<T>(new futures::detail::Core<T>(std::move(t)));
 }
 
 // via
 }
 
 // via
@@ -566,13 +818,13 @@ void mapSetCallback(InputIterator first, InputIterator last, F func) {
 // collectAll (variadic)
 
 template <typename... Fs>
 // collectAll (variadic)
 
 template <typename... Fs>
-typename detail::CollectAllVariadicContext<
-  typename std::decay<Fs>::type::value_type...>::type
+typename futures::detail::CollectAllVariadicContext<
+    typename std::decay<Fs>::type::value_type...>::type
 collectAll(Fs&&... fs) {
 collectAll(Fs&&... fs) {
-  auto ctx = std::make_shared<detail::CollectAllVariadicContext<
-    typename std::decay<Fs>::type::value_type...>>();
-  detail::collectVariadicHelper<detail::CollectAllVariadicContext>(
-      ctx, std::forward<Fs>(fs)...);
+  auto ctx = std::make_shared<futures::detail::CollectAllVariadicContext<
+      typename std::decay<Fs>::type::value_type...>>();
+  futures::detail::collectVariadicHelper<
+      futures::detail::CollectAllVariadicContext>(ctx, std::forward<Fs>(fs)...);
   return ctx->p.getFuture();
 }
 
   return ctx->p.getFuture();
 }
 
@@ -605,6 +857,7 @@ collectAll(InputIterator first, InputIterator last) {
 
 // collect (iterator)
 
 
 // collect (iterator)
 
+namespace futures {
 namespace detail {
 
 template <typename T>
 namespace detail {
 
 template <typename T>
@@ -643,17 +896,18 @@ struct CollectContext {
   std::atomic<bool> threw {false};
 };
 
   std::atomic<bool> threw {false};
 };
 
-}
+} // namespace detail
+} // namespace futures
 
 template <class InputIterator>
 
 template <class InputIterator>
-Future<typename detail::CollectContext<
-  typename std::iterator_traits<InputIterator>::value_type::value_type>::Result>
+Future<typename futures::detail::CollectContext<typename std::iterator_traits<
+    InputIterator>::value_type::value_type>::Result>
 collect(InputIterator first, InputIterator last) {
   typedef
     typename std::iterator_traits<InputIterator>::value_type::value_type T;
 
 collect(InputIterator first, InputIterator last) {
   typedef
     typename std::iterator_traits<InputIterator>::value_type::value_type T;
 
-  auto ctx = std::make_shared<detail::CollectContext<T>>(
-    std::distance(first, last));
+  auto ctx = std::make_shared<futures::detail::CollectContext<T>>(
+      std::distance(first, last));
   mapSetCallback<T>(first, last, [ctx](size_t i, Try<T>&& t) {
     if (t.hasException()) {
        if (!ctx->threw.exchange(true)) {
   mapSetCallback<T>(first, last, [ctx](size_t i, Try<T>&& t) {
     if (t.hasException()) {
        if (!ctx->threw.exchange(true)) {
@@ -669,13 +923,13 @@ collect(InputIterator first, InputIterator last) {
 // collect (variadic)
 
 template <typename... Fs>
 // collect (variadic)
 
 template <typename... Fs>
-typename detail::CollectVariadicContext<
-  typename std::decay<Fs>::type::value_type...>::type
+typename futures::detail::CollectVariadicContext<
+    typename std::decay<Fs>::type::value_type...>::type
 collect(Fs&&... fs) {
 collect(Fs&&... fs) {
-  auto ctx = std::make_shared<detail::CollectVariadicContext<
-    typename std::decay<Fs>::type::value_type...>>();
-  detail::collectVariadicHelper<detail::CollectVariadicContext>(
-      ctx, std::forward<Fs>(fs)...);
+  auto ctx = std::make_shared<futures::detail::CollectVariadicContext<
+      typename std::decay<Fs>::type::value_type...>>();
+  futures::detail::collectVariadicHelper<
+      futures::detail::CollectVariadicContext>(ctx, std::forward<Fs>(fs)...);
   return ctx->p.getFuture();
 }
 
   return ctx->p.getFuture();
 }
 
@@ -784,10 +1038,10 @@ Future<T> reduce(It first, It last, T&& initial, F&& func) {
   }
 
   typedef typename std::iterator_traits<It>::value_type::value_type ItT;
   }
 
   typedef typename std::iterator_traits<It>::value_type::value_type ItT;
-  typedef
-      typename std::conditional<detail::callableWith<F, T&&, Try<ItT>&&>::value,
-                                Try<ItT>,
-                                ItT>::type Arg;
+  typedef typename std::conditional<
+      futures::detail::callableWith<F, T&&, Try<ItT>&&>::value,
+      Try<ItT>,
+      ItT>::type Arg;
   typedef isTry<Arg> IsTry;
 
   auto sfunc = std::make_shared<F>(std::move(func));
   typedef isTry<Arg> IsTry;
 
   auto sfunc = std::make_shared<F>(std::move(func));
@@ -815,27 +1069,38 @@ Future<T> reduce(It first, It last, T&& initial, F&& func) {
 template <class Collection, class F, class ItT, class Result>
 std::vector<Future<Result>>
 window(Collection input, F func, size_t n) {
 template <class Collection, class F, class ItT, class Result>
 std::vector<Future<Result>>
 window(Collection input, F func, size_t n) {
-  struct WindowContext {
-    WindowContext(Collection&& i, F&& fn)
-        : input_(std::move(i)), promises_(input_.size()),
-          func_(std::move(fn))
-      {}
-    std::atomic<size_t> i_ {0};
-    Collection input_;
-    std::vector<Promise<Result>> promises_;
-    F func_;
+  // Use global inline executor singleton
+  auto executor = &InlineExecutor::instance();
+  return window(executor, std::move(input), std::move(func), n);
+}
 
 
-    static inline void spawn(const std::shared_ptr<WindowContext>& ctx) {
-      size_t i = ctx->i_++;
-      if (i < ctx->input_.size()) {
-        // Using setCallback_ directly since we don't need the Future
-        ctx->func_(std::move(ctx->input_[i])).setCallback_(
-          // ctx is captured by value
-          [ctx, i](Try<Result>&& t) {
-            ctx->promises_[i].setTry(std::move(t));
+template <class Collection, class F, class ItT, class Result>
+std::vector<Future<Result>>
+window(Executor* executor, Collection input, F func, size_t n) {
+  struct WindowContext {
+    WindowContext(Executor* executor_, Collection&& input_, F&& func_)
+        : executor(executor_),
+          input(std::move(input_)),
+          promises(input.size()),
+          func(std::move(func_)) {}
+    std::atomic<size_t> i{0};
+    Executor* executor;
+    Collection input;
+    std::vector<Promise<Result>> promises;
+    F func;
+
+    static inline void spawn(std::shared_ptr<WindowContext> ctx) {
+      size_t i = ctx->i++;
+      if (i < ctx->input.size()) {
+        auto fut = ctx->func(std::move(ctx->input[i]));
+        fut.setCallback_([ctx = std::move(ctx), i](Try<Result>&& t) mutable {
+          const auto executor_ = ctx->executor;
+          executor_->add([ctx = std::move(ctx), i, t = std::move(t)]() mutable {
+            ctx->promises[i].setTry(std::move(t));
             // Chain another future onto this one
             spawn(std::move(ctx));
           });
             // Chain another future onto this one
             spawn(std::move(ctx));
           });
+        });
       }
     }
   };
       }
     }
   };
@@ -843,16 +1108,16 @@ window(Collection input, F func, size_t n) {
   auto max = std::min(n, input.size());
 
   auto ctx = std::make_shared<WindowContext>(
   auto max = std::min(n, input.size());
 
   auto ctx = std::make_shared<WindowContext>(
-    std::move(input), std::move(func));
+      executor, std::move(input), std::move(func));
 
 
+  // Start the first n Futures
   for (size_t i = 0; i < max; ++i) {
   for (size_t i = 0; i < max; ++i) {
-    // Start the first n Futures
-    WindowContext::spawn(ctx);
+    executor->add([ctx]() mutable { WindowContext::spawn(std::move(ctx)); });
   }
 
   std::vector<Future<Result>> futures;
   }
 
   std::vector<Future<Result>> futures;
-  futures.reserve(ctx->promises_.size());
-  for (auto& promise : ctx->promises_) {
+  futures.reserve(ctx->promises.size());
+  for (auto& promise : ctx->promises) {
     futures.emplace_back(promise.getFuture());
   }
 
     futures.emplace_back(promise.getFuture());
   }
 
@@ -948,6 +1213,10 @@ Future<T> Future<T>::within(Duration dur, E e, Timekeeper* tk) {
     std::atomic<bool> token {false};
   };
 
     std::atomic<bool> token {false};
   };
 
+  if (this->isReady()) {
+    return std::move(*this);
+  }
+
   std::shared_ptr<Timekeeper> tks;
   if (!tk) {
     tks = folly::detail::getTimekeeperSingleton();
   std::shared_ptr<Timekeeper> tks;
   if (!tk) {
     tks = folly::detail::getTimekeeperSingleton();
@@ -957,25 +1226,31 @@ Future<T> Future<T>::within(Duration dur, E e, Timekeeper* tk) {
   auto ctx = std::make_shared<Context>(std::move(e));
 
   ctx->thisFuture = this->then([ctx](Try<T>&& t) mutable {
   auto ctx = std::make_shared<Context>(std::move(e));
 
   ctx->thisFuture = this->then([ctx](Try<T>&& t) mutable {
-    // TODO: "this" completed first, cancel "after"
     if (ctx->token.exchange(true) == false) {
       ctx->promise.setTry(std::move(t));
     }
   });
 
     if (ctx->token.exchange(true) == false) {
       ctx->promise.setTry(std::move(t));
     }
   });
 
-  tk->after(dur).then([ctx](Try<Unit> const& t) mutable {
+  // Have time keeper use a weak ptr to hold ctx,
+  // so that ctx can be deallocated as soon as the future job finished.
+  tk->after(dur).then([weakCtx = to_weak_ptr(ctx)](Try<Unit> const& t) mutable {
+    auto lockedCtx = weakCtx.lock();
+    if (!lockedCtx) {
+      // ctx already released. "this" completed first, cancel "after"
+      return;
+    }
     // "after" completed first, cancel "this"
     // "after" completed first, cancel "this"
-    ctx->thisFuture.raise(TimedOut());
-    if (ctx->token.exchange(true) == false) {
+    lockedCtx->thisFuture.raise(TimedOut());
+    if (lockedCtx->token.exchange(true) == false) {
       if (t.hasException()) {
       if (t.hasException()) {
-        ctx->promise.setException(std::move(t.exception()));
+        lockedCtx->promise.setException(std::move(t.exception()));
       } else {
       } else {
-        ctx->promise.setException(std::move(ctx->exception));
+        lockedCtx->promise.setException(std::move(lockedCtx->exception));
       }
     }
   });
 
       }
     }
   });
 
-  return ctx->promise.getFuture().via(getExecutor());
+  return ctx->promise.getFuture().via(this->getExecutor());
 }
 
 // delayed
 }
 
 // delayed
@@ -989,12 +1264,15 @@ Future<T> Future<T>::delayed(Duration dur, Timekeeper* tk) {
     });
 }
 
     });
 }
 
+namespace futures {
 namespace detail {
 
 namespace detail {
 
-template <class T>
-void waitImpl(Future<T>& f) {
+template <class FutureType, typename T = typename FutureType::value_type>
+void waitImpl(FutureType& f) {
   // short-circuit if there's nothing to do
   // short-circuit if there's nothing to do
-  if (f.isReady()) return;
+  if (f.isReady()) {
+    return;
+  }
 
   FutureBatonType baton;
   f.setCallback_([&](const Try<T>& /* t */) { baton.post(); });
 
   FutureBatonType baton;
   f.setCallback_([&](const Try<T>& /* t */) { baton.post(); });
@@ -1002,8 +1280,8 @@ void waitImpl(Future<T>& f) {
   assert(f.isReady());
 }
 
   assert(f.isReady());
 }
 
-template <class T>
-void waitImpl(Future<T>& f, Duration dur) {
+template <class FutureType, typename T = typename FutureType::value_type>
+void waitImpl(FutureType& f, Duration dur) {
   // short-circuit if there's nothing to do
   if (f.isReady()) {
     return;
   // short-circuit if there's nothing to do
   if (f.isReady()) {
     return;
@@ -1027,8 +1305,9 @@ void waitViaImpl(Future<T>& f, DrivableExecutor* e) {
   // Set callback so to ensure that the via executor has something on it
   // so that once the preceding future triggers this callback, drive will
   // always have a callback to satisfy it
   // Set callback so to ensure that the via executor has something on it
   // so that once the preceding future triggers this callback, drive will
   // always have a callback to satisfy it
-  if (f.isReady())
+  if (f.isReady()) {
     return;
     return;
+  }
   f = f.via(e).then([](T&& t) { return std::move(t); });
   while (!f.isReady()) {
     e->drive();
   f = f.via(e).then([](T&& t) { return std::move(t); });
   while (!f.isReady()) {
     e->drive();
@@ -1036,57 +1315,82 @@ void waitViaImpl(Future<T>& f, DrivableExecutor* e) {
   assert(f.isReady());
 }
 
   assert(f.isReady());
 }
 
-} // detail
+} // namespace detail
+} // namespace futures
 
 template <class T>
 
 template <class T>
-Future<T>& Future<T>::wait() & {
-  detail::waitImpl(*this);
+SemiFuture<T>& SemiFuture<T>::wait() & {
+  futures::detail::waitImpl(*this);
   return *this;
 }
 
 template <class T>
   return *this;
 }
 
 template <class T>
-Future<T>&& Future<T>::wait() && {
-  detail::waitImpl(*this);
+SemiFuture<T>&& SemiFuture<T>::wait() && {
+  futures::detail::waitImpl(*this);
   return std::move(*this);
 }
 
 template <class T>
   return std::move(*this);
 }
 
 template <class T>
-Future<T>& Future<T>::wait(Duration dur) & {
-  detail::waitImpl(*this, dur);
+SemiFuture<T>& SemiFuture<T>::wait(Duration dur) & {
+  futures::detail::waitImpl(*this, dur);
   return *this;
 }
 
 template <class T>
   return *this;
 }
 
 template <class T>
-Future<T>&& Future<T>::wait(Duration dur) && {
-  detail::waitImpl(*this, dur);
+SemiFuture<T>&& SemiFuture<T>::wait(Duration dur) && {
+  futures::detail::waitImpl(*this, dur);
   return std::move(*this);
 }
 
 template <class T>
   return std::move(*this);
 }
 
 template <class T>
-Future<T>& Future<T>::waitVia(DrivableExecutor* e) & {
-  detail::waitViaImpl(*this, e);
+T SemiFuture<T>::get() {
+  return std::move(wait().value());
+}
+
+template <class T>
+T SemiFuture<T>::get(Duration dur) {
+  wait(dur);
+  if (this->isReady()) {
+    return std::move(this->value());
+  } else {
+    throwTimedOut();
+  }
+}
+
+template <class T>
+Future<T>& Future<T>::wait() & {
+  futures::detail::waitImpl(*this);
   return *this;
 }
 
 template <class T>
   return *this;
 }
 
 template <class T>
-Future<T>&& Future<T>::waitVia(DrivableExecutor* e) && {
-  detail::waitViaImpl(*this, e);
+Future<T>&& Future<T>::wait() && {
+  futures::detail::waitImpl(*this);
   return std::move(*this);
 }
 
 template <class T>
   return std::move(*this);
 }
 
 template <class T>
-T Future<T>::get() {
-  return std::move(wait().value());
+Future<T>& Future<T>::wait(Duration dur) & {
+  futures::detail::waitImpl(*this, dur);
+  return *this;
 }
 
 template <class T>
 }
 
 template <class T>
-T Future<T>::get(Duration dur) {
-  wait(dur);
-  if (isReady()) {
-    return std::move(value());
-  } else {
-    throw TimedOut();
-  }
+Future<T>&& Future<T>::wait(Duration dur) && {
+  futures::detail::waitImpl(*this, dur);
+  return std::move(*this);
+}
+
+template <class T>
+Future<T>& Future<T>::waitVia(DrivableExecutor* e) & {
+  futures::detail::waitViaImpl(*this, e);
+  return *this;
+}
+
+template <class T>
+Future<T>&& Future<T>::waitVia(DrivableExecutor* e) && {
+  futures::detail::waitViaImpl(*this, e);
+  return std::move(*this);
 }
 
 template <class T>
 }
 
 template <class T>
@@ -1094,20 +1398,23 @@ T Future<T>::getVia(DrivableExecutor* e) {
   return std::move(waitVia(e).value());
 }
 
   return std::move(waitVia(e).value());
 }
 
+namespace futures {
 namespace detail {
 namespace detail {
-  template <class T>
-  struct TryEquals {
-    static bool equals(const Try<T>& t1, const Try<T>& t2) {
-      return t1.value() == t2.value();
-    }
-  };
-}
+template <class T>
+struct TryEquals {
+  static bool equals(const Try<T>& t1, const Try<T>& t2) {
+    return t1.value() == t2.value();
+  }
+};
+} // namespace detail
+} // namespace futures
 
 template <class T>
 Future<bool> Future<T>::willEqual(Future<T>& f) {
   return collectAll(*this, f).then([](const std::tuple<Try<T>, Try<T>>& t) {
     if (std::get<0>(t).hasValue() && std::get<1>(t).hasValue()) {
 
 template <class T>
 Future<bool> Future<T>::willEqual(Future<T>& f) {
   return collectAll(*this, f).then([](const std::tuple<Try<T>, Try<T>>& t) {
     if (std::get<0>(t).hasValue() && std::get<1>(t).hasValue()) {
-      return detail::TryEquals<T>::equals(std::get<0>(t), std::get<1>(t));
+      return futures::detail::TryEquals<T>::equals(
+          std::get<0>(t), std::get<1>(t));
     } else {
       return false;
       }
     } else {
       return false;
       }
@@ -1120,52 +1427,12 @@ Future<T> Future<T>::filter(F&& predicate) {
   return this->then([p = std::forward<F>(predicate)](T val) {
     T const& valConstRef = val;
     if (!p(valConstRef)) {
   return this->then([p = std::forward<F>(predicate)](T val) {
     T const& valConstRef = val;
     if (!p(valConstRef)) {
-      throw PredicateDoesNotObtain();
+      throwPredicateDoesNotObtain();
     }
     return val;
   });
 }
 
     }
     return val;
   });
 }
 
-template <class T>
-template <class Callback>
-auto Future<T>::thenMulti(Callback&& fn)
-    -> decltype(this->then(std::forward<Callback>(fn))) {
-  // thenMulti with one callback is just a then
-  return then(std::forward<Callback>(fn));
-}
-
-template <class T>
-template <class Callback, class... Callbacks>
-auto Future<T>::thenMulti(Callback&& fn, Callbacks&&... fns)
-    -> decltype(this->then(std::forward<Callback>(fn)).
-                      thenMulti(std::forward<Callbacks>(fns)...)) {
-  // thenMulti with two callbacks is just then(a).thenMulti(b, ...)
-  return then(std::forward<Callback>(fn)).
-         thenMulti(std::forward<Callbacks>(fns)...);
-}
-
-template <class T>
-template <class Callback, class... Callbacks>
-auto Future<T>::thenMultiWithExecutor(Executor* x, Callback&& fn,
-                                      Callbacks&&... fns)
-    -> decltype(this->then(std::forward<Callback>(fn)).
-                      thenMulti(std::forward<Callbacks>(fns)...)) {
-  // thenMultiExecutor with two callbacks is
-  // via(x).then(a).thenMulti(b, ...).via(oldX)
-  auto oldX = getExecutor();
-  setExecutor(x);
-  return then(std::forward<Callback>(fn)).
-         thenMulti(std::forward<Callbacks>(fns)...).via(oldX);
-}
-
-template <class T>
-template <class Callback>
-auto Future<T>::thenMultiWithExecutor(Executor* x, Callback&& fn)
-    -> decltype(this->then(std::forward<Callback>(fn))) {
-  // thenMulti with one callback is just a then with an executor
-  return then(x, std::forward<Callback>(fn));
-}
-
 template <class F>
 inline Future<Unit> when(bool p, F&& thunk) {
   return p ? std::forward<F>(thunk)().unit() : makeFuture();
 template <class F>
 inline Future<Unit> when(bool p, F&& thunk) {
   return p ? std::forward<F>(thunk)().unit() : makeFuture();
@@ -1205,232 +1472,6 @@ namespace futures {
   }
 }
 
   }
 }
 
-namespace futures {
-
-namespace detail {
-
-struct retrying_policy_raw_tag {};
-struct retrying_policy_fut_tag {};
-
-template <class Policy>
-struct retrying_policy_traits {
-  using ew = exception_wrapper;
-  FOLLY_CREATE_HAS_MEMBER_FN_TRAITS(has_op_call, operator());
-  template <class Ret>
-  using has_op = typename std::integral_constant<bool,
-        has_op_call<Policy, Ret(size_t, const ew&)>::value ||
-        has_op_call<Policy, Ret(size_t, const ew&) const>::value>;
-  using is_raw = has_op<bool>;
-  using is_fut = has_op<Future<bool>>;
-  using tag = typename std::conditional<
-        is_raw::value, retrying_policy_raw_tag, typename std::conditional<
-        is_fut::value, retrying_policy_fut_tag, void>::type>::type;
-};
-
-template <class Policy, class FF, class Prom>
-void retryingImpl(size_t k, Policy&& p, FF&& ff, Prom prom) {
-  using F = typename std::result_of<FF(size_t)>::type;
-  using T = typename F::value_type;
-  auto f = makeFutureWith([&] { return ff(k++); });
-  f.then([
-    k,
-    prom = std::move(prom),
-    pm = std::forward<Policy>(p),
-    ffm = std::forward<FF>(ff)
-  ](Try<T> && t) mutable {
-    if (t.hasValue()) {
-      prom.setValue(std::move(t).value());
-      return;
-    }
-    auto& x = t.exception();
-    auto q = pm(k, x);
-    q.then([
-      k,
-      prom = std::move(prom),
-      xm = std::move(x),
-      pm = std::move(pm),
-      ffm = std::move(ffm)
-    ](bool shouldRetry) mutable {
-      if (shouldRetry) {
-        retryingImpl(k, std::move(pm), std::move(ffm), std::move(prom));
-      } else {
-        prom.setException(std::move(xm));
-      };
-    });
-  });
-}
-
-template <class Policy, class FF>
-typename std::result_of<FF(size_t)>::type
-retrying(size_t k, Policy&& p, FF&& ff) {
-  using F = typename std::result_of<FF(size_t)>::type;
-  using T = typename F::value_type;
-  auto prom = Promise<T>();
-  auto f = prom.getFuture();
-  retryingImpl(
-      k, std::forward<Policy>(p), std::forward<FF>(ff), std::move(prom));
-  return f;
-}
-
-template <class Policy, class FF>
-typename std::result_of<FF(size_t)>::type
-retrying(Policy&& p, FF&& ff, retrying_policy_raw_tag) {
-  auto q = [pm = std::forward<Policy>(p)](size_t k, exception_wrapper x) {
-    return makeFuture<bool>(pm(k, x));
-  };
-  return retrying(0, std::move(q), std::forward<FF>(ff));
-}
-
-template <class Policy, class FF>
-typename std::result_of<FF(size_t)>::type
-retrying(Policy&& p, FF&& ff, retrying_policy_fut_tag) {
-  return retrying(0, std::forward<Policy>(p), std::forward<FF>(ff));
-}
-
-//  jittered exponential backoff, clamped to [backoff_min, backoff_max]
-template <class URNG>
-Duration retryingJitteredExponentialBackoffDur(
-    size_t n,
-    Duration backoff_min,
-    Duration backoff_max,
-    double jitter_param,
-    URNG& rng) {
-  using d = Duration;
-  auto dist = std::normal_distribution<double>(0.0, jitter_param);
-  auto jitter = std::exp(dist(rng));
-  auto backoff = d(d::rep(jitter * backoff_min.count() * std::pow(2, n - 1)));
-  return std::max(backoff_min, std::min(backoff_max, backoff));
-}
-
-template <class Policy, class URNG>
-std::function<Future<bool>(size_t, const exception_wrapper&)>
-retryingPolicyCappedJitteredExponentialBackoff(
-    size_t max_tries,
-    Duration backoff_min,
-    Duration backoff_max,
-    double jitter_param,
-    URNG&& rng,
-    Policy&& p) {
-  return [
-    pm = std::forward<Policy>(p),
-    max_tries,
-    backoff_min,
-    backoff_max,
-    jitter_param,
-    rngp = std::forward<URNG>(rng)
-  ](size_t n, const exception_wrapper& ex) mutable {
-    if (n == max_tries) {
-      return makeFuture(false);
-    }
-    return pm(n, ex).then(
-        [ n, backoff_min, backoff_max, jitter_param, rngp = std::move(rngp) ](
-            bool v) mutable {
-          if (!v) {
-            return makeFuture(false);
-          }
-          auto backoff = detail::retryingJitteredExponentialBackoffDur(
-              n, backoff_min, backoff_max, jitter_param, rngp);
-          return futures::sleep(backoff).then([] { return true; });
-        });
-  };
-}
-
-template <class Policy, class URNG>
-std::function<Future<bool>(size_t, const exception_wrapper&)>
-retryingPolicyCappedJitteredExponentialBackoff(
-    size_t max_tries,
-    Duration backoff_min,
-    Duration backoff_max,
-    double jitter_param,
-    URNG&& rng,
-    Policy&& p,
-    retrying_policy_raw_tag) {
-  auto q = [pm = std::forward<Policy>(p)](
-      size_t n, const exception_wrapper& e) {
-    return makeFuture(pm(n, e));
-  };
-  return retryingPolicyCappedJitteredExponentialBackoff(
-      max_tries,
-      backoff_min,
-      backoff_max,
-      jitter_param,
-      std::forward<URNG>(rng),
-      std::move(q));
-}
-
-template <class Policy, class URNG>
-std::function<Future<bool>(size_t, const exception_wrapper&)>
-retryingPolicyCappedJitteredExponentialBackoff(
-    size_t max_tries,
-    Duration backoff_min,
-    Duration backoff_max,
-    double jitter_param,
-    URNG&& rng,
-    Policy&& p,
-    retrying_policy_fut_tag) {
-  return retryingPolicyCappedJitteredExponentialBackoff(
-      max_tries,
-      backoff_min,
-      backoff_max,
-      jitter_param,
-      std::forward<URNG>(rng),
-      std::forward<Policy>(p));
-}
-}
-
-template <class Policy, class FF>
-typename std::result_of<FF(size_t)>::type
-retrying(Policy&& p, FF&& ff) {
-  using tag = typename detail::retrying_policy_traits<Policy>::tag;
-  return detail::retrying(std::forward<Policy>(p), std::forward<FF>(ff), tag());
-}
-
-inline
-std::function<bool(size_t, const exception_wrapper&)>
-retryingPolicyBasic(
-    size_t max_tries) {
-  return [=](size_t n, const exception_wrapper&) { return n < max_tries; };
-}
-
-template <class Policy, class URNG>
-std::function<Future<bool>(size_t, const exception_wrapper&)>
-retryingPolicyCappedJitteredExponentialBackoff(
-    size_t max_tries,
-    Duration backoff_min,
-    Duration backoff_max,
-    double jitter_param,
-    URNG&& rng,
-    Policy&& p) {
-  using tag = typename detail::retrying_policy_traits<Policy>::tag;
-  return detail::retryingPolicyCappedJitteredExponentialBackoff(
-      max_tries,
-      backoff_min,
-      backoff_max,
-      jitter_param,
-      std::forward<URNG>(rng),
-      std::forward<Policy>(p),
-      tag());
-}
-
-inline
-std::function<Future<bool>(size_t, const exception_wrapper&)>
-retryingPolicyCappedJitteredExponentialBackoff(
-    size_t max_tries,
-    Duration backoff_min,
-    Duration backoff_max,
-    double jitter_param) {
-  auto p = [](size_t, const exception_wrapper&) { return true; };
-  return retryingPolicyCappedJitteredExponentialBackoff(
-      max_tries,
-      backoff_min,
-      backoff_max,
-      jitter_param,
-      ThreadLocalPRNG(),
-      std::move(p));
-}
-
-}
-
 // Instantiate the most common Future types to save compile time
 extern template class Future<Unit>;
 extern template class Future<bool>;
 // Instantiate the most common Future types to save compile time
 extern template class Future<Unit>;
 extern template class Future<bool>;
@@ -1438,5 +1479,4 @@ extern template class Future<int>;
 extern template class Future<int64_t>;
 extern template class Future<std::string>;
 extern template class Future<double>;
 extern template class Future<int64_t>;
 extern template class Future<std::string>;
 extern template class Future<double>;
-
 } // namespace folly
 } // namespace folly