Swap a few APIs to reduce sign and implicit truncations required to work with it
[folly.git] / folly / futures / Future-inl.h
index 135440a9e1ebfc49569c54bcb492c0884fb04833..cf3e334437ca440899e7a468770e6b3494c1a09f 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2015 Facebook, Inc.
+ * Copyright 2017 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 #pragma once
 
 
 #pragma once
 
+#include <algorithm>
+#include <cassert>
 #include <chrono>
 #include <chrono>
+#include <random>
 #include <thread>
 #include <thread>
-
-#include <folly/experimental/fibers/Baton.h>
+#include <folly/Baton.h>
 #include <folly/Optional.h>
 #include <folly/Optional.h>
+#include <folly/Random.h>
+#include <folly/Traits.h>
 #include <folly/futures/detail/Core.h>
 #include <folly/futures/Timekeeper.h>
 
 #include <folly/futures/detail/Core.h>
 #include <folly/futures/Timekeeper.h>
 
+#if FOLLY_MOBILE || defined(__APPLE__)
+#define FOLLY_FUTURE_USING_FIBER 0
+#else
+#define FOLLY_FUTURE_USING_FIBER 1
+#include <folly/fibers/Baton.h>
+#endif
+
 namespace folly {
 
 class Timekeeper;
 
 namespace detail {
 namespace folly {
 
 class Timekeeper;
 
 namespace detail {
-  Timekeeper* getTimekeeperSingleton();
+#if FOLLY_FUTURE_USING_FIBER
+typedef folly::fibers::Baton FutureBatonType;
+#else
+typedef folly::Baton<> FutureBatonType;
+#endif
+}
+
+namespace detail {
+  std::shared_ptr<Timekeeper> getTimekeeperSingleton();
 }
 
 template <class T>
 }
 
 template <class T>
@@ -44,22 +63,14 @@ Future<T>& Future<T>::operator=(Future<T>&& other) noexcept {
 }
 
 template <class T>
 }
 
 template <class T>
-template <class T2>
-Future<T>::Future(T2&& val) : core_(nullptr) {
-  Promise<T> p;
-  p.setValue(std::forward<T2>(val));
-  *this = p.getFuture();
-}
-
-template <>
-template <class F,
-          typename std::enable_if<std::is_void<F>::value, int>::type>
-Future<void>::Future() : core_(nullptr) {
-  Promise<void> p;
-  p.setValue();
-  *this = p.getFuture();
-}
+template <class T2, typename>
+Future<T>::Future(T2&& val)
+    : core_(new detail::Core<T>(Try<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*)
+    : core_(new detail::Core<T>(Try<T>(T()))) {}
 
 template <class T>
 Future<T>::~Future() {
 
 template <class T>
 Future<T>::~Future() {
@@ -84,7 +95,7 @@ template <class T>
 template <class F>
 void Future<T>::setCallback_(F&& func) {
   throwIfInvalid();
 template <class F>
 void Future<T>::setCallback_(F&& func) {
   throwIfInvalid();
-  core_->setCallback(std::move(func));
+  core_->setCallback(std::forward<F>(func));
 }
 
 // unwrap
 }
 
 // unwrap
@@ -106,21 +117,18 @@ 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...>) {
+Future<T>::thenImplementation(F&& func, detail::argResult<isTry, F, Args...>) {
   static_assert(sizeof...(Args) <= 1, "Then must take zero/one argument");
   typedef typename R::ReturnsFuture::Inner B;
 
   throwIfInvalid();
 
   static_assert(sizeof...(Args) <= 1, "Then must take zero/one argument");
   typedef typename R::ReturnsFuture::Inner B;
 
   throwIfInvalid();
 
-  // wrap these so we can move them into the lambda
-  folly::MoveWrapper<Promise<B>> p;
-  folly::MoveWrapper<F> funcm(std::forward<F>(func));
+  Promise<B> p;
+  p.core_->setInterruptHandlerNoLock(core_->getInterruptHandler());
 
   // grab the Future now before we lose our handle on the Promise
 
   // grab the Future now before we lose our handle on the Promise
-  auto f = p->getFuture();
-  if (getExecutor()) {
-    f.setExecutor(getExecutor());
-  }
+  auto f = p.getFuture();
+  f.core_->setExecutorNoLock(getExecutor());
 
   /* This is a bit tricky.
 
 
   /* This is a bit tricky.
 
@@ -141,9 +149,6 @@ 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.
 
-     We have to move in the Promise and func using the MoveWrapper
-     hack. (func could be copied but it's a big drag on perf).
-
      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. 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
@@ -154,16 +159,14 @@ Future<T>::thenImplementation(F func, detail::argResult<isTry, F, Args...>) {
      in some circumstances, but I think it should be explicit not implicit
      in the destruction of the Future used to create it.
      */
      in some circumstances, but I think it should be explicit not implicit
      in the destruction of the Future used to create it.
      */
-  setCallback_(
-    [p, funcm](Try<T>&& t) mutable {
-      if (!isTry && t.hasException()) {
-        p->setException(std::move(t.exception()));
-      } else {
-        p->setWith([&]() {
-          return (*funcm)(t.template get<isTry, Args>()...);
-        });
-      }
-    });
+  setCallback_([ funcm = std::forward<F>(func), pm = std::move(p) ](
+      Try<T> && t) mutable {
+    if (!isTry && t.hasException()) {
+      pm.setException(std::move(t.exception()));
+    } else {
+      pm.setWith([&]() { return funcm(t.template get<isTry, Args>()...); });
+    }
+  });
 
   return f;
 }
 
   return f;
 }
@@ -173,40 +176,43 @@ 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...>) {
+Future<T>::thenImplementation(F&& func, detail::argResult<isTry, F, Args...>) {
   static_assert(sizeof...(Args) <= 1, "Then must take zero/one argument");
   typedef typename R::ReturnsFuture::Inner B;
 
   throwIfInvalid();
 
   static_assert(sizeof...(Args) <= 1, "Then must take zero/one argument");
   typedef typename R::ReturnsFuture::Inner B;
 
   throwIfInvalid();
 
-  // wrap these so we can move them into the lambda
-  folly::MoveWrapper<Promise<B>> p;
-  folly::MoveWrapper<F> funcm(std::forward<F>(func));
+  Promise<B> p;
+  p.core_->setInterruptHandlerNoLock(core_->getInterruptHandler());
 
   // grab the Future now before we lose our handle on the Promise
 
   // grab the Future now before we lose our handle on the Promise
-  auto f = p->getFuture();
-  if (getExecutor()) {
-    f.setExecutor(getExecutor());
-  }
+  auto f = p.getFuture();
+  f.core_->setExecutorNoLock(getExecutor());
 
 
-  setCallback_(
-    [p, funcm](Try<T>&& t) mutable {
+  setCallback_([ funcm = std::forward<F>(func), pm = std::move(p) ](
+      Try<T> && t) mutable {
+    auto ew = [&] {
       if (!isTry && t.hasException()) {
       if (!isTry && t.hasException()) {
-        p->setException(std::move(t.exception()));
+        return std::move(t.exception());
       } else {
         try {
       } else {
         try {
-          auto f2 = (*funcm)(t.template get<isTry, Args>()...);
+          auto f2 = funcm(t.template get<isTry, Args>()...);
           // that didn't throw, now we can steal p
           // that didn't throw, now we can steal p
-          f2.setCallback_([p](Try<B>&& b) mutable {
-            p->setTry(std::move(b));
+          f2.setCallback_([p = std::move(pm)](Try<B> && b) mutable {
+            p.setTry(std::move(b));
           });
           });
+          return exception_wrapper();
         } catch (const std::exception& e) {
         } catch (const std::exception& e) {
-          p->setException(exception_wrapper(std::current_exception(), e));
+          return exception_wrapper(std::current_exception(), e);
         } catch (...) {
         } catch (...) {
-          p->setException(exception_wrapper(std::current_exception()));
+          return exception_wrapper(std::current_exception());
         }
       }
         }
       }
-    });
+    }();
+    if (ew) {
+      pm.setException(std::move(ew));
+    }
+  });
 
   return f;
 }
 
   return f;
 }
@@ -223,22 +229,21 @@ Future<T>::then(R(Caller::*func)(Args...), Caller *instance) {
   });
 }
 
   });
 }
 
