Make consistent set of get and getTry methods on SemiFuture.
[folly.git] / folly / futures / Future-inl.h
index 1baee146817ac679e9c72c210c5ff312c8cd8df7..56b98410abcfe59d24cfcdbe89caecf08a0d8ba2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017 Facebook, Inc.
+ * Copyright 2017-present Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,7 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 #pragma once
 
 #include <algorithm>
 #include <chrono>
 #include <thread>
 
-#include <folly/Baton.h>
 #include <folly/Optional.h>
 #include <folly/executors/InlineExecutor.h>
 #include <folly/futures/Timekeeper.h>
 #include <folly/futures/detail/Core.h>
+#include <folly/synchronization/Baton.h>
 
 #ifndef FOLLY_FUTURE_USING_FIBER
 #if FOLLY_MOBILE || defined(__APPLE__)
@@ -174,30 +173,50 @@ FutureBase<T>::~FutureBase() {
 
 template <class T>
 T& FutureBase<T>::value() & {
+  return result().value();
+}
+
+template <class T>
+T const& FutureBase<T>::value() const& {
+  return result().value();
+}
+
+template <class T>
+T&& FutureBase<T>::value() && {
+  return std::move(result().value());
+}
+
+template <class T>
+T const&& FutureBase<T>::value() const&& {
+  return std::move(result().value());
+}
+
+template <class T>
+Try<T>& FutureBase<T>::result() & {
   throwIfInvalid();
 
-  return core_->getTry().value();
+  return core_->getTry();
 }
 
 template <class T>
-T const& FutureBase<T>::value() const& {
+Try<T> const& FutureBase<T>::result() const& {
   throwIfInvalid();
 
-  return core_->getTry().value();
+  return core_->getTry();
 }
 
 template <class T>
-T&& FutureBase<T>::value() && {
+Try<T>&& FutureBase<T>::result() && {
   throwIfInvalid();
 
-  return std::move(core_->getTry().value());
+  return std::move(core_->getTry());
 }
 
 template <class T>
-T const&& FutureBase<T>::value() const&& {
+Try<T> const&& FutureBase<T>::result() const&& {
   throwIfInvalid();
 
-  return std::move(core_->getTry().value());
+  return std::move(core_->getTry());
 }
 
 template <class T>
@@ -208,12 +227,12 @@ bool FutureBase<T>::isReady() const {
 
 template <class T>
 bool FutureBase<T>::hasValue() {
-  return getTry().hasValue();
+  return core_->getTry().hasValue();
 }
 
 template <class T>
 bool FutureBase<T>::hasException() {
-  return getTry().hasException();
+  return core_->getTry().hasException();
 }
 
 template <class T>
@@ -224,13 +243,6 @@ void FutureBase<T>::detach() {
   }
 }
 
-template <class T>
-Try<T>& FutureBase<T>::getTry() {
-  throwIfInvalid();
-
-  return core_->getTry();
-}
-
 template <class T>
 void FutureBase<T>::throwIfInvalid() const {
   if (!core_) {
@@ -473,7 +485,7 @@ void SemiFuture<T>::boost_() {
   if (auto e = this->getExecutor()) {
     // We know in a SemiFuture that if we have an executor it should be
     // DeferredExecutor. Verify this in debug mode.
-    DCHECK(dynamic_cast<DeferredExecutor*>(e));
+    DCHECK(nullptr != dynamic_cast<DeferredExecutor*>(e));
 
     auto ka = static_cast<DeferredExecutor*>(e)->getKeepAliveToken();
     static_cast<DeferredExecutor*>(e)->boost();
@@ -483,6 +495,9 @@ void SemiFuture<T>::boost_() {
 template <class T>
 inline Future<T> SemiFuture<T>::via(Executor* executor, int8_t priority) && {
   throwIfInvalid();
+  if (!executor) {
+    throwNoExecutor();
+  }
 
   // If current executor is deferred, boost block to ensure that work
   // progresses and is run on the new executor.
@@ -490,7 +505,7 @@ inline Future<T> SemiFuture<T>::via(Executor* executor, int8_t priority) && {
   if (oldExecutor && executor && (executor != oldExecutor)) {
     // We know in a SemiFuture that if we have an executor it should be
     // DeferredExecutor. Verify this in debug mode.
-    DCHECK(dynamic_cast<DeferredExecutor*>(this->getExecutor()));
+    DCHECK(nullptr != dynamic_cast<DeferredExecutor*>(this->getExecutor()));
     if (static_cast<DeferredExecutor*>(oldExecutor)) {
       executor->add([oldExecutorKA = oldExecutor->getKeepAliveToken()]() {
         static_cast<DeferredExecutor*>(oldExecutorKA.get())->boost();
@@ -517,13 +532,13 @@ SemiFuture<T>::defer(F&& func) && {
   // We know in a SemiFuture that if we have an executor it should be
   // DeferredExecutor (either it was that way before, or we just created it).
   // Verify this in debug mode.
-  DCHECK(dynamic_cast<DeferredExecutor*>(e));
+  DCHECK(nullptr != dynamic_cast<DeferredExecutor*>(e));
   // Convert to a folly::future with a deferred executor
   // Will be low-cost if this is not a new executor as via optimises for that
   // case
   auto sf =
       std::move(*this)
-          .via(defKeepAlive.get())
+          .via(e)
           // Then add the work, with a wrapper function that captures the
           // keepAlive so the executor is destroyed at the right time.
           .then(
@@ -792,11 +807,6 @@ Future<T>::onError(F&& func) {
   return f;
 }
 
-template <class T>
-Try<T>& Future<T>::getTryVia(DrivableExecutor* e) {
-  return waitVia(e).getTry();
-}
-
 template <class Func>
 auto via(Executor* x, Func&& func)
     -> Future<typename isFuture<decltype(std::declval<Func>()())>::Inner> {
@@ -1376,7 +1386,7 @@ void waitImpl(FutureType& f, Duration dur) {
   });
   doBoost(f);
   f = std::move(ret);
-  if (baton->timed_wait(dur)) {
+  if (baton->try_wait_for(dur)) {
     assert(f.isReady());
   }
 }
@@ -1396,6 +1406,21 @@ void waitViaImpl(Future<T>& f, DrivableExecutor* e) {
   assert(f.isReady());
 }
 
+template <class T>
+void waitViaImpl(SemiFuture<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 = std::move(f).via(e).then([](T&& t) { return std::move(t); });
+  while (!f.isReady()) {
+    e->drive();
+  }
+  assert(f.isReady());
+}
+
 } // namespace detail
 } // namespace futures
 
@@ -1423,9 +1448,21 @@ SemiFuture<T>&& SemiFuture<T>::wait(Duration dur) && {
   return std::move(*this);
 }
 
+template <class T>
+SemiFuture<T>& SemiFuture<T>::waitVia(DrivableExecutor* e) & {
+  futures::detail::waitViaImpl(*this, e);
+  return *this;
+}
+
+template <class T>
+SemiFuture<T>&& SemiFuture<T>::waitVia(DrivableExecutor* e) && {
+  futures::detail::waitViaImpl(*this, e);
+  return std::move(*this);
+}
+
 template <class T>
 T SemiFuture<T>::get() && {
-  return std::move(wait().value());
+  return std::move(wait()).value();
 }
 
 template <class T>
@@ -1438,6 +1475,31 @@ T SemiFuture<T>::get(Duration dur) && {
   }
 }
 
+template <class T>
+Try<T> SemiFuture<T>::getTry() && {
+  return std::move(wait()).result();
+}
+
+template <class T>
+Try<T> SemiFuture<T>::getTry(Duration dur) && {
+  wait(dur);
+  if (this->isReady()) {
+    return std::move(this->result());
+  } else {
+    throwTimedOut();
+  }
+}
+
+template <class T>
+T SemiFuture<T>::getVia(DrivableExecutor* e) && {
+  return std::move(waitVia(e)).value();
+}
+
+template <class T>
+Try<T> SemiFuture<T>::getTryVia(DrivableExecutor* e) && {
+  return std::move(waitVia(e)).result();
+}
+
 template <class T>
 Future<T>& Future<T>::wait() & {
   futures::detail::waitImpl(*this);
@@ -1489,11 +1551,21 @@ T Future<T>::get(Duration dur) {
   }
 }
 
+template <class T>
+Try<T>& Future<T>::getTry() {
+  return result();
+}
+
 template <class T>
 T Future<T>::getVia(DrivableExecutor* e) {
   return std::move(waitVia(e).value());
 }
 
+template <class T>
+Try<T>& Future<T>::getTryVia(DrivableExecutor* e) {
+  return waitVia(e).getTry();
+}
+
 namespace futures {
 namespace detail {
 template <class T>