rearrange Future.h
authorHans Fugal <fugalh@fb.com>
Mon, 27 Apr 2015 18:20:04 +0000 (11:20 -0700)
committerAlecs King <int@fb.com>
Mon, 27 Apr 2015 23:54:58 +0000 (16:54 -0700)
Summary: Move boring preamble stuff to `Future-pre.h` and `folly::futures` and `makeFuture` and pals to `helpers.h`.

Test Plan:
tests still build and pass

Reviewed By: jsedgwick@fb.com

Subscribers: exa, folly-diffs@, jsedgwick, yfeldblum, chalfant, hannesr, davejwatson

FB internal diff: D2014330

Signature: t1:2014330:1429941589:1e2c336136f3375f9b96e5df8c06ca5820ba6aeb

folly/Makefile.am
folly/futures/Future-pre.h [new file with mode: 0644]
folly/futures/Future.h
folly/futures/helpers.h [new file with mode: 0644]

index adba4d1e205d2625c82a031b3cdf78284768cae8..1c4030cfe62b1c0de103c3b991fea5067d80811b 100644 (file)
@@ -122,8 +122,10 @@ nobase_follyinclude_HEADERS = \
        Format-inl.h \
        futures/Deprecated.h \
        futures/DrivableExecutor.h \
-       futures/Future-inl.h \
+       futures/Future-pre.h \
+       futures/helpers.h \
        futures/Future.h \
+       futures/Future-inl.h \
        futures/FutureException.h \
        futures/InlineExecutor.h \
        futures/ManualExecutor.h \
diff --git a/folly/futures/Future-pre.h b/folly/futures/Future-pre.h
new file mode 100644 (file)
index 0000000..70add42
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2015 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+// included by Future.h, do not include directly.
+
+namespace folly {
+
+template <class> struct Promise;
+
+template <typename T>
+struct isFuture : std::false_type {
+  typedef T Inner;
+};
+
+template <typename T>
+struct isFuture<Future<T>> : std::true_type {
+  typedef T Inner;
+};
+
+template <typename T>
+struct isTry : std::false_type {};
+
+template <typename T>
+struct isTry<Try<T>> : std::true_type {};
+
+namespace detail {
+
+template <class> struct Core;
+template <class...> struct VariadicContext;
+template <class> struct CollectContext;
+
+template<typename F, typename... Args>
+using resultOf = decltype(std::declval<F>()(std::declval<Args>()...));
+
+template <typename...>
+struct ArgType;
+
+template <typename Arg, typename... Args>
+struct ArgType<Arg, Args...> {
+  typedef Arg FirstArg;
+};
+
+template <>
+struct ArgType<> {
+  typedef void FirstArg;
+};
+
+template <bool isTry, typename F, typename... Args>
+struct argResult {
+  typedef resultOf<F, Args...> Result;
+};
+
+template<typename F, typename... Args>
+struct callableWith {
+    template<typename T,
+             typename = detail::resultOf<T, Args...>>
+    static constexpr std::true_type
+    check(std::nullptr_t) { return std::true_type{}; };
+
+    template<typename>
+    static constexpr std::false_type
+    check(...) { return std::false_type{}; };
+
+    typedef decltype(check<F>(nullptr)) type;
+    static constexpr bool value = type::value;
+};
+
+template<typename T, typename F>
+struct callableResult {
+  typedef typename std::conditional<
+    callableWith<F>::value,
+    detail::argResult<false, F>,
+    typename std::conditional<
+      callableWith<F, T&&>::value,
+      detail::argResult<false, F, T&&>,
+      typename std::conditional<
+        callableWith<F, T&>::value,
+        detail::argResult<false, F, T&>,
+        typename std::conditional<
+          callableWith<F, Try<T>&&>::value,
+          detail::argResult<true, F, Try<T>&&>,
+          detail::argResult<true, F, Try<T>&>>::type>::type>::type>::type Arg;
+  typedef isFuture<typename Arg::Result> ReturnsFuture;
+  typedef Future<typename ReturnsFuture::Inner> Return;
+};
+
+template<typename F>
+struct callableResult<void, F> {
+  typedef typename std::conditional<
+    callableWith<F>::value,
+    detail::argResult<false, F>,
+    typename std::conditional<
+      callableWith<F, Try<void>&&>::value,
+      detail::argResult<true, F, Try<void>&&>,
+      detail::argResult<true, F, Try<void>&>>::type>::type Arg;
+  typedef isFuture<typename Arg::Result> ReturnsFuture;
+  typedef Future<typename ReturnsFuture::Inner> Return;
+};
+
+template <typename L>
+struct Extract : Extract<decltype(&L::operator())> { };
+
+template <typename Class, typename R, typename... Args>
+struct Extract<R(Class::*)(Args...) const> {
+  typedef isFuture<R> ReturnsFuture;
+  typedef Future<typename ReturnsFuture::Inner> Return;
+  typedef typename ReturnsFuture::Inner RawReturn;
+  typedef typename ArgType<Args...>::FirstArg FirstArg;
+};
+
+template <typename Class, typename R, typename... Args>
+struct Extract<R(Class::*)(Args...)> {
+  typedef isFuture<R> ReturnsFuture;
+  typedef Future<typename ReturnsFuture::Inner> Return;
+  typedef typename ReturnsFuture::Inner RawReturn;
+  typedef typename ArgType<Args...>::FirstArg FirstArg;
+};
+
+} // detail
+
+
+struct Timekeeper;
+
+} // namespace
index 683c3cbbda985aeb1e949f51974be026fa2e53ce..0989873d51ebfe15f8f523dc9fd5508bb88c44cf 100644 (file)
 #include <folly/futures/FutureException.h>
 #include <folly/futures/detail/Types.h>
 
