Promise<T>::makeEmpty() and Future<T>::makeEmpty()
[folly.git] / folly / futures / Future-inl.h
index 2a8b56b888084e1b89175164d1430fab6ebfab75..ab70c38d7bd436fdf8bc8253f0ed5320640320d9 100644 (file)
@@ -24,7 +24,6 @@
 #include <folly/Baton.h>
 #include <folly/Optional.h>
 #include <folly/Random.h>
-#include <folly/Traits.h>
 #include <folly/futures/detail/Core.h>
 #include <folly/futures/Timekeeper.h>
 
@@ -112,7 +111,7 @@ class CoreCallbackState {
   union {
     F func_;
   };
-  Promise<T> promise_{detail::EmptyConstruct{}};
+  Promise<T> promise_{Promise<T>::makeEmpty()};
 };
 
 template <typename T, typename F>
@@ -125,6 +124,11 @@ inline auto makeCoreCallbackState(Promise<T>&& p, F&& f) noexcept(
 }
 }
 
+template <class T>
+Future<T> Future<T>::makeEmpty() {
+  return Future<T>(detail::EmptyConstruct{});
+}
+
 template <class T>
 Future<T>::Future(Future<T>&& other) noexcept : core_(other.core_) {
   other.core_ = nullptr;
@@ -136,6 +140,40 @@ Future<T>& Future<T>::operator=(Future<T>&& other) noexcept {
   return *this;
 }
 
+template <class T>
+template <
+    class T2,
+    typename std::enable_if<
+        !std::is_same<T, typename std::decay<T2>::type>::value &&
+            std::is_constructible<T, T2&&>::value &&
+            std::is_convertible<T2&&, T>::value,
+        int>::type>
+Future<T>::Future(Future<T2>&& other)
+    : Future(std::move(other).then([](T2&& v) { return T(std::move(v)); })) {}
+
+template <class T>
+template <
+    class T2,
+    typename std::enable_if<
+        !std::is_same<T, typename std::decay<T2>::type>::value &&
+            std::is_constructible<T, T2&&>::value &&
+            !std::is_convertible<T2&&, T>::value,
+        int>::type>
+Future<T>::Future(Future<T2>&& other)
+    : Future(std::move(other).then([](T2&& v) { return T(std::move(v)); })) {}
+
+template <class T>
+template <
+    class T2,
+    typename std::enable_if<
+        !std::is_same<T, typename std::decay<T2>::type>::value &&
+            std::is_constructible<T, T2&&>::value,
+        int>::type>
+Future<T>& Future<T>::operator=(Future<T2>&& other) {
+  return operator=(
+      std::move(other).then([](T2&& v) { return T(std::move(v)); }));
+}
+
 template <class T>
 template <class T2, typename>
 Future<T>::Future(T2&& val)
@@ -297,18 +335,6 @@ Future<T>::then(R(Caller::*func)(Args...), Caller *instance) {
   });
 }
 
-template <class T>
-template <class Executor, class Arg, class... Args>
-auto Future<T>::then(Executor* x, Arg&& arg, Args&&... args)
-  -> decltype(this->then(std::forward<Arg>(arg),
-                         std::forward<Args>(args)...))
-{
-  auto oldX = getExecutor();
-  setExecutor(x);
-  return this->then(std::forward<Arg>(arg), std::forward<Args>(args)...).
-               via(oldX);
-}
-
 template <class T>
 Future<Unit> Future<T>::then() {
   return then([] () {});
@@ -538,6 +564,10 @@ void Future<T>::raise(exception_wrapper exception) {
   core_->raise(std::move(exception));
 }
 
+template <class T>
+Future<T>::Future(detail::EmptyConstruct) noexcept
+    : core_(nullptr) {}
+
 // makeFuture
 
 template <class T>
@@ -1181,46 +1211,6 @@ Future<T> Future<T>::filter(F&& predicate) {
   });
 }
 
-template <class T>
-template <class Callback>
-auto Future<T>::thenMulti(Callback&& fn)
-    -> decltype(this->then(std::forward<Callback>(fn))) {
-  // thenMulti with one callback is just a then
-  return then(std::forward<Callback>(fn));
-}
-
-template <class T>
-template <class Callback, class... Callbacks>
-auto Future<T>::thenMulti(Callback&& fn, Callbacks&&... fns)
-    -> decltype(this->then(std::forward<Callback>(fn)).
-                      thenMulti(std::forward<Callbacks>(fns)...)) {
-  // thenMulti with two callbacks is just then(a).thenMulti(b, ...)
-  return then(std::forward<Callback>(fn)).
-         thenMulti(std::forward<Callbacks>(fns)...);
-}
-
-template <class T>
-template <class Callback, class... Callbacks>
-auto Future<T>::thenMultiWithExecutor(Executor* x, Callback&& fn,
-                                      Callbacks&&... fns)
-    -> decltype(this->then(std::forward<Callback>(fn)).
-                      thenMulti(std::forward<Callbacks>(fns)...)) {
-  // thenMultiExecutor with two callbacks is
-  // via(x).then(a).thenMulti(b, ...).via(oldX)
-  auto oldX = getExecutor();
-  setExecutor(x);
-  return then(std::forward<Callback>(fn)).
-         thenMulti(std::forward<Callbacks>(fns)...).via(oldX);
-}
-
-template <class T>
-template <class Callback>
-auto Future<T>::thenMultiWithExecutor(Executor* x, Callback&& fn)
-    -> decltype(this->then(std::forward<Callback>(fn))) {
-  // thenMulti with one callback is just a then with an executor
-  return then(x, std::forward<Callback>(fn));
-}
-
 template <class F>
 inline Future<Unit> when(bool p, F&& thunk) {
   return p ? std::forward<F>(thunk)().unit() : makeFuture();
@@ -1269,14 +1259,9 @@ 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 result = std::result_of_t<Policy(size_t, const exception_wrapper&)>;
+  using is_raw = std::is_same<result, bool>;
+  using is_fut = std::is_same<result, 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;