-// TODO(6838553)
-#ifndef __clang__
 template <class T>
 template <class T>
-template <class... Args>
-auto Future<T>::then(Executor* x, Args&&... args)
-  -> decltype(this->then(std::forward<Args>(args)...))
+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);
 {
   auto oldX = getExecutor();
   setExecutor(x);
-  return this->then(std::forward<Args>(args)...).via(oldX);
+  return this->then(std::forward<Arg>(arg), std::forward<Args>(args)...).
+               via(oldX);
 }
 }
-#endif
 
 template <class T>
 
 template <class T>
-Future<void> Future<T>::then() {
-  return then([] (Try<T>&& t) {});
+Future<Unit> Future<T>::then() {
+  return then([] () {});
 }
 
 // onError where the callback returns T
 }
 
 // onError where the callback returns T
@@ -255,16 +260,14 @@ Future<T>::onError(F&& func) {
       "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());
   auto f = p.getFuture();
   auto f = p.getFuture();
-  auto pm = folly::makeMoveWrapper(std::move(p));
-  auto funcm = folly::makeMoveWrapper(std::move(func));
-  setCallback_([pm, funcm](Try<T>&& t) mutable {
-    if (!t.template withException<Exn>([&] (Exn& e) {
-          pm->setWith([&]{
-            return (*funcm)(e);
-          });
-        })) {
-      pm->setTry(std::move(t));
+
+  setCallback_([ funcm = std::forward<F>(func), pm = std::move(p) ](
+      Try<T> && t) mutable {
+    if (!t.template withException<Exn>(
+            [&](Exn& e) { pm.setWith([&] { return funcm(e); }); })) {
+      pm.setTry(std::move(t));
     }
   });
 
     }
   });
 
@@ -286,22 +289,28 @@ Future<T>::onError(F&& func) {
 
   Promise<T> p;
   auto f = p.getFuture();
 
   Promise<T> p;
   auto f = p.getFuture();
-  auto pm = folly::makeMoveWrapper(std::move(p));
-  auto funcm = folly::makeMoveWrapper(std::move(func));
-  setCallback_([pm, funcm](Try<T>&& t) mutable {
-    if (!t.template withException<Exn>([&] (Exn& e) {
-          try {
-            auto f2 = (*funcm)(e);
-            f2.setCallback_([pm](Try<T>&& t2) mutable {
-              pm->setTry(std::move(t2));
-            });
-          } catch (const std::exception& e2) {
-            pm->setException(exception_wrapper(std::current_exception(), e2));
-          } catch (...) {
-            pm->setException(exception_wrapper(std::current_exception()));
+
+  setCallback_([ pm = std::move(p), funcm = std::forward<F>(func) ](
+      Try<T> && t) mutable {
+    if (!t.template withException<Exn>([&](Exn& e) {
+          auto ew = [&] {
+            try {
+              auto f2 = funcm(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));
           }
         })) {
           }
         })) {
-      pm->setTry(std::move(t));
+      pm.setTry(std::move(t));
     }
   });
 
     }
   });
 
@@ -310,10 +319,9 @@ Future<T>::onError(F&& func) {
 
 template <class T>
 template <class F>
 
 template <class T>
 template <class F>
-Future<T> Future<T>::ensure(F func) {
-  MoveWrapper<F> funcw(std::move(func));
-  return this->then([funcw](Try<T>&& t) {
-    (*funcw)();
+Future<T> Future<T>::ensure(F&& func) {
+  return this->then([funcw = std::forward<F>(func)](Try<T> && t) mutable {
+    funcw();
     return makeFuture(std::move(t));
   });
 }
     return makeFuture(std::move(t));
   });
 }
@@ -321,17 +329,15 @@ Future<T> Future<T>::ensure(F func) {
 template <class T>
 template <class F>
 Future<T> Future<T>::onTimeout(Duration dur, F&& func, Timekeeper* tk) {
 template <class T>
 template <class F>
 Future<T> Future<T>::onTimeout(Duration dur, F&& func, Timekeeper* tk) {
-  auto funcw = folly::makeMoveWrapper(std::forward<F>(func));
-  return within(dur, tk)
-    .onError([funcw](TimedOut const&) { return (*funcw)(); });
+  return within(dur, tk).onError([funcw = std::forward<F>(func)](
+      TimedOut const&) { return funcw(); });
 }
 
 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<detail::callableWith<F, exception_wrapper>::value &&
+                            detail::Extract<F>::ReturnsFuture::value,
+                        Future<T>>::type
 Future<T>::onError(F&& func) {
   static_assert(
       std::is_same<typename detail::Extract<F>::Return, Future<T>>::value,
 Future<T>::onError(F&& func) {
   static_assert(
       std::is_same<typename detail::Extract<F>::Return, Future<T>>::value,
@@ -339,24 +345,29 @@ Future<T>::onError(F&& func) {
 
   Promise<T> p;
   auto f = p.getFuture();
 
   Promise<T> p;
   auto f = p.getFuture();
-  auto pm = folly::makeMoveWrapper(std::move(p));
-  auto funcm = folly::makeMoveWrapper(std::move(func));
-  setCallback_([pm, funcm](Try<T> t) mutable {
-    if (t.hasException()) {
-      try {
-        auto f2 = (*funcm)(std::move(t.exception()));
-        f2.setCallback_([pm](Try<T> t2) mutable {
-          pm->setTry(std::move(t2));
-        });
-      } catch (const std::exception& e2) {
-        pm->setException(exception_wrapper(std::current_exception(), e2));
-      } catch (...) {
-        pm->setException(exception_wrapper(std::current_exception()));
-      }
-    } else {
-      pm->setTry(std::move(t));
-    }
-  });
+  setCallback_(
+      [ pm = std::move(p), funcm = std::forward<F>(func) ](Try<T> t) mutable {
+        if (t.hasException()) {
+          auto ew = [&] {
+            try {
+              auto f2 = funcm(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));
+          }
+        } else {
+          pm.setTry(std::move(t));
+        }
+      });
 
   return f;
 }
 
   return f;
 }
@@ -375,17 +386,14 @@ Future<T>::onError(F&& func) {
 
   Promise<T> p;
   auto f = p.getFuture();
 
   Promise<T> p;
   auto f = p.getFuture();
-  auto pm = folly::makeMoveWrapper(std::move(p));
-  auto funcm = folly::makeMoveWrapper(std::move(func));
-  setCallback_([pm, funcm](Try<T> t) mutable {
-    if (t.hasException()) {
-      pm->setWith([&]{
-        return (*funcm)(std::move(t.exception()));
+  setCallback_(
+      [ pm = std::move(p), funcm = std::forward<F>(func) ](Try<T> t) mutable {
+        if (t.hasException()) {
+          pm.setWith([&] { return funcm(std::move(t.exception())); });
+        } else {
+          pm.setTry(std::move(t));
+        }
       });
       });
-    } else {
-      pm->setTry(std::move(t));
-    }
-  });
 
   return f;
 }
 
   return f;
 }
@@ -411,6 +419,11 @@ Try<T>& Future<T>::getTry() {
   return core_->getTry();
 }
 
   return core_->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;
 template <class T>
 Optional<Try<T>> Future<T>::poll() {
   Optional<Try<T>> o;
@@ -421,24 +434,30 @@ Optional<Try<T>> Future<T>::poll() {
 }
 
 template <class T>
 }
 
 template <class T>
-template <typename Executor>
-inline Future<T> Future<T>::via(Executor* executor) && {
+inline Future<T> Future<T>::via(Executor* executor, int8_t priority) && {
   throwIfInvalid();
 
   throwIfInvalid();
 
-  setExecutor(executor);
+  setExecutor(executor, priority);
 
   return std::move(*this);
 }
 
 template <class T>
 
   return std::move(*this);
 }
 
 template <class T>
-template <typename Executor>
-inline Future<T> Future<T>::via(Executor* executor) & {
+inline Future<T> Future<T>::via(Executor* executor, int8_t priority) & {
   throwIfInvalid();
 
   throwIfInvalid();
 
-  MoveWrapper<Promise<T>> p;
-  auto f = p->getFuture();
-  then([p](Try<T>&& t) mutable { p->setTry(std::move(t)); });
-  return std::move(f).via(executor);
+  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(func())>::Inner>
+{
+  // TODO make this actually more performant. :-P #7260175
+  return via(x).then(std::forward<Func>(func));
 }
 
 template <class T>
 }
 
 template <class T>
@@ -447,6 +466,16 @@ bool Future<T>::isReady() const {
   return core_->ready();
 }
 
   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));
 template <class T>
 void Future<T>::raise(exception_wrapper exception) {
   core_->raise(std::move(exception));
@@ -456,98 +485,97 @@ void Future<T>::raise(exception_wrapper exception) {
 
 template <class T>
 Future<typename std::decay<T>::type> makeFuture(T&& t) {
 
 template <class T>
 Future<typename std::decay<T>::type> makeFuture(T&& t) {
-  Promise<typename std::decay<T>::type> p;
-  p.setValue(std::forward<T>(t));
-  return p.getFuture();
+  return makeFuture(Try<typename std::decay<T>::type>(std::forward<T>(t)));
 }
 
 inline // for multiple translation units
 }
 
 inline // for multiple translation units
-Future<void> makeFuture() {
-  Promise<void> p;
-  p.setValue();
-  return p.getFuture();
+Future<Unit> makeFuture() {
+  return makeFuture(Unit{});
 }
 
 }
 
+// makeFutureWith(Future<T>()) -> Future<T>
 template <class F>
 template <class F>
-auto makeFutureWith(
-    F&& func,
-    typename std::enable_if<!std::is_reference<F>::value, bool>::type sdf)
-    -> Future<decltype(func())> {
-  Promise<decltype(func())> p;
-  p.setWith(
-    [&func]() {
-      return (func)();
-    });
-  return p.getFuture();
+typename std::enable_if<isFuture<typename std::result_of<F()>::type>::value,
+                        typename std::result_of<F()>::type>::type
+makeFutureWith(F&& func) {
+  using InnerType =
+      typename isFuture<typename std::result_of<F()>::type>::Inner;
+  try {
+    return func();
+  } catch (std::exception& e) {
+    return makeFuture<InnerType>(
+        exception_wrapper(std::current_exception(), e));
+  } catch (...) {
+    return makeFuture<InnerType>(exception_wrapper(std::current_exception()));
+  }
 }
 
 }
 
+// makeFutureWith(T()) -> Future<T>
+// makeFutureWith(void()) -> Future<Unit>
 template <class F>
 template <class F>
-auto makeFutureWith(F const& func) -> Future<decltype(func())> {
-  F copy = func;
-  return makeFutureWith(std::move(copy));
+typename std::enable_if<
+    !(isFuture<typename std::result_of<F()>::type>::value),
+    Future<typename Unit::Lift<typename std::result_of<F()>::type>::type>>::type
+makeFutureWith(F&& func) {
+  using LiftedResult =
+      typename Unit::Lift<typename std::result_of<F()>::type>::type;
+  return makeFuture<LiftedResult>(makeTryWith([&func]() mutable {
+    return func();
+  }));
 }
 
 template <class T>
 Future<T> makeFuture(std::exception_ptr const& e) {
 }
 
 template <class T>
 Future<T> makeFuture(std::exception_ptr const& e) {
-  Promise<T> p;
-  p.setException(e);
-  return p.getFuture();
+  return makeFuture(Try<T>(e));
 }
 
 template <class T>
 Future<T> makeFuture(exception_wrapper ew) {
 }
 
 template <class T>
 Future<T> makeFuture(exception_wrapper ew) {
-  Promise<T> p;
-  p.setException(std::move(ew));
-  return p.getFuture();
+  return makeFuture(Try<T>(std::move(ew)));
 }
 
 template <class T, class E>
 typename std::enable_if<std::is_base_of<std::exception, E>::value,
                         Future<T>>::type
 makeFuture(E const& e) {
 }
 
 template <class T, class E>
 typename std::enable_if<std::is_base_of<std::exception, E>::value,
                         Future<T>>::type
 makeFuture(E const& e) {
-  Promise<T> p;
-  p.setException(make_exception_wrapper<E>(e));
-  return p.getFuture();
+  return makeFuture(Try<T>(make_exception_wrapper<E>(e)));
 }
 
 template <class T>
 Future<T> makeFuture(Try<T>&& t) {
 }
 
 template <class T>
 Future<T> makeFuture(Try<T>&& t) {
-  Promise<typename std::decay<T>::type> p;
-  p.setTry(std::move(t));
-  return p.getFuture();
+  return Future<T>(new detail::Core<T>(std::move(t)));
 }
 
 }
 
-template <>
-inline Future<void> makeFuture(Try<void>&& t) {
-  if (t.hasException()) {
-    return makeFuture<void>(std::move(t.exception()));
-  } else {
-    return makeFuture();
-  }
+// via
+Future<Unit> via(Executor* executor, int8_t priority) {
+  return makeFuture().via(executor, priority);
 }
 
 }
 
-// via
-template <typename Executor>
-Future<void> via(Executor* executor) {
-  return makeFuture().via(executor);
+// mapSetCallback calls func(i, Try<T>) when every future completes
+
+template <class T, class InputIterator, class F>
+void mapSetCallback(InputIterator first, InputIterator last, F func) {
+  for (size_t i = 0; first != last; ++first, ++i) {
+    first->setCallback_([func, i](Try<T>&& t) {
+      func(i, std::move(t));
+    });
+  }
 }
 
 }
 
-// when (variadic)
+// collectAll (variadic)
 
 template <typename... Fs>
 
 template <typename... Fs>
-typename detail::VariadicContext<
+typename detail::CollectAllVariadicContext<
   typename std::decay<Fs>::type::value_type...>::type
 collectAll(Fs&&... fs) {
   typename std::decay<Fs>::type::value_type...>::type
 collectAll(Fs&&... fs) {
-  auto ctx =
-    new detail::VariadicContext<typename std::decay<Fs>::type::value_type...>();
-  ctx->total = sizeof...(fs);
-  auto f_saved = ctx->p.getFuture();
-  detail::collectAllVariadicHelper(ctx,
-    std::forward<typename std::decay<Fs>::type>(fs)...);
-  return f_saved;
+  auto ctx = std::make_shared<detail::CollectAllVariadicContext<
+    typename std::decay<Fs>::type::value_type...>>();
+  detail::collectVariadicHelper<detail::CollectAllVariadicContext>(
+    ctx, std::forward<typename std::decay<Fs>::type>(fs)...);
+  return ctx->p.getFuture();
 }
 
 }
 
-// when (iterator)
+// collectAll (iterator)
 
 template <class InputIterator>
 Future<
 
 template <class InputIterator>
 Future<
@@ -557,184 +585,159 @@ collectAll(InputIterator first, InputIterator last) {
   typedef
     typename std::iterator_traits<InputIterator>::value_type::value_type T;
 
   typedef
     typename std::iterator_traits<InputIterator>::value_type::value_type T;
 
-  if (first >= last) {
-    return makeFuture(std::vector<Try<T>>());
-  }
-  size_t n = std::distance(first, last);
-
-  auto ctx = new detail::WhenAllContext<T>();
-
-  ctx->results.resize(n);
-
-  auto f_saved = ctx->p.getFuture();
-
-  for (size_t i = 0; first != last; ++first, ++i) {
-     assert(i < n);
-     auto& f = *first;
-     f.setCallback_([ctx, i, n](Try<T> t) {
-       ctx->results[i] = std::move(t);
-       if (++ctx->count == n) {
-         ctx->p.setValue(std::move(ctx->results));
-         delete ctx;
-       }
-     });
-  }
+  struct CollectAllContext {
+    CollectAllContext(size_t n) : results(n) {}
+    ~CollectAllContext() {
+      p.setValue(std::move(results));
+    }
+    Promise<std::vector<Try<T>>> p;
+    std::vector<Try<T>> results;
+  };
 
 
-  return f_saved;
+  auto ctx =
+      std::make_shared<CollectAllContext>(size_t(std::distance(first, last)));
+  mapSetCallback<T>(first, last, [ctx](size_t i, Try<T>&& t) {
+    ctx->results[i] = std::move(t);
+  });
+  return ctx->p.getFuture();
 }
 
 }
 
-namespace detail {
+// collect (iterator)
 
 
-template <class, class, typename = void> struct CollectContextHelper;
-
-template <class T, class VecT>
-struct CollectContextHelper<T, VecT,
-    typename std::enable_if<std::is_same<T, VecT>::value>::type> {
-  static inline std::vector<T>&& getResults(std::vector<VecT>& results) {
-    return std::move(results);
-  }
-};
-
-template <class T, class VecT>
-struct CollectContextHelper<T, VecT,
-    typename std::enable_if<!std::is_same<T, VecT>::value>::type> {
-  static inline std::vector<T> getResults(std::vector<VecT>& results) {
-    std::vector<T> finalResults;
-    finalResults.reserve(results.size());
-    for (auto& opt : results) {
-      finalResults.push_back(std::move(opt.value()));
-    }
-    return finalResults;
-  }
-};
+namespace detail {
 
 template <typename T>
 struct CollectContext {
 
 template <typename T>
 struct CollectContext {
+  struct Nothing {
+    explicit Nothing(int /* n */) {}
+  };
 
 
-  typedef typename std::conditional<
-    std::is_default_constructible<T>::value,
-    T,
-    Optional<T>
-   >::type VecT;
-
-  explicit CollectContext(int n) : count(0), threw(false) {
-    results.resize(n);
-  }
-
-  Promise<std::vector<T>> p;
-  std::vector<VecT> results;
-  std::atomic<size_t> count;
-  std::atomic_bool threw;
-
-  typedef std::vector<T> result_type;
-
-  static inline Future<std::vector<T>> makeEmptyFuture() {
-    return makeFuture(std::vector<T>());
-  }
-
-  inline void setValue() {
-    p.setValue(CollectContextHelper<T, VecT>::getResults(results));
-  }
-
-  inline void addResult(int i, Try<T>& t) {
-    results[i] = std::move(t.value());
-  }
-};
-
-template <>
-struct CollectContext<void> {
-
-  explicit CollectContext(int n) : count(0), threw(false) {}
-
-  Promise<void> p;
-  std::atomic<size_t> count;
-  std::atomic_bool threw;
-
-  typedef void result_type;
-
-  static inline Future<void> makeEmptyFuture() {
-    return makeFuture();
-  }
-
-  inline void setValue() {
-    p.setValue();
+  using Result = typename std::conditional<
+    std::is_void<T>::value,
+    void,
+    std::vector<T>>::type;
+
+  using InternalResult = typename std::conditional<
+    std::is_void<T>::value,
+    Nothing,
+    std::vector<Optional<T>>>::type;
+
+  explicit CollectContext(size_t n) : result(n) {}
+  ~CollectContext() {
+    if (!threw.exchange(true)) {
+      // map Optional<T> -> T
+      std::vector<T> finalResult;
+      finalResult.reserve(result.size());
+      std::transform(result.begin(), result.end(),
+                     std::back_inserter(finalResult),
+                     [](Optional<T>& o) { return std::move(o.value()); });
+      p.setValue(std::move(finalResult));
+    }
   }
   }
-
-  inline void addResult(int i, Try<void>& t) {
-    // do nothing
+  inline void setPartialResult(size_t i, Try<T>& t) {
+    result[i] = std::move(t.value());
   }
   }
+  Promise<Result> p;
+  InternalResult result;
+  std::atomic<bool> threw {false};
 };
 
 };
 
-} // detail
+}
 
 template <class InputIterator>
 Future<typename detail::CollectContext<
 
 template <class InputIterator>
 Future<typename detail::CollectContext<
-  typename std::iterator_traits<InputIterator>::value_type::value_type
->::result_type>
+  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;
 
-  if (first >= last) {
-    return detail::CollectContext<T>::makeEmptyFuture();
-  }
-
-  size_t n = std::distance(first, last);
-  auto ctx = new detail::CollectContext<T>(n);
-  auto f_saved = ctx->p.getFuture();
-
-  for (size_t i = 0; first != last; ++first, ++i) {
-     assert(i < n);
-     auto& f = *first;
-     f.setCallback_([ctx, i, n](Try<T> t) {
-       auto c = ++ctx->count;
-
-       if (t.hasException()) {
-         if (!ctx->threw.exchange(true)) {
-           ctx->p.setException(std::move(t.exception()));
-         }
-       } else if (!ctx->threw) {
-         ctx->addResult(i, t);
-         if (c == n) {
-           ctx->setValue();
-         }
+  auto ctx = std::make_shared<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)) {
+         ctx->p.setException(std::move(t.exception()));
        }
        }
+     } else if (!ctx->threw) {
+       ctx->setPartialResult(i, t);
+     }
+  });
+  return ctx->p.getFuture();
+}
 
 
-       if (c == n) {
-         delete ctx;
-       }
-     });
-  }
+// collect (variadic)
 
 
-  return f_saved;
+template <typename... Fs>
+typename detail::CollectVariadicContext<
+  typename std::decay<Fs>::type::value_type...>::type
+collect(Fs&&... fs) {
+  auto ctx = std::make_shared<detail::CollectVariadicContext<
+    typename std::decay<Fs>::type::value_type...>>();
+  detail::collectVariadicHelper<detail::CollectVariadicContext>(
+    ctx, std::forward<typename std::decay<Fs>::type>(fs)...);
+  return ctx->p.getFuture();
 }
 
 }
 
+// collectAny (iterator)
+
 template <class InputIterator>
 Future<
   std::pair<size_t,
             Try<
               typename
 template <class InputIterator>
 Future<
   std::pair<size_t,
             Try<
               typename
-              std::iterator_traits<InputIterator>::value_type::value_type> > >
+              std::iterator_traits<InputIterator>::value_type::value_type>>>
 collectAny(InputIterator first, InputIterator last) {
   typedef
     typename std::iterator_traits<InputIterator>::value_type::value_type T;
 
 collectAny(InputIterator first, InputIterator last) {
   typedef
     typename std::iterator_traits<InputIterator>::value_type::value_type T;
 
-  auto ctx = new detail::WhenAnyContext<T>(std::distance(first, last));
-  auto f_saved = ctx->p.getFuture();
+  struct CollectAnyContext {
+    CollectAnyContext() {}
+    Promise<std::pair<size_t, Try<T>>> p;
+    std::atomic<bool> done {false};
+  };
 
 
-  for (size_t i = 0; first != last; first++, i++) {
-    auto& f = *first;
-    f.setCallback_([i, ctx](Try<T>&& t) {
-      if (!ctx->done.exchange(true)) {
-        ctx->p.setValue(std::make_pair(i, std::move(t)));
-      }
-      ctx->decref();
-    });
-  }
+  auto ctx = std::make_shared<CollectAnyContext>();
+  mapSetCallback<T>(first, last, [ctx](size_t i, Try<T>&& t) {
+    if (!ctx->done.exchange(true)) {
+      ctx->p.setValue(std::make_pair(i, std::move(t)));
+    }
+  });
+  return ctx->p.getFuture();
+}
+
+// collectAnyWithoutException (iterator)
 
 
-  return f_saved;
+template <class InputIterator>
+Future<std::pair<
+    size_t,
+    typename std::iterator_traits<InputIterator>::value_type::value_type>>
+collectAnyWithoutException(InputIterator first, InputIterator last) {
+  typedef
+      typename std::iterator_traits<InputIterator>::value_type::value_type T;
+
+  struct CollectAnyWithoutExceptionContext {
+    CollectAnyWithoutExceptionContext(){}
+    Promise<std::pair<size_t, T>> p;
+    std::atomic<bool> done{false};
+    std::atomic<size_t> nFulfilled{0};
+    size_t nTotal;
+  };
+
+  auto ctx = std::make_shared<CollectAnyWithoutExceptionContext>();
+  ctx->nTotal = size_t(std::distance(first, last));
+
+  mapSetCallback<T>(first, last, [ctx](size_t i, Try<T>&& t) {
+    if (!t.hasException() && !ctx->done.exchange(true)) {
+      ctx->p.setValue(std::make_pair(i, std::move(t.value())));
+    } else if (++ctx->nFulfilled == ctx->nTotal) {
+      ctx->p.setException(t.exception());
+    }
+  });
+  return ctx->p.getFuture();
 }
 
 }
 
+// collectN (iterator)
+
 template <class InputIterator>
 Future<std::vector<std::pair<size_t, Try<typename
   std::iterator_traits<InputIterator>::value_type::value_type>>>>
 template <class InputIterator>
 Future<std::vector<std::pair<size_t, Try<typename
   std::iterator_traits<InputIterator>::value_type::value_type>>>>
@@ -743,90 +746,190 @@ collectN(InputIterator first, InputIterator last, size_t n) {
     std::iterator_traits<InputIterator>::value_type::value_type T;
   typedef std::vector<std::pair<size_t, Try<T>>> V;
 
     std::iterator_traits<InputIterator>::value_type::value_type T;
   typedef std::vector<std::pair<size_t, Try<T>>> V;
 
-  struct ctx_t {
+  struct CollectNContext {
     V v;
     V v;
-    size_t completed;
+    std::atomic<size_t> completed = {0};
     Promise<V> p;
   };
     Promise<V> p;
   };
-  auto ctx = std::make_shared<ctx_t>();
-  ctx->completed = 0;
-
-  // for each completed Future, increase count and add to vector, until we
-  // have n completed futures at which point we fulfill our Promise with the
-  // vector
-  auto it = first;
-  size_t i = 0;
-  while (it != last) {
-    it->then([ctx, n, i](Try<T>&& t) {
-      auto& v = ctx->v;
+  auto ctx = std::make_shared<CollectNContext>();
+
+  if (size_t(std::distance(first, last)) < n) {
+    ctx->p.setException(std::runtime_error("Not enough futures"));
+  } else {
+    // for each completed Future, increase count and add to vector, until we
+    // have n completed futures at which point we fulfil our Promise with the
+    // vector
+    mapSetCallback<T>(first, last, [ctx, n](size_t i, Try<T>&& t) {
       auto c = ++ctx->completed;
       if (c <= n) {
         assert(ctx->v.size() < n);
       auto c = ++ctx->completed;
       if (c <= n) {
         assert(ctx->v.size() < n);
-        v.push_back(std::make_pair(i, std::move(t)));
+        ctx->v.emplace_back(i, std::move(t));
         if (c == n) {
         if (c == n) {
-          ctx->p.setTry(Try<V>(std::move(v)));
+          ctx->p.setTry(Try<V>(std::move(ctx->v)));
         }
       }
     });
         }
       }
     });
-
-    it++;
-    i++;
-  }
-
-  if (i < n) {
-    ctx->p.setException(std::runtime_error("Not enough futures"));
   }
 
   return ctx->p.getFuture();
 }
 
   }
 
   return ctx->p.getFuture();
 }
 
-template <class It, class T, class F, class ItT, class Arg>
-typename std::enable_if<!isFutureResult<F, T, Arg>::value, Future<T>>::type
-reduce(It first, It last, T initial, F func) {
+// reduce (iterator)
+
+template <class It, class T, class F>
+Future<T> reduce(It first, It last, T&& initial, F&& func) {
   if (first == last) {
     return makeFuture(std::move(initial));
   }
 
   if (first == last) {
     return makeFuture(std::move(initial));
   }
 
+  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 isTry<Arg> IsTry;
 
   typedef isTry<Arg> IsTry;
 
-  return collectAll(first, last)
-    .then([initial, func](std::vector<Try<ItT>>& vals) mutable {
-      for (auto& val : vals) {
-        initial = func(std::move(initial),
-                       // Either return a ItT&& or a Try<ItT>&& depending
-                       // on the type of the argument of func.
-                       val.template get<IsTry::value, Arg&&>());
-      }
-      return initial;
+  auto sfunc = std::make_shared<F>(std::move(func));
+
+  auto f = first->then(
+      [ minitial = std::move(initial), sfunc ](Try<ItT> & head) mutable {
+        return (*sfunc)(
+            std::move(minitial), head.template get<IsTry::value, Arg&&>());
+      });
+
+  for (++first; first != last; ++first) {
+    f = collectAll(f, *first).then([sfunc](std::tuple<Try<T>, Try<ItT>>& t) {
+      return (*sfunc)(std::move(std::get<0>(t).value()),
+                  // Either return a ItT&& or a Try<ItT>&& depending
+                  // on the type of the argument of func.
+                  std::get<1>(t).template get<IsTry::value, Arg&&>());
     });
     });
+  }
+
+  return f;
+}
+
+// window (collection)
+
+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_;
+
+    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));
+            // Chain another future onto this one
+            spawn(std::move(ctx));
+          });
+      }
+    }
+  };
+
+  auto max = std::min(n, input.size());
+
+  auto ctx = std::make_shared<WindowContext>(
+    std::move(input), std::move(func));
+
+  for (size_t i = 0; i < max; ++i) {
+    // Start the first n Futures
+    WindowContext::spawn(ctx);
+  }
+
+  std::vector<Future<Result>> futures;
+  futures.reserve(ctx->promises_.size());
+  for (auto& promise : ctx->promises_) {
+    futures.emplace_back(promise.getFuture());
+  }
+
+  return futures;
 }
 
 }
 
+// reduce
+
+template <class T>
+template <class I, class F>
+Future<I> Future<T>::reduce(I&& initial, F&& func) {
+  return then([
+    minitial = std::forward<I>(initial),
+    mfunc = std::forward<F>(func)
+  ](T& vals) mutable {
+    auto ret = std::move(minitial);
+    for (auto& val : vals) {
+      ret = mfunc(std::move(ret), std::move(val));
+    }
+    return ret;
+  });
+}
+
+// unorderedReduce (iterator)
+
 template <class It, class T, class F, class ItT, class Arg>
 template <class It, class T, class F, class ItT, class Arg>
-typename std::enable_if<isFutureResult<F, T, Arg>::value, Future<T>>::type
-reduce(It first, It last, T initial, F func) {
+Future<T> unorderedReduce(It first, It last, T initial, F func) {
   if (first == last) {
     return makeFuture(std::move(initial));
   }
 
   typedef isTry<Arg> IsTry;
 
   if (first == last) {
     return makeFuture(std::move(initial));
   }
 
   typedef isTry<Arg> IsTry;
 
-  auto f = first->then([initial, func](Try<ItT>& head) mutable {
-    return func(std::move(initial),
-                head.template get<IsTry::value, Arg&&>());
-  });
+  struct UnorderedReduceContext {
+    UnorderedReduceContext(T&& memo, F&& fn, size_t n)
+        : lock_(), memo_(makeFuture<T>(std::move(memo))),
+          func_(std::move(fn)), numThens_(0), numFutures_(n), promise_()
+      {}
+    folly::MicroSpinLock lock_; // protects memo_ and numThens_
+    Future<T> memo_;
+    F func_;
+    size_t numThens_; // how many Futures completed and called .then()
+    size_t numFutures_; // how many Futures in total
+    Promise<T> promise_;
+  };
 
 
-  for (++first; first != last; ++first) {
-    f = collectAll(f, *first).then([func](std::tuple<Try<T>, Try<ItT>>& t) {
-      return func(std::move(std::get<0>(t).value()),
-                  // Either return a ItT&& or a Try<ItT>&& depending
-                  // on the type of the argument of func.
-                  std::get<1>(t).template get<IsTry::value, Arg&&>());
-    });
-  }
+  auto ctx = std::make_shared<UnorderedReduceContext>(
+    std::move(initial), std::move(func), std::distance(first, last));
+
+  mapSetCallback<ItT>(
+      first,
+      last,
+      [ctx](size_t /* i */, Try<ItT>&& t) {
+        // Futures can be completed in any order, simultaneously.
+        // To make this non-blocking, we create a new Future chain in
+        // the order of completion to reduce the values.
+        // The spinlock just protects chaining a new Future, not actually
+        // executing the reduce, which should be really fast.
+        folly::MSLGuard lock(ctx->lock_);
+        ctx->memo_ =
+            ctx->memo_.then([ ctx, mt = std::move(t) ](T && v) mutable {
+              // Either return a ItT&& or a Try<ItT>&& depending
+              // on the type of the argument of func.
+              return ctx->func_(std::move(v),
+                                mt.template get<IsTry::value, Arg&&>());
+            });
+        if (++ctx->numThens_ == ctx->numFutures_) {
+          // After reducing the value of the last Future, fulfill the Promise
+          ctx->memo_.setCallback_(
+              [ctx](Try<T>&& t2) { ctx->promise_.setValue(std::move(t2)); });
+        }
+      });
 
 
-  return f;
+  return ctx->promise_.getFuture();
 }
 
 }
 
+// within
+
 template <class T>
 Future<T> Future<T>::within(Duration dur, Timekeeper* tk) {
   return within(dur, TimedOut(), tk);
 template <class T>
 Future<T> Future<T>::within(Duration dur, Timekeeper* tk) {
   return within(dur, TimedOut(), tk);
@@ -837,41 +940,49 @@ template <class E>
 Future<T> Future<T>::within(Duration dur, E e, Timekeeper* tk) {
 
   struct Context {
 Future<T> Future<T>::within(Duration dur, E e, Timekeeper* tk) {
 
   struct Context {
-    Context(E ex) : exception(std::move(ex)), promise(), token(false) {}
+    Context(E ex) : exception(std::move(ex)), promise() {}
     E exception;
     E exception;
+    Future<Unit> thisFuture;
     Promise<T> promise;
     Promise<T> promise;
-    std::atomic<bool> token;
+    std::atomic<bool> token {false};
   };
   };
-  auto ctx = std::make_shared<Context>(std::move(e));
 
 
+  std::shared_ptr<Timekeeper> tks;
   if (!tk) {
   if (!tk) {
-    tk = folly::detail::getTimekeeperSingleton();
+    tks = folly::detail::getTimekeeperSingleton();
+    tk = DCHECK_NOTNULL(tks.get());
   }
 
   }
 
-  tk->after(dur)
-    .then([ctx](Try<void> const& t) {
-      if (ctx->token.exchange(true) == false) {
-        if (t.hasException()) {
-          ctx->promise.setException(std::move(t.exception()));
-        } else {
-          ctx->promise.setException(std::move(ctx->exception));
-        }
-      }
-    });
+  auto ctx = std::make_shared<Context>(std::move(e));
 
 
-  this->then([ctx](Try<T>&& t) {
+  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));
     }
   });
 
-  return ctx->promise.getFuture();
+  tk->after(dur).then([ctx](Try<Unit> const& t) mutable {
+    // "after" completed first, cancel "this"
+    ctx->thisFuture.raise(TimedOut());
+    if (ctx->token.exchange(true) == false) {
+      if (t.hasException()) {
+        ctx->promise.setException(std::move(t.exception()));
+      } else {
+        ctx->promise.setException(std::move(ctx->exception));
+      }
+    }
+  });
+
+  return ctx->promise.getFuture().via(getExecutor());
 }
 
 }
 
+// delayed
+
 template <class T>
 Future<T> Future<T>::delayed(Duration dur, Timekeeper* tk) {
   return collectAll(*this, futures::sleep(dur, tk))
 template <class T>
 Future<T> Future<T>::delayed(Duration dur, Timekeeper* tk) {
   return collectAll(*this, futures::sleep(dur, tk))
-    .then([](std::tuple<Try<T>, Try<void>> tup) {
+    .then([](std::tuple<Try<T>, Try<Unit>> tup) {
       Try<T>& t = std::get<0>(tup);
       return makeFuture<T>(std::move(t));
     });
       Try<T>& t = std::get<0>(tup);
       return makeFuture<T>(std::move(t));
     });
@@ -884,47 +995,44 @@ void waitImpl(Future<T>& f) {
   // short-circuit if there's nothing to do
   if (f.isReady()) return;
 
   // short-circuit if there's nothing to do
   if (f.isReady()) return;
 
-  folly::fibers::Baton baton;
-  f = f.then([&](Try<T> t) {
-    baton.post();
-    return makeFuture(std::move(t));
-  });
+  FutureBatonType baton;
+  f.setCallback_([&](const Try<T>& /* t */) { baton.post(); });
   baton.wait();
   baton.wait();
-
-  // There's a race here between the return here and the actual finishing of
-  // the future. f is completed, but the setup may not have finished on done
-  // after the baton has posted.
-  while (!f.isReady()) {
-    std::this_thread::yield();
-  }
+  assert(f.isReady());
 }
 
 template <class T>
 void waitImpl(Future<T>& f, Duration dur) {
   // short-circuit if there's nothing to do
 }
 
 template <class T>
 void waitImpl(Future<T>& f, Duration dur) {
   // short-circuit if there's nothing to do
-  if (f.isReady()) return;
+  if (f.isReady()) {
+    return;
+  }
 
 
-  auto baton = std::make_shared<folly::fibers::Baton>();
-  f = f.then([baton](Try<T> t) {
+  Promise<T> promise;
+  auto ret = promise.getFuture();
+  auto baton = std::make_shared<FutureBatonType>();
+  f.setCallback_([ baton, promise = std::move(promise) ](Try<T> && t) mutable {
+    promise.setTry(std::move(t));
     baton->post();
     baton->post();
-    return makeFuture(std::move(t));
   });
   });
-
-  // Let's preserve the invariant that if we did not timeout (timed_wait returns
-  // true), then the returned Future is complete when it is returned to the
-  // caller. We need to wait out the race for that Future to complete.
+  f = std::move(ret);
   if (baton->timed_wait(dur)) {
   if (baton->timed_wait(dur)) {
-    while (!f.isReady()) {
-      std::this_thread::yield();
-    }
+    assert(f.isReady());
   }
 }
 
 template <class T>
 void waitViaImpl(Future<T>& f, DrivableExecutor* e) {
   }
 }
 
 template <class T>
 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
+  if (f.isReady())
+    return;
+  f = f.via(e).then([](T&& t) { return std::move(t); });
   while (!f.isReady()) {
     e->drive();
   }
   while (!f.isReady()) {
     e->drive();
   }
+  assert(f.isReady());
 }
 
 } // detail
 }
 
 } // detail
@@ -970,11 +1078,6 @@ T Future<T>::get() {
   return std::move(wait().value());
 }
 
   return std::move(wait().value());
 }
 
-template <>
-inline void Future<void>::get() {
-  wait().value();
-}
-
 template <class T>
 T Future<T>::get(Duration dur) {
   wait(dur);
 template <class T>
 T Future<T>::get(Duration dur) {
   wait(dur);
@@ -985,31 +1088,25 @@ T Future<T>::get(Duration dur) {
   }
 }
 
   }
 }
 
-template <>
-inline void Future<void>::get(Duration dur) {
-  wait(dur);
-  if (isReady()) {
-    return;
-  } else {
-    throw TimedOut();
-  }
-}
-
 template <class T>
 T Future<T>::getVia(DrivableExecutor* e) {
   return std::move(waitVia(e).value());
 }
 
 template <class T>
 T Future<T>::getVia(DrivableExecutor* e) {
   return std::move(waitVia(e).value());
 }
 
-template <>
-inline void Future<void>::getVia(DrivableExecutor* e) {
-  waitVia(e).value();
+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>
 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 std::get<0>(t).value() == std::get<1>(t).value();
+      return detail::TryEquals<T>::equals(std::get<0>(t), std::get<1>(t));
     } else {
       return false;
       }
     } else {
       return false;
       }
@@ -1018,41 +1115,85 @@ Future<bool> Future<T>::willEqual(Future<T>& f) {
 
 template <class T>
 template <class F>
 
 template <class T>
 template <class F>
-Future<T> Future<T>::filter(F predicate) {
-  auto p = folly::makeMoveWrapper(std::move(predicate));
-  return this->then([p](T val) {
+Future<T> Future<T>::filter(F&& predicate) {
+  return this->then([p = std::forward<F>(predicate)](T val) {
     T const& valConstRef = val;
     T const& valConstRef = val;
-    if (!(*p)(valConstRef)) {
+    if (!p(valConstRef)) {
       throw PredicateDoesNotObtain();
     }
     return val;
   });
 }
 
       throw PredicateDoesNotObtain();
     }
     return val;
   });
 }
 
-namespace futures {
-  namespace {
-    template <class Z>
-    Future<Z> chainHelper(Future<Z> f) {
-      return f;
-    }
+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 Z, class F, class Fn, class... Callbacks>
-    Future<Z> chainHelper(F f, Fn fn, Callbacks... fns) {
-      return chainHelper<Z>(f.then(fn), fns...);
-    }
-  }
+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 A, class Z, class... Callbacks>
-  std::function<Future<Z>(Try<A>)>
-  chain(Callbacks... fns) {
-    MoveWrapper<Promise<A>> pw;
-    MoveWrapper<Future<Z>> fw(chainHelper<Z>(pw->getFuture(), fns...));
-    return [=](Try<A> t) mutable {
-      pw->setTry(std::move(t));
-      return std::move(*fw);
-    };
+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 P, class F>
+Future<Unit> whileDo(P&& predicate, F&& thunk) {
+  if (predicate()) {
+    auto future = thunk();
+    return future.then([
+      predicate = std::forward<P>(predicate),
+      thunk = std::forward<F>(thunk)
+    ]() mutable {
+      return whileDo(std::forward<P>(predicate), std::forward<F>(thunk));
+    });
   }
   }
+  return makeFuture();
+}
 
 
+template <class F>
+Future<Unit> times(const int n, F&& thunk) {
+  return folly::whileDo(
+      [ n, count = folly::make_unique<std::atomic<int>>(0) ]() mutable {
+        return count->fetch_add(1) < n;
+      },
+      std::forward<F>(thunk));
+}
+
+namespace futures {
   template <class It, class F, class ItT, class Result>
   std::vector<Future<Result>> map(It first, It last, F func) {
     std::vector<Future<Result>> results;
   template <class It, class F, class ItT, class Result>
   std::vector<Future<Result>> map(It first, It last, F func) {
     std::vector<Future<Result>> results;
@@ -1063,9 +1204,212 @@ namespace futures {
   }
 }
 
   }
 }
 
-} // namespace folly
+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;
+};
 
 
-// I haven't included a Future<T&> specialization because I don't forsee us
-// using it, however it is not difficult to add when needed. Refer to
-// Future<void> for guidance. std::future and boost::future code would also be
-// instructive.
+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 f = ff(k++);
+  return f.onError(
+      [ k, pm = std::forward<Policy>(p), ffm = std::forward<FF>(ff) ](
+          exception_wrapper x) mutable {
+        auto q = pm(k, x);
+        return q.then(
+            [ k, xm = std::move(x), pm = std::move(pm), ffm = std::move(ffm) ](
+                bool r) mutable {
+              return r ? retrying(k, std::move(pm), std::move(ffm))
+                       : makeFuture<T>(std::move(xm));
+            });
+      });
+}
+
+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>;
+extern template class Future<int>;
+extern template class Future<int64_t>;
+extern template class Future<std::string>;
+extern template class Future<double>;
+
+} // namespace folly