-namespace folly {
-
-template <class> struct Promise;
-
-template <typename T>
-struct isFuture : std::false_type {
-  typedef T Inner;
-};
-
-template <typename T>
-struct isFuture<Future<T>> : std::true_type {
-  typedef T Inner;
-};
-
-template <typename T>
-struct isTry : std::false_type {};
-
-template <typename T>
-struct isTry<Try<T>> : std::true_type {};
-
-namespace detail {
-
-template <class> struct Core;
-template <class...> struct VariadicContext;
-template <class> struct CollectContext;
-
-template<typename F, typename... Args>
-using resultOf = decltype(std::declval<F>()(std::declval<Args>()...));
-
-template <typename...>
-struct ArgType;
-
-template <typename Arg, typename... Args>
-struct ArgType<Arg, Args...> {
-  typedef Arg FirstArg;
-};
-
-template <>
-struct ArgType<> {
-  typedef void FirstArg;
-};
-
-template <bool isTry, typename F, typename... Args>
-struct argResult {
-  typedef resultOf<F, Args...> Result;
-};
-
-template<typename F, typename... Args>
-struct callableWith {
-    template<typename T,
-             typename = detail::resultOf<T, Args...>>
-    static constexpr std::true_type
-    check(std::nullptr_t) { return std::true_type{}; };
-
-    template<typename>
-    static constexpr std::false_type
-    check(...) { return std::false_type{}; };
-
-    typedef decltype(check<F>(nullptr)) type;
-    static constexpr bool value = type::value;
-};
-
-template<typename T, typename F>
-struct callableResult {
-  typedef typename std::conditional<
-    callableWith<F>::value,
-    detail::argResult<false, F>,
-    typename std::conditional<
-      callableWith<F, T&&>::value,
-      detail::argResult<false, F, T&&>,
-      typename std::conditional<
-        callableWith<F, T&>::value,
-        detail::argResult<false, F, T&>,
-        typename std::conditional<
-          callableWith<F, Try<T>&&>::value,
-          detail::argResult<true, F, Try<T>&&>,
-          detail::argResult<true, F, Try<T>&>>::type>::type>::type>::type Arg;
-  typedef isFuture<typename Arg::Result> ReturnsFuture;
-  typedef Future<typename ReturnsFuture::Inner> Return;
-};
-
-template<typename F>
-struct callableResult<void, F> {
-  typedef typename std::conditional<
-    callableWith<F>::value,
-    detail::argResult<false, F>,
-    typename std::conditional<
-      callableWith<F, Try<void>&&>::value,
-      detail::argResult<true, F, Try<void>&&>,
-      detail::argResult<true, F, Try<void>&>>::type>::type Arg;
-  typedef isFuture<typename Arg::Result> ReturnsFuture;
-  typedef Future<typename ReturnsFuture::Inner> Return;
-};
-
-template <typename L>
-struct Extract : Extract<decltype(&L::operator())> { };
+// boring predeclarations and details
+#include <folly/futures/Future-pre.h>
 
-template <typename Class, typename R, typename... Args>
-struct Extract<R(Class::*)(Args...) const> {
-  typedef isFuture<R> ReturnsFuture;
-  typedef Future<typename ReturnsFuture::Inner> Return;
-  typedef typename ReturnsFuture::Inner RawReturn;
-  typedef typename ArgType<Args...>::FirstArg FirstArg;
-};
-
-template <typename Class, typename R, typename... Args>
-struct Extract<R(Class::*)(Args...)> {
-  typedef isFuture<R> ReturnsFuture;
-  typedef Future<typename ReturnsFuture::Inner> Return;
-  typedef typename ReturnsFuture::Inner RawReturn;
-  typedef typename ArgType<Args...>::FirstArg FirstArg;
-};
-
-} // detail
-
-struct Timekeeper;
-
-/// This namespace is for utility functions that would usually be static
-/// members of Future, except they don't make sense there because they don't
-/// depend on the template type (rather, on the type of their arguments in
-/// some cases). This is the least-bad naming scheme we could think of. Some
-/// of the functions herein have really-likely-to-collide names, like "map"
-/// and "sleep".
-namespace futures {
-  /// Returns a Future that will complete after the specified duration. The
-  /// Duration typedef of a `std::chrono` duration type indicates the
-  /// resolution you can expect to be meaningful (milliseconds at the time of
-  /// writing). Normally you wouldn't need to specify a Timekeeper, we will
-  /// use the global futures timekeeper (we run a thread whose job it is to
-  /// keep time for futures timeouts) but we provide the option for power
-  /// users.
-  ///
-  /// The Timekeeper thread will be lazily created the first time it is
-  /// needed. If your program never uses any timeouts or other time-based
-  /// Futures you will pay no Timekeeper thread overhead.
-  Future<void> sleep(Duration, Timekeeper* = nullptr);
+// not-boring helpers, e.g. all in folly::futures, makeFuture variants, etc.
+// Needs to be included after Future-pre.h and before Future-inl.h
+#include <folly/futures/helpers.h>
 
-  /// Create a Future chain from a sequence of callbacks. i.e.
-  ///
-  ///   f.then(a).then(b).then(c);
-  ///
-  /// where f is a Future<A> and the result of the chain is a Future<Z>
-  /// becomes
-  ///
-  ///   f.then(chain<A,Z>(a, b, c));
-  // If anyone figures how to get chain to deduce A and Z, I'll buy you a drink.
-  template <class A, class Z, class... Callbacks>
-  std::function<Future<Z>(Try<A>)>
-  chain(Callbacks... fns);
-
-  /**
-   * Set func as the callback for each input Future and return a vector of
-   * Futures containing the results in the input order.
-   */
-  template <class It, class F,
-            class ItT = typename std::iterator_traits<It>::value_type,
-            class Result = decltype(std::declval<ItT>().then(std::declval<F>()))>
-  std::vector<Future<Result>> map(It first, It last, F func);
-
-  // Sugar for the most common case
-  template <class Collection, class F>
-  auto map(Collection&& c, F&& func)
-      -> decltype(map(c.begin(), c.end(), func)) {
-    return map(c.begin(), c.end(), std::forward<F>(func));
-  }
-
-}
+namespace folly {
 
 template <class T>
 class Future {
@@ -562,181 +403,6 @@ class Future {
   void setExecutor(Executor* x) { core_->setExecutor(x); }
 };
 
-/**
-  Make a completed Future by moving in a value. e.g.
-
-    string foo = "foo";
-    auto f = makeFuture(std::move(foo));
-
-  or
-
-    auto f = makeFuture<string>("foo");
-*/
-template <class T>
-Future<typename std::decay<T>::type> makeFuture(T&& t);
-
-/** Make a completed void Future. */
-Future<void> makeFuture();
-
-/** Make a completed Future by executing a function. If the function throws
-  we capture the exception, otherwise we capture the result. */
-template <class F>
-auto makeFutureWith(
-  F&& func,
-  typename std::enable_if<
-    !std::is_reference<F>::value, bool>::type sdf = false)
-  -> Future<decltype(func())>;
-
-template <class F>
-auto makeFutureWith(
-  F const& func)
-  -> Future<decltype(func())>;
-
-/// Make a failed Future from an exception_ptr.
-/// Because the Future's type cannot be inferred you have to specify it, e.g.
-///
-///   auto f = makeFuture<string>(std::current_exception());
-template <class T>
-Future<T> makeFuture(std::exception_ptr const& e) DEPRECATED;
-
-/// Make a failed Future from an exception_wrapper.
-template <class T>
-Future<T> makeFuture(exception_wrapper ew);
-
-/** Make a Future from an exception type E that can be passed to
-  std::make_exception_ptr(). */
-template <class T, class E>
-typename std::enable_if<std::is_base_of<std::exception, E>::value,
-                        Future<T>>::type
-makeFuture(E const& e);
-
-/** Make a Future out of a Try */
-template <class T>
-Future<T> makeFuture(Try<T>&& t);
-
-/*
- * Return a new Future that will call back on the given Executor.
- * This is just syntactic sugar for makeFuture().via(executor)
- *
- * @param executor the Executor to call back on
- *
- * @returns a void Future that will call back on the given executor
- */
-template <typename Executor>
-Future<void> via(Executor* executor);
-
-/** When all the input Futures complete, the returned Future will complete.
-  Errors do not cause early termination; this Future will always succeed
-  after all its Futures have finished (whether successfully or with an
-  error).
-
-  The Futures are moved in, so your copies are invalid. If you need to
-  chain further from these Futures, use the variant with an output iterator.
-
-  This function is thread-safe for Futures running on different threads. But
-  if you are doing anything non-trivial after, you will probably want to
-  follow with `via(executor)` because it will complete in whichever thread the
-  last Future completes in.
-
-  The return type for Future<T> input is a Future<std::vector<Try<T>>>
-  */
-template <class InputIterator>
-Future<std::vector<Try<
-  typename std::iterator_traits<InputIterator>::value_type::value_type>>>
-collectAll(InputIterator first, InputIterator last);
-
-// Sugar for the most common case
-template <class Collection>
-auto collectAll(Collection&& c) -> decltype(collectAll(c.begin(), c.end())) {
-  return collectAll(c.begin(), c.end());
-}
-
-/// This version takes a varying number of Futures instead of an iterator.
-/// The return type for (Future<T1>, Future<T2>, ...) input
-/// is a Future<std::tuple<Try<T1>, Try<T2>, ...>>.
-/// The Futures are moved in, so your copies are invalid.
-template <typename... Fs>
-typename detail::VariadicContext<
-  typename std::decay<Fs>::type::value_type...>::type
-collectAll(Fs&&... fs);
-
-/// Like collectAll, but will short circuit on the first exception. Thus, the
-/// type of the returned Future is std::vector<T> instead of
-/// std::vector<Try<T>>
-template <class InputIterator>
-Future<typename detail::CollectContext<
-  typename std::iterator_traits<InputIterator>::value_type::value_type
->::result_type>
-collect(InputIterator first, InputIterator last);
-
-// Sugar for the most common case
-template <class Collection>
-auto collect(Collection&& c) -> decltype(collect(c.begin(), c.end())) {
-  return collect(c.begin(), c.end());
-}
-
-/** The result is a pair of the index of the first Future to complete and
-  the Try. If multiple Futures complete at the same time (or are already
-  complete when passed in), the "winner" is chosen non-deterministically.
-
-  This function is thread-safe for Futures running on different threads.
-  */
-template <class InputIterator>
-Future<std::pair<
-  size_t,
-  Try<typename std::iterator_traits<InputIterator>::value_type::value_type>>>
-collectAny(InputIterator first, InputIterator last);
-
-// Sugar for the most common case
-template <class Collection>
-auto collectAny(Collection&& c) -> decltype(collectAny(c.begin(), c.end())) {
-  return collectAny(c.begin(), c.end());
-}
-
-/** when n Futures have completed, the Future completes with a vector of
-  the index and Try of those n Futures (the indices refer to the original
-  order, but the result vector will be in an arbitrary order)
-
-  Not thread safe.
-  */
-template <class InputIterator>
-Future<std::vector<std::pair<
-  size_t,
-  Try<typename std::iterator_traits<InputIterator>::value_type::value_type>>>>
-collectN(InputIterator first, InputIterator last, size_t n);
-
-// Sugar for the most common case
-template <class Collection>
-auto collectN(Collection&& c, size_t n)
-    -> decltype(collectN(c.begin(), c.end(), n)) {
-  return collectN(c.begin(), c.end(), n);
-}
-
-template <typename F, typename T, typename ItT>
-using MaybeTryArg = typename std::conditional<
-  detail::callableWith<F, T&&, Try<ItT>&&>::value, Try<ItT>, ItT>::type;
-
-template<typename F, typename T, typename Arg>
-using isFutureResult = isFuture<typename std::result_of<F(T&&, Arg&&)>::type>;
-
-/** repeatedly calls func on every result, e.g.
-    reduce(reduce(reduce(T initial, result of first), result of second), ...)
-
-    The type of the final result is a Future of the type of the initial value.
-
-    Func can either return a T, or a Future<T>
-  */
-template <class It, class T, class F,
-          class ItT = typename std::iterator_traits<It>::value_type::value_type,
-          class Arg = MaybeTryArg<F, T, ItT>>
-typename std::enable_if<!isFutureResult<F, T, Arg>::value, Future<T>>::type
-reduce(It first, It last, T initial, F func);
-
-template <class It, class T, class F,
-          class ItT = typename std::iterator_traits<It>::value_type::value_type,
-          class Arg = MaybeTryArg<F, T, ItT>>
-typename std::enable_if<isFutureResult<F, T, Arg>::value, Future<T>>::type
-reduce(It first, It last, T initial, F func);
 
 // Sugar for the most common case
 template <class Collection, class T, class F>
diff --git a/folly/futures/helpers.h b/folly/futures/helpers.h
new file mode 100644 (file)
index 0000000..138cfd4
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * Copyright 2015 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <folly/futures/Future.h>
+
+namespace folly {
+
+/// This namespace is for utility functions that would usually be static
+/// members of Future, except they don't make sense there because they don't
+/// depend on the template type (rather, on the type of their arguments in
+/// some cases). This is the least-bad naming scheme we could think of. Some
+/// of the functions herein have really-likely-to-collide names, like "map"
+/// and "sleep".
+namespace futures {
+  /// Returns a Future that will complete after the specified duration. The
+  /// Duration typedef of a `std::chrono` duration type indicates the
+  /// resolution you can expect to be meaningful (milliseconds at the time of
+  /// writing). Normally you wouldn't need to specify a Timekeeper, we will
+  /// use the global futures timekeeper (we run a thread whose job it is to
+  /// keep time for futures timeouts) but we provide the option for power
+  /// users.
+  ///
+  /// The Timekeeper thread will be lazily created the first time it is
+  /// needed. If your program never uses any timeouts or other time-based
+  /// Futures you will pay no Timekeeper thread overhead.
+  Future<void> sleep(Duration, Timekeeper* = nullptr);
+
+  /// Create a Future chain from a sequence of callbacks. i.e.
+  ///
+  ///   f.then(a).then(b).then(c);
+  ///
+  /// where f is a Future<A> and the result of the chain is a Future<Z>
+  /// becomes
+  ///
+  ///   f.then(chain<A,Z>(a, b, c));
+  // If anyone figures how to get chain to deduce A and Z, I'll buy you a drink.
+  template <class A, class Z, class... Callbacks>
+  std::function<Future<Z>(Try<A>)>
+  chain(Callbacks... fns);
+
+  /**
+   * Set func as the callback for each input Future and return a vector of
+   * Futures containing the results in the input order.
+   */
+  template <class It, class F,
+            class ItT = typename std::iterator_traits<It>::value_type,
+            class Result = decltype(std::declval<ItT>().then(std::declval<F>()))>
+  std::vector<Future<Result>> map(It first, It last, F func);
+
+  // Sugar for the most common case
+  template <class Collection, class F>
+  auto map(Collection&& c, F&& func)
+      -> decltype(map(c.begin(), c.end(), func)) {
+    return map(c.begin(), c.end(), std::forward<F>(func));
+  }
+
+}
+
+/**
+  Make a completed Future by moving in a value. e.g.
+
+    string foo = "foo";
+    auto f = makeFuture(std::move(foo));
+
+  or
+
+    auto f = makeFuture<string>("foo");
+*/
+template <class T>
+Future<typename std::decay<T>::type> makeFuture(T&& t);
+
+/** Make a completed void Future. */
+Future<void> makeFuture();
+
+/** Make a completed Future by executing a function. If the function throws
+  we capture the exception, otherwise we capture the result. */
+template <class F>
+auto makeFutureWith(
+  F&& func,
+  typename std::enable_if<
+    !std::is_reference<F>::value, bool>::type sdf = false)
+  -> Future<decltype(func())>;
+
+template <class F>
+auto makeFutureWith(
+  F const& func)
+  -> Future<decltype(func())>;
+
+/// Make a failed Future from an exception_ptr.
+/// Because the Future's type cannot be inferred you have to specify it, e.g.
+///
+///   auto f = makeFuture<string>(std::current_exception());
+template <class T>
+Future<T> makeFuture(std::exception_ptr const& e) DEPRECATED;
+
+/// Make a failed Future from an exception_wrapper.
+template <class T>
+Future<T> makeFuture(exception_wrapper ew);
+
+/** Make a Future from an exception type E that can be passed to
+  std::make_exception_ptr(). */
+template <class T, class E>
+typename std::enable_if<std::is_base_of<std::exception, E>::value,
+                        Future<T>>::type
+makeFuture(E const& e);
+
+/** Make a Future out of a Try */
+template <class T>
+Future<T> makeFuture(Try<T>&& t);
+
+/*
+ * Return a new Future that will call back on the given Executor.
+ * This is just syntactic sugar for makeFuture().via(executor)
+ *
+ * @param executor the Executor to call back on
+ *
+ * @returns a void Future that will call back on the given executor
+ */
+template <typename Executor>
+Future<void> via(Executor* executor);
+
+/** When all the input Futures complete, the returned Future will complete.
+  Errors do not cause early termination; this Future will always succeed
+  after all its Futures have finished (whether successfully or with an
+  error).
+
+  The Futures are moved in, so your copies are invalid. If you need to
+  chain further from these Futures, use the variant with an output iterator.
+
+  This function is thread-safe for Futures running on different threads. But
+  if you are doing anything non-trivial after, you will probably want to
+  follow with `via(executor)` because it will complete in whichever thread the
+  last Future completes in.
+
+  The return type for Future<T> input is a Future<std::vector<Try<T>>>
+  */
+template <class InputIterator>
+Future<std::vector<Try<
+  typename std::iterator_traits<InputIterator>::value_type::value_type>>>
+collectAll(InputIterator first, InputIterator last);
+
+// Sugar for the most common case
+template <class Collection>
+auto collectAll(Collection&& c) -> decltype(collectAll(c.begin(), c.end())) {
+  return collectAll(c.begin(), c.end());
+}
+
+/// This version takes a varying number of Futures instead of an iterator.
+/// The return type for (Future<T1>, Future<T2>, ...) input
+/// is a Future<std::tuple<Try<T1>, Try<T2>, ...>>.
+/// The Futures are moved in, so your copies are invalid.
+template <typename... Fs>
+typename detail::VariadicContext<
+  typename std::decay<Fs>::type::value_type...>::type
+collectAll(Fs&&... fs);
+
+/// Like collectAll, but will short circuit on the first exception. Thus, the
+/// type of the returned Future is std::vector<T> instead of
+/// std::vector<Try<T>>
+template <class InputIterator>
+Future<typename detail::CollectContext<
+  typename std::iterator_traits<InputIterator>::value_type::value_type
+>::result_type>
+collect(InputIterator first, InputIterator last);
+
+// Sugar for the most common case
+template <class Collection>
+auto collect(Collection&& c) -> decltype(collect(c.begin(), c.end())) {
+  return collect(c.begin(), c.end());
+}
+
+/** The result is a pair of the index of the first Future to complete and
+  the Try. If multiple Futures complete at the same time (or are already
+  complete when passed in), the "winner" is chosen non-deterministically.
+
+  This function is thread-safe for Futures running on different threads.
+  */
+template <class InputIterator>
+Future<std::pair<
+  size_t,
+  Try<typename std::iterator_traits<InputIterator>::value_type::value_type>>>
+collectAny(InputIterator first, InputIterator last);
+
+// Sugar for the most common case
+template <class Collection>
+auto collectAny(Collection&& c) -> decltype(collectAny(c.begin(), c.end())) {
+  return collectAny(c.begin(), c.end());
+}
+
+/** when n Futures have completed, the Future completes with a vector of
+  the index and Try of those n Futures (the indices refer to the original
+  order, but the result vector will be in an arbitrary order)
+
+  Not thread safe.
+  */
+template <class InputIterator>
+Future<std::vector<std::pair<
+  size_t,
+  Try<typename std::iterator_traits<InputIterator>::value_type::value_type>>>>
+collectN(InputIterator first, InputIterator last, size_t n);
+
+// Sugar for the most common case
+template <class Collection>
+auto collectN(Collection&& c, size_t n)
+    -> decltype(collectN(c.begin(), c.end(), n)) {
+  return collectN(c.begin(), c.end(), n);
+}
+
+template <typename F, typename T, typename ItT>
+using MaybeTryArg = typename std::conditional<
+  detail::callableWith<F, T&&, Try<ItT>&&>::value, Try<ItT>, ItT>::type;
+
+template<typename F, typename T, typename Arg>
+using isFutureResult = isFuture<typename std::result_of<F(T&&, Arg&&)>::type>;
+
+/** repeatedly calls func on every result, e.g.
+    reduce(reduce(reduce(T initial, result of first), result of second), ...)
+
+    The type of the final result is a Future of the type of the initial value.
+
+    Func can either return a T, or a Future<T>
+  */
+template <class It, class T, class F,
+          class ItT = typename std::iterator_traits<It>::value_type::value_type,
+          class Arg = MaybeTryArg<F, T, ItT>>
+typename std::enable_if<!isFutureResult<F, T, Arg>::value, Future<T>>::type
+reduce(It first, It last, T initial, F func);
+
+template <class It, class T, class F,
+          class ItT = typename std::iterator_traits<It>::value_type::value_type,
+          class Arg = MaybeTryArg<F, T, ItT>>
+typename std::enable_if<isFutureResult<F, T, Arg>::value, Future<T>>::type
+reduce(It first, It last, T initial, F func);
+
+} // namespace folly