Make folly pass TSAN checks
[folly.git] / folly / futures / Future.h
index 40687b42b4f5cc7deb7dabcf7ace69105ad42e91..2acc1b94cd85cff51b0dbb17c841a45fba6995a6 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.
 #include <vector>
 
 #include <folly/Optional.h>
-#include <folly/MoveWrapper.h>
-#include <folly/futures/Deprecated.h>
+#include <folly/Portability.h>
 #include <folly/futures/DrivableExecutor.h>
 #include <folly/futures/Promise.h>
-#include <folly/futures/Try.h>
+#include <folly/Try.h>
 #include <folly/futures/FutureException.h>
 #include <folly/futures/detail/Types.h>
 
@@ -60,11 +59,9 @@ class Future {
               !isFuture<typename std::decay<T2>::type>::value>::type>
   /* implicit */ Future(T2&& val);
 
-  template <class T2 = T,
-            typename std::enable_if<
-              folly::is_void_or_unit<T2>::value,
-              int>::type = 0>
-  Future();
+  template <class T2 = T>
+  /* implicit */ Future(
+      typename std::enable_if<std::is_same<Unit, T2>::value>::type* = nullptr);
 
   ~Future();
 
@@ -111,9 +108,20 @@ class Future {
   /** True when the result (or exception) is ready. */
   bool isReady() const;
 
+  /// sugar for getTry().hasValue()
+  bool hasValue();
+
+  /// sugar for getTry().hasException()
+  bool hasException();
+
   /** A reference to the Try of the value */
   Try<T>& getTry();
 
+  /// Call e->drive() repeatedly until the future is fulfilled. Examples
+  /// of DrivableExecutor include EventBase and ManualExecutor. Returns a
+  /// reference to the Try of the value.
+  Try<T>& getTryVia(DrivableExecutor* e);
+
   /// If the promise has been fulfilled, return an Optional with the Try<T>.
   /// Otherwise return an empty Optional.
   /// Note that this moves the Try<T> out.
@@ -160,14 +168,19 @@ class Future {
     value(), which may rethrow if this has captured an exception. If func
     throws, the exception will be captured in the Future that is returned.
     */
-  /* TODO n3428 and other async frameworks have something like then(scheduler,
-     Future), we might want to support a similar API which could be
-     implemented a little more efficiently than
-     f.via(executor).then(callback) */
-  template <typename F, typename R = detail::callableResult<T, F>>
-  typename R::Return then(F func) {
+  // gcc 4.8 requires that we cast function reference types to function pointer
+  // types. Fore more details see the comment on FunctionReferenceToPointer
+  // in Future-pre.h.
+  // gcc versions 4.9 and above (as well as clang) do not require this hack.
+  // For those, the FF tenplate parameter can be removed and occurences of FF
+  // replaced with F.
+  template <
+      typename F,
+      typename FF = typename detail::FunctionReferenceToPointer<F>::type,
+      typename R = detail::callableResult<T, FF>>
+  typename R::Return then(F&& func) {
     typedef typename R::Arg Arguments;
-    return thenImplementation<F, R>(std::move(func), Arguments());
+    return thenImplementation<FF, R>(std::forward<FF>(func), Arguments());
   }
 
   /// Variant where func is an member function
@@ -201,9 +214,9 @@ class Future {
     -> decltype(this->then(std::forward<Arg>(arg),
                            std::forward<Args>(args)...));
 
-  /// Convenience method for ignoring the value and creating a Future<void>.
+  /// Convenience method for ignoring the value and creating a Future<Unit>.
   /// Exceptions still propagate.
-  Future<void> then();
+  Future<Unit> then();
 
   /// Set an error callback for this Future. The callback should take a single
   /// argument of the type that you want to catch, and should return a value of
@@ -255,7 +268,7 @@ class Future {
   /// func shouldn't throw, but if it does it will be captured and propagated,
   /// and discard any value/exception that this Future has obtained.
   template <class F>
-  Future<T> ensure(F func);
+  Future<T> ensure(F&& func);
 
   /// Like onError, but for timeouts. example:
   ///
@@ -286,19 +299,19 @@ class Future {
   /// by then), and it is active (active by default).
   ///
   /// Inactive Futures will activate upon destruction.
-  Future<T>& activate() & DEPRECATED {
+  FOLLY_DEPRECATED("do not use") Future<T>& activate() & {
     core_->activate();
     return *this;
   }
-  Future<T>& deactivate() & DEPRECATED {
+  FOLLY_DEPRECATED("do not use") Future<T>& deactivate() & {
     core_->deactivate();
     return *this;
   }
-  Future<T> activate() && DEPRECATED {
+  FOLLY_DEPRECATED("do not use") Future<T> activate() && {
     core_->activate();
     return std::move(*this);
   }
-  Future<T> deactivate() && DEPRECATED {
+  FOLLY_DEPRECATED("do not use") Future<T> deactivate() && {
     core_->deactivate();
     return std::move(*this);
   }
@@ -310,7 +323,7 @@ class Future {
   template <class E>
   void raise(E&& exception) {
     raise(make_exception_wrapper<typename std::remove_reference<E>::type>(
-        std::move(exception)));
+        std::forward<E>(exception)));
   }
 
   /// Raise an interrupt. If the promise holder has an interrupt
@@ -373,7 +386,7 @@ class Future {
   /// If the predicate does not obtain with the value, the result
   /// is a folly::PredicateDoesNotObtain exception
   template <class F>
-  Future<T> filter(F predicate);
+  Future<T> filter(F&& predicate);
 
   /// Like reduce, but works on a Future<std::vector<T / Try<T>>>, for example
   /// the result of collect or collectAll
@@ -416,6 +429,11 @@ class Future {
   auto thenMultiWithExecutor(Executor* x, Callback&& fn)
     -> decltype(this->then(std::forward<Callback>(fn)));
 
+  /// Discard a result, but propagate an exception.
+  Future<Unit> unit() {
+    return then([]{ return Unit{}; });
+  }
+
  protected:
   typedef detail::Core<T>* corePtr;
 
@@ -435,17 +453,40 @@ class Future {
   template <class T2>
   friend Future<T2> makeFuture(Try<T2>&&);
 
+  /// Repeat the given future (i.e., the computation it contains)
+  /// n times.
+  ///
+  /// thunk behaves like std::function<Future<T2>(void)>
+  template <class F>
+  friend Future<Unit> times(int n, F&& thunk);
+
+  /// Carry out the computation contained in the given future if
+  /// the predicate holds.
+  ///
+  /// thunk behaves like std::function<Future<T2>(void)>
+  template <class F>
+  friend Future<Unit> when(bool p, F&& thunk);
+
+  /// Carry out the computation contained in the given future if
+  /// while the predicate continues to hold.
+  ///
+  /// thunk behaves like std::function<Future<T2>(void)>
+  ///
+  /// predicate behaves like std::function<bool(void)>
+  template <class P, class F>
+  friend Future<Unit> whileDo(P&& predicate, F&& thunk);
+
   // Variant: returns a value
   // e.g. f.then([](Try<T> t){ return t.value(); });
   template <typename F, typename R, bool isTry, typename... Args>
   typename std::enable_if<!R::ReturnsFuture::value, typename R::Return>::type
-  thenImplementation(F func, detail::argResult<isTry, F, Args...>);
+  thenImplementation(F&& func, detail::argResult<isTry, F, Args...>);
 
   // Variant: returns a Future
   // e.g. f.then([](Try<T> t){ return makeFuture<T>(t); });
   template <typename F, typename R, bool isTry, typename... Args>
   typename std::enable_if<R::ReturnsFuture::value, typename R::Return>::type
-  thenImplementation(F func, detail::argResult<isTry, F, Args...>);
+  thenImplementation(F&& func, detail::argResult<isTry, F, Args...>);
 
   Executor* getExecutor() { return core_->getExecutor(); }
   void setExecutor(Executor* x, int8_t priority = Executor::MID_PRI) {