explicit instantiation of common Future types
[folly.git] / folly / futures / Future-inl.h
index 927a3142b8ed94a056b3d3f8beac50359d039878..33b758ea2db126692601b62850a9a5ca9a2a035d 100644 (file)
@@ -226,18 +226,17 @@ Future<T>::then(R(Caller::*func)(Args...), Caller *instance) {
   });
 }
 
-// TODO(6838553)
-#ifndef __clang__
 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);
-  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>
 Future<void> Future<T>::then() {
@@ -424,7 +423,6 @@ Optional<Try<T>> Future<T>::poll() {
 }
 
 template <class T>
-template <typename Executor>
 inline Future<T> Future<T>::via(Executor* executor) && {
   throwIfInvalid();
 
@@ -434,7 +432,6 @@ inline Future<T> Future<T>::via(Executor* executor) && {
 }
 
 template <class T>
-template <typename Executor>
 inline Future<T> Future<T>::via(Executor* executor) & {
   throwIfInvalid();
 
@@ -530,8 +527,7 @@ inline Future<void> makeFuture(Try<void>&& t) {
 }
 
 // via
-template <typename Executor>
-Future<void> via(Executor* executor) {
+inline Future<void> via(Executor* executor) {
   return makeFuture().via(executor);
 }
 
@@ -620,13 +616,13 @@ struct CollectContext {
     Optional<T>
    >::type VecT;
 
-  explicit CollectContext(int n) : count(0), threw(false) {
+  explicit CollectContext(int n) : count(0), success_count(0), threw(false) {
     results.resize(n);
   }
 
   Promise<std::vector<T>> p;
   std::vector<VecT> results;
-  std::atomic<size_t> count;
+  std::atomic<size_t> count, success_count;
   std::atomic_bool threw;
 
   typedef std::vector<T> result_type;
@@ -647,10 +643,10 @@ struct CollectContext {
 template <>
 struct CollectContext<void> {
 
-  explicit CollectContext(int n) : count(0), threw(false) {}
+  explicit CollectContext(int n) : count(0), success_count(0), threw(false) {}
 
   Promise<void> p;
-  std::atomic<size_t> count;
+  std::atomic<size_t> count, success_count;
   std::atomic_bool threw;
 
   typedef void result_type;
@@ -690,7 +686,6 @@ collect(InputIterator first, InputIterator last) {
      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)) {
@@ -698,12 +693,12 @@ collect(InputIterator first, InputIterator last) {
          }
        } else if (!ctx->threw) {
          ctx->addResult(i, t);
-         if (c == n) {
+         if (++ctx->success_count == n) {
            ctx->setValue();
          }
        }
 
-       if (c == n) {
+       if (++ctx->count == n) {
          delete ctx;
        }
      });
@@ -783,44 +778,28 @@ collectN(InputIterator first, InputIterator last, size_t n) {
   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) {
+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));
   }
 
+  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;
 
-  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;
-    });
-}
+  folly::MoveWrapper<T> minitial(std::move(initial));
+  auto sfunc = std::make_shared<F>(std::move(func));
 
-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) {
-  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),
+  auto f = first->then([minitial, 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([func](std::tuple<Try<T>, Try<ItT>>& t) {
-      return func(std::move(std::get<0>(t).value()),
+    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&&>());
@@ -830,6 +809,20 @@ reduce(It first, It last, T initial, F func) {
   return f;
 }
 
+template <class T>
+template <class I, class F>
+Future<I> Future<T>::reduce(I&& initial, F&& func) {
+  folly::MoveWrapper<I> minitial(std::move(initial));
+  folly::MoveWrapper<F> mfunc(std::move(func));
+  return then([minitial, mfunc](T& vals) mutable {
+    auto ret = std::move(*minitial);
+    for (auto& val : vals) {
+      ret = (*mfunc)(std::move(ret), std::move(val));
+    }
+    return ret;
+  });
+}
+
 template <class T>
 Future<T> Future<T>::within(Duration dur, Timekeeper* tk) {
   return within(dur, TimedOut(), tk);
@@ -1008,11 +1001,27 @@ 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 <>
+  struct TryEquals<void> {
+    static bool equals(const Try<void>& t1, const Try<void>& t2) {
+      return true;
+    }
+  };
+}
+
 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;
       }
@@ -1066,6 +1075,14 @@ namespace futures {
   }
 }
 
+// Instantiate the most common Future types to save compile time
+extern template class Future<void>;
+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
 
 // I haven't included a Future<T&> specialization because I don't forsee us