X-Git-Url: http://plrg.eecs.uci.edu/git/?p=folly.git;a=blobdiff_plain;f=folly%2Ffutures%2FFuture.h;h=5b2dc82f7b44b6c8f9a4a910f1f17fdb0c6c1204;hp=90207dd8a1000a807b9a18a9ba99b1d17d2a2934;hb=ff18deaf720fbe59551a7ff275b09003a61c4351;hpb=ad932c32057925606acb5156dd58e2626a8cccc3 diff --git a/folly/futures/Future.h b/folly/futures/Future.h index 90207dd8..5b2dc82f 100644 --- a/folly/futures/Future.h +++ b/folly/futures/Future.h @@ -1,5 +1,5 @@ /* - * Copyright 2015 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 @@ -24,201 +23,281 @@ #include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include +#include #include +// boring predeclarations and details +#include + +// 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 + namespace folly { -template struct Promise; +template +class Future; -template -struct isFuture : std::false_type { - typedef T Inner; -}; +template +class SemiFuture; -template -struct isFuture> : std::true_type { - typedef T Inner; -}; +namespace futures { +namespace detail { +template +class FutureBase { + public: + typedef T value_type; -template -struct isTry : std::false_type {}; + /// Construct a Future from a value (perfect forwarding) + template < + class T2 = T, + typename = typename std::enable_if< + !isFuture::type>::value && + !isSemiFuture::type>::value>::type> + /* implicit */ FutureBase(T2&& val); -template -struct isTry> : std::true_type {}; + template + /* implicit */ FutureBase( + typename std::enable_if::value>::type*); -namespace detail { + template < + class... Args, + typename std::enable_if::value, int>:: + type = 0> + explicit FutureBase(in_place_t, Args&&... args); -template struct Core; -template struct VariadicContext; -template struct CollectContext; + FutureBase(FutureBase const&) = delete; + FutureBase(SemiFuture&&) noexcept; + FutureBase(Future&&) noexcept; -template -using resultOf = decltype(std::declval()(std::declval()...)); + // not copyable + FutureBase(Future const&) = delete; + FutureBase(SemiFuture const&) = delete; -template -struct ArgType; + ~FutureBase(); -template -struct ArgType { - typedef Arg FirstArg; -}; + /// Returns a reference to the result, with a reference category and const- + /// qualification equivalent to the reference category and const-qualification + /// of the receiver. + /// + /// If moved-from, throws NoState. + /// + /// If !isReady(), throws FutureNotReady. + /// + /// If an exception has been captured, throws that exception. + T& value() &; + T const& value() const&; + T&& value() &&; + T const&& value() const&&; + + /// Returns a reference to the try of the result. Throws as for value if + /// future is not valid. + Try& result() &; + Try const& result() const&; + Try&& result() &&; + Try const&& result() const&&; -template <> -struct ArgType<> { - typedef void FirstArg; -}; + /** True when the result (or exception) is ready. */ + bool isReady() const; -template -struct argResult { - typedef resultOf Result; -}; + /// sugar for getTry().hasValue() + bool hasValue(); -template -struct callableWith { - template> - static constexpr std::true_type - check(std::nullptr_t) { return std::true_type{}; }; + /// sugar for getTry().hasException() + bool hasException(); - template - static constexpr std::false_type - check(...) { return std::false_type{}; }; + /// If the promise has been fulfilled, return an Optional with the Try. + /// Otherwise return an empty Optional. + /// Note that this moves the Try out. + Optional> poll(); - typedef decltype(check(nullptr)) type; - static constexpr bool value = type::value; -}; + /// This is not the method you're looking for. + /// + /// This needs to be public because it's used by make* and when*, and it's + /// not worth listing all those and their fancy template signatures as + /// friends. But it's not for public consumption. + template + void setCallback_(F&& func); -template -struct callableResult { - typedef typename std::conditional< - callableWith::value, - detail::argResult, - typename std::conditional< - callableWith::value, - detail::argResult, - typename std::conditional< - callableWith::value, - detail::argResult, - typename std::conditional< - callableWith&&>::value, - detail::argResult&&>, - detail::argResult&>>::type>::type>::type>::type Arg; - typedef isFuture ReturnsFuture; - typedef Future Return; -}; + bool isActive() { + return core_->isActive(); + } -template -struct callableResult { - typedef typename std::conditional< - callableWith::value, - detail::argResult, - typename std::conditional< - callableWith&&>::value, - detail::argResult&&>, - detail::argResult&>>::type>::type Arg; - typedef isFuture ReturnsFuture; - typedef Future Return; -}; + template + void raise(E&& exception) { + raise(make_exception_wrapper::type>( + std::forward(exception))); + } + + /// Raise an interrupt. If the promise holder has an interrupt + /// handler it will be called and potentially stop asynchronous work from + /// being done. This is advisory only - a promise holder may not set an + /// interrupt handler, or may do anything including ignore. But, if you know + /// your future supports this the most likely result is stopping or + /// preventing the asynchronous operation (if in time), and the promise + /// holder setting an exception on the future. (That may happen + /// asynchronously, of course.) + void raise(exception_wrapper interrupt); -template -struct Extract : Extract { }; + void cancel() { + raise(FutureCancellation()); + } -template -struct Extract { - typedef isFuture ReturnsFuture; - typedef Future Return; - typedef typename ReturnsFuture::Inner RawReturn; - typedef typename ArgType::FirstArg FirstArg; -}; + protected: + friend class Promise; + template + friend class SemiFuture; + template + friend class Future; -template -struct Extract { - typedef isFuture ReturnsFuture; - typedef Future Return; - typedef typename ReturnsFuture::Inner RawReturn; - typedef typename ArgType::FirstArg FirstArg; -}; + using corePtr = futures::detail::Core*; + + // shared core state object + corePtr core_; -} // detail + explicit FutureBase(corePtr obj) : core_(obj) {} -struct Timekeeper; + explicit FutureBase(futures::detail::EmptyConstruct) noexcept; -/// 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 sleep(Duration, Timekeeper* = nullptr); + void detach(); - /// Create a Future chain from a sequence of callbacks. i.e. - /// - /// f.then(a).then(b).then(c); - /// - /// where f is a Future and the result of the chain is a Future - /// becomes - /// - /// f.then(chain(a, b, c)); - // If anyone figures how to get chain to deduce A and Z, I'll buy you a drink. - template - std::function(Try)> - chain(Callbacks... fns); -} + void throwIfInvalid() const; + + template + void assign(FutureType&) noexcept; + + Executor* getExecutor() { + return core_->getExecutor(); + } + + void setExecutor(Executor* x, int8_t priority = Executor::MID_PRI) { + core_->setExecutor(x, priority); + } + + // Variant: returns a value + // e.g. f.then([](Try t){ return t.value(); }); + template + typename std::enable_if::type + thenImplementation(F&& func, futures::detail::argResult); + + // Variant: returns a Future + // e.g. f.then([](Try t){ return makeFuture(t); }); + template + typename std::enable_if::type + thenImplementation(F&& func, futures::detail::argResult); +}; +} // namespace detail +} // namespace futures template -class Future { +class SemiFuture : private futures::detail::FutureBase { + private: + using Base = futures::detail::FutureBase; + using DeferredExecutor = futures::detail::DeferredExecutor; + public: - typedef T value_type; + static SemiFuture makeEmpty(); // equivalent to moved-from + + // Export public interface of FutureBase + // FutureBase is inherited privately to avoid subclasses being cast to + // a FutureBase pointer + using typename Base::value_type; + + /// Construct a Future from a value (perfect forwarding) + template < + class T2 = T, + typename = typename std::enable_if< + !isFuture::type>::value && + !isSemiFuture::type>::value>::type> + /* implicit */ SemiFuture(T2&& val) : Base(std::forward(val)) {} + + template + /* implicit */ SemiFuture( + typename std::enable_if::value>::type* p = nullptr) + : Base(p) {} + + template < + class... Args, + typename std::enable_if::value, int>:: + type = 0> + explicit SemiFuture(in_place_t, Args&&... args) + : Base(in_place, std::forward(args)...) {} + + SemiFuture(SemiFuture const&) = delete; + // movable + SemiFuture(SemiFuture&&) noexcept; + // safe move-constructabilty from Future + /* implicit */ SemiFuture(Future&&) noexcept; + + using Base::cancel; + using Base::hasException; + using Base::hasValue; + using Base::isActive; + using Base::isReady; + using Base::poll; + using Base::raise; + using Base::setCallback_; + using Base::value; + using Base::result; + + SemiFuture& operator=(SemiFuture const&) = delete; + SemiFuture& operator=(SemiFuture&&) noexcept; + SemiFuture& operator=(Future&&) noexcept; - // not copyable - Future(Future const&) = delete; - Future& operator=(Future const&) = delete; + /// Block until the future is fulfilled. Returns the value (moved out), or + /// throws the exception. The future must not already have a callback. + T get() &&; - // movable - Future(Future&&) noexcept; - Future& operator=(Future&&) noexcept; + /// Block until the future is fulfilled, or until timed out. Returns the + /// value (moved out), or throws the exception (which might be a TimedOut + /// exception). + T get(Duration dur) &&; - // makeFuture - template - /* implicit */ - Future(const typename std::enable_if::value, F>::type& val); + /// Block until the future is fulfilled, or until timed out. Returns the + /// Try of the value (moved out). + Try getTry() &&; - template - /* implicit */ - Future(typename std::enable_if::value, F>::type&& val); + /// Block until the future is fulfilled, or until timed out. Returns the + /// Try of the value (moved out) or may throw a TimedOut exception. + Try getTry(Duration dur) &&; + + /// Call e->drive() repeatedly until the future is fulfilled. Examples + /// of DrivableExecutor include EventBase and ManualExecutor. Returns the + /// value (moved out), or throws the exception. + T getVia(DrivableExecutor* e) &&; - template ::value, int>::type = 0> - Future(); + /// Call e->drive() repeatedly until the future is fulfilled. Examples + /// of DrivableExecutor include EventBase and ManualExecutor. Returns the + /// Try of the value (moved out). + Try getTryVia(DrivableExecutor* e) &&; - ~Future(); + /// Block until this Future is complete. Returns a reference to this Future. + SemiFuture& wait() &; - /** Return the reference to result. Should not be called if !isReady(). - Will rethrow the exception if an exception has been - captured. - */ - typename std::add_lvalue_reference::type - value(); - typename std::add_lvalue_reference::type - value() const; + /// Overload of wait() for rvalue Futures + SemiFuture&& wait() &&; + + /// Block until this Future is complete or until the given Duration passes. + /// Returns a reference to this Future + SemiFuture& wait(Duration) &; + + /// Overload of wait(Duration) for rvalue Futures + SemiFuture&& wait(Duration) &&; + + /// Call e->drive() repeatedly until the future is fulfilled. Examples + /// of DrivableExecutor include EventBase and ManualExecutor. Returns a + /// reference to this SemiFuture so that you can chain calls if desired. + /// value (moved out), or throws the exception. + SemiFuture& waitVia(DrivableExecutor* e) &; + + /// Overload of waitVia() for rvalue Futures + SemiFuture&& waitVia(DrivableExecutor* e) &&; /// Returns an inactive Future which will call back on the other side of /// executor (when it is activated). @@ -240,46 +319,174 @@ class Future { // The ref-qualifier allows for `this` to be moved out so we // don't get access-after-free situations in chaining. // https://akrzemi1.wordpress.com/2014/06/02/ref-qualifiers/ - template - Future via(Executor* executor) &&; + inline Future via( + Executor* executor, + int8_t priority = Executor::MID_PRI) &&; + + /** + * Defer work to run on the consumer of the future. + * This work will be run eithe ron an executor that the caller sets on the + * SemiFuture, or inline with the call to .get(). + * NB: This is a custom method because boost-blocking executors is a + * special-case for work deferral in folly. With more general boost-blocking + * support all executors would boost block and we would simply use some form + * of driveable executor here. + */ + template + SemiFuture::Return::value_type> + defer(F&& func) &&; + + // Public as for setCallback_ + // Ensure that a boostable executor performs work to chain deferred work + // cleanly + void boost_(); + + private: + friend class Promise; + template + friend class futures::detail::FutureBase; + template + friend class SemiFuture; - /// This variant creates a new future, where the ref-qualifier && version - /// moves `this` out. This one is less efficient but avoids confusing users - /// when "return f.via(x);" fails. - template - Future via(Executor* executor) &; + using typename Base::corePtr; + using Base::setExecutor; + using Base::throwIfInvalid; - /** True when the result (or exception) is ready. */ - bool isReady() const; + template + friend SemiFuture makeSemiFuture(Try&&); - /** A reference to the Try of the value */ - Try& getTry(); + explicit SemiFuture(corePtr obj) : Base(obj) {} - /// If the promise has been fulfilled, return an Optional with the Try. - /// Otherwise return an empty Optional. - /// Note that this moves the Try out. - Optional> poll(); + explicit SemiFuture(futures::detail::EmptyConstruct) noexcept + : Base(futures::detail::EmptyConstruct{}) {} +}; - /// Block until the future is fulfilled. Returns the value (moved out), or - /// throws the exception. The future must not already have a callback. - T get(); +template +class Future : private futures::detail::FutureBase { + private: + using Base = futures::detail::FutureBase; - /// Block until the future is fulfilled, or until timed out. Returns the - /// value (moved out), or throws the exception (which might be a TimedOut - /// exception). - T get(Duration dur); + public: + // Export public interface of FutureBase + // FutureBase is inherited privately to avoid subclasses being cast to + // a FutureBase pointer + using typename Base::value_type; + + /// Construct a Future from a value (perfect forwarding) + template < + class T2 = T, + typename = typename std::enable_if< + !isFuture::type>::value && + !isSemiFuture::type>::value>::type> + /* implicit */ Future(T2&& val) : Base(std::forward(val)) {} + + template + /* implicit */ Future( + typename std::enable_if::value>::type* p = nullptr) + : Base(p) {} + + template < + class... Args, + typename std::enable_if::value, int>:: + type = 0> + explicit Future(in_place_t, Args&&... args) + : Base(in_place, std::forward(args)...) {} + + Future(Future const&) = delete; + // movable + Future(Future&&) noexcept; + + // converting move + template < + class T2, + typename std::enable_if< + !std::is_same::type>::value && + std::is_constructible::value && + std::is_convertible::value, + int>::type = 0> + /* implicit */ Future(Future&&); + template < + class T2, + typename std::enable_if< + !std::is_same::type>::value && + std::is_constructible::value && + !std::is_convertible::value, + int>::type = 0> + explicit Future(Future&&); + template < + class T2, + typename std::enable_if< + !std::is_same::type>::value && + std::is_constructible::value, + int>::type = 0> + Future& operator=(Future&&); + + using Base::cancel; + using Base::hasException; + using Base::hasValue; + using Base::isActive; + using Base::isReady; + using Base::poll; + using Base::raise; + using Base::setCallback_; + using Base::value; + using Base::result; + + static Future makeEmpty(); // equivalent to moved-from + + // not copyable + Future& operator=(Future const&) = delete; + + // movable + Future& operator=(Future&&) noexcept; /// Call e->drive() repeatedly until the future is fulfilled. Examples /// of DrivableExecutor include EventBase and ManualExecutor. Returns the /// value (moved out), or throws the exception. T getVia(DrivableExecutor* e); + /// 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& getTryVia(DrivableExecutor* e); + /// Unwraps the case of a Future> instance, and returns a simple /// Future instance. template - typename std::enable_if::value, - Future::Inner>>::type - unwrap(); + typename std:: + enable_if::value, Future::Inner>>::type + unwrap(); + + /// Returns an inactive Future which will call back on the other side of + /// executor (when it is activated). + /// + /// NB remember that Futures activate when they destruct. This is good, + /// it means that this will work: + /// + /// f.via(e).then(a).then(b); + /// + /// a and b will execute in the same context (the far side of e), because + /// the Future (temporary variable) created by via(e) does not call back + /// until it destructs, which is after then(a) and then(b) have been wired + /// up. + /// + /// But this is still racy: + /// + /// f = f.via(e).then(a); + /// f.then(b); + // The ref-qualifier allows for `this` to be moved out so we + // don't get access-after-free situations in chaining. + // https://akrzemi1.wordpress.com/2014/06/02/ref-qualifiers/ + inline Future via( + Executor* executor, + int8_t priority = Executor::MID_PRI) &&; + + /// This variant creates a new future, where the ref-qualifier && version + /// moves `this` out. This one is less efficient but avoids confusing users + /// when "return f.via(x);" fails. + inline Future via( + Executor* executor, + int8_t priority = Executor::MID_PRI) &; /** When this Future has completed, execute func which is a function that takes one of: @@ -301,14 +508,10 @@ 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 R::Return then(F func) { - typedef typename R::Arg Arguments; - return thenImplementation(std::move(func), Arguments()); + template > + typename R::Return then(F&& func) { + return this->template thenImplementation( + std::forward(func), typename R::Arg()); } /// Variant where func is an member function @@ -322,12 +525,41 @@ class Future { /// /// f1.then(std::bind(&Worker::doWork, w)); template - Future::Inner> - then(R(Caller::*func)(Args...), Caller *instance); + Future::Inner> then( + R (Caller::*func)(Args...), + Caller* instance); + + /// Execute the callback via the given Executor. The executor doesn't stick. + /// + /// Contrast + /// + /// f.via(x).then(b).then(c) + /// + /// with + /// + /// f.then(x, b).then(c) + /// + /// In the former both b and c execute via x. In the latter, only b executes + /// via x, and c executes via the same executor (if any) that f had. + template + auto then(Executor* x, Arg&& arg, Args&&... args) { + auto oldX = this->getExecutor(); + this->setExecutor(x); + return this->then(std::forward(arg), std::forward(args)...) + .via(oldX); + } - /// Convenience method for ignoring the value and creating a Future. + /// Convenience method for ignoring the value and creating a Future. /// Exceptions still propagate. - Future then(); + /// This function is identical to .unit(). + Future then(); + + /// Convenience method for ignoring the value and creating a Future. + /// Exceptions still propagate. + /// This function is identical to parameterless .then(). + Future unit() { + return 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 @@ -345,33 +577,35 @@ class Future { /// }); template typename std::enable_if< - !detail::callableWith::value && - !detail::Extract::ReturnsFuture::value, - Future>::type + !futures::detail::callableWith::value && + !futures::detail::callableWith::value && + !futures::detail::Extract::ReturnsFuture::value, + Future>::type onError(F&& func); /// Overload of onError where the error callback returns a Future template typename std::enable_if< - !detail::callableWith::value && - detail::Extract::ReturnsFuture::value, - Future>::type + !futures::detail::callableWith::value && + !futures::detail::callableWith::value && + futures::detail::Extract::ReturnsFuture::value, + Future>::type onError(F&& func); /// Overload of onError that takes exception_wrapper and returns Future template typename std::enable_if< - detail::callableWith::value && - detail::Extract::ReturnsFuture::value, - Future>::type + futures::detail::callableWith::value && + futures::detail::Extract::ReturnsFuture::value, + Future>::type onError(F&& func); /// Overload of onError that takes exception_wrapper and returns T template typename std::enable_if< - detail::callableWith::value && - !detail::Extract::ReturnsFuture::value, - Future>::type + futures::detail::callableWith::value && + !futures::detail::Extract::ReturnsFuture::value, + Future>::type onError(F&& func); /// func is like std::function and is executed unconditionally, and @@ -379,7 +613,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 - Future ensure(F func); + Future ensure(F&& func); /// Like onError, but for timeouts. example: /// @@ -397,60 +631,28 @@ class Future { template Future onTimeout(Duration, F&& func, Timekeeper* = nullptr); - /// This is not the method you're looking for. - /// - /// This needs to be public because it's used by make* and when*, and it's - /// not worth listing all those and their fancy template signatures as - /// friends. But it's not for public consumption. - template - void setCallback_(F&& func); - /// A Future's callback is executed when all three of these conditions have /// become true: it has a value (set by the Promise), it has a callback (set /// by then), and it is active (active by default). /// /// Inactive Futures will activate upon destruction. - Future& activate() & { - core_->activate(); + FOLLY_DEPRECATED("do not use") Future& activate() & { + this->core_->activate(); return *this; } - Future& deactivate() & { - core_->deactivate(); + FOLLY_DEPRECATED("do not use") Future& deactivate() & { + this->core_->deactivate(); return *this; } - Future activate() && { - core_->activate(); + FOLLY_DEPRECATED("do not use") Future activate() && { + this->core_->activate(); return std::move(*this); } - Future deactivate() && { - core_->deactivate(); + FOLLY_DEPRECATED("do not use") Future deactivate() && { + this->core_->deactivate(); return std::move(*this); } - bool isActive() { - return core_->isActive(); - } - - template - void raise(E&& exception) { - raise(make_exception_wrapper::type>( - std::move(exception))); - } - - /// Raise an interrupt. If the promise holder has an interrupt - /// handler it will be called and potentially stop asynchronous work from - /// being done. This is advisory only - a promise holder may not set an - /// interrupt handler, or may do anything including ignore. But, if you know - /// your future supports this the most likely result is stopping or - /// preventing the asynchronous operation (if in time), and the promise - /// holder setting an exception on the future. (That may happen - /// asynchronously, of course.) - void raise(exception_wrapper interrupt); - - void cancel() { - raise(FutureCancellation()); - } - /// Throw TimedOut if this Future does not complete within the given /// duration from now. The optional Timeekeeper is as with futures::sleep(). Future within(Duration, Timekeeper* = nullptr); @@ -465,6 +667,18 @@ class Future { /// now. The optional Timekeeper is as with futures::sleep(). Future delayed(Duration, Timekeeper* = nullptr); + /// Block until the future is fulfilled. Returns the value (moved out), or + /// throws the exception. The future must not already have a callback. + T get(); + + /// Block until the future is fulfilled, or until timed out. Returns the + /// value (moved out), or throws the exception (which might be a TimedOut + /// exception). + T get(Duration dur); + + /** A reference to the Try of the value */ + Try& getTry(); + /// Block until this Future is complete. Returns a reference to this Future. Future& wait() &; @@ -497,191 +711,110 @@ class Future { /// If the predicate does not obtain with the value, the result /// is a folly::PredicateDoesNotObtain exception template - Future filter(F predicate); - - protected: - typedef detail::Core* corePtr; - - // shared core state object - corePtr core_; - - explicit - Future(corePtr obj) : core_(obj) {} - - void detach(); + Future filter(F&& predicate); - void throwIfInvalid() const; + /// Like reduce, but works on a Future>>, for example + /// the result of collect or collectAll + template + Future reduce(I&& initial, F&& func); - friend class Promise; - template friend class Future; + /// Create a Future chain from a sequence of callbacks. i.e. + /// + /// f.then(a).then(b).then(c) + /// + /// where f is a Future and the result of the chain is a Future + /// becomes + /// + /// f.thenMulti(a, b, c); + template + auto thenMulti(Callback&& fn, Callbacks&&... fns) { + // thenMulti with two callbacks is just then(a).thenMulti(b, ...) + return then(std::forward(fn)) + .thenMulti(std::forward(fns)...); + } - // Variant: returns a value - // e.g. f.then([](Try t){ return t.value(); }); - template - typename std::enable_if::type - thenImplementation(F func, detail::argResult); + template + auto thenMulti(Callback&& fn) { + // thenMulti with one callback is just a then + return then(std::forward(fn)); + } - // Variant: returns a Future - // e.g. f.then([](Try t){ return makeFuture(t); }); - template - typename std::enable_if::type - thenImplementation(F func, detail::argResult); + /// Create a Future chain from a sequence of callbacks. i.e. + /// + /// f.via(executor).then(a).then(b).then(c).via(oldExecutor) + /// + /// where f is a Future and the result of the chain is a Future + /// becomes + /// + /// f.thenMultiWithExecutor(executor, a, b, c); + template + auto thenMultiWithExecutor(Executor* x, Callback&& fn, Callbacks&&... fns) { + // thenMultiExecutor with two callbacks is + // via(x).then(a).thenMulti(b, ...).via(oldX) + auto oldX = this->getExecutor(); + this->setExecutor(x); + return then(std::forward(fn)) + .thenMulti(std::forward(fns)...) + .via(oldX); + } - Executor* getExecutor() { return core_->getExecutor(); } - void setExecutor(Executor* x) { core_->setExecutor(x); } -}; + template + auto thenMultiWithExecutor(Executor* x, Callback&& fn) { + // thenMulti with one callback is just a then with an executor + return then(x, std::forward(fn)); + } -/** - Make a completed Future by moving in a value. e.g. + // Convert this Future to a SemiFuture to safely export from a library + // without exposing a continuation interface + SemiFuture semi() { + return SemiFuture{std::move(*this)}; + } - string foo = "foo"; - auto f = makeFuture(std::move(foo)); + protected: + friend class Promise; + template + friend class futures::detail::FutureBase; + template + friend class Future; + template + friend class SemiFuture; - or + using Base::setExecutor; + using Base::throwIfInvalid; + using typename Base::corePtr; - auto f = makeFuture("foo"); -*/ -template -Future::type> makeFuture(T&& t); + explicit Future(corePtr obj) : Base(obj) {} -/** Make a completed void Future. */ -Future makeFuture(); + explicit Future(futures::detail::EmptyConstruct) noexcept + : Base(futures::detail::EmptyConstruct{}) {} -/** Make a completed Future by executing a function. If the function throws - we capture the exception, otherwise we capture the result. */ -template -auto makeFutureTry( - F&& func, - typename std::enable_if< - !std::is_reference::value, bool>::type sdf = false) - -> Future; - -template -auto makeFutureTry( - F const& func) - -> Future; - -/// 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(std::current_exception()); -template -Future makeFuture(std::exception_ptr const& e) DEPRECATED; + template + friend Future makeFuture(Try&&); -/// Make a failed Future from an exception_wrapper. -template -Future makeFuture(exception_wrapper ew); + /// Repeat the given future (i.e., the computation it contains) + /// n times. + /// + /// thunk behaves like std::function(void)> + template + friend Future times(int n, F&& thunk); -/** Make a Future from an exception type E that can be passed to - std::make_exception_ptr(). */ -template -typename std::enable_if::value, - Future>::type -makeFuture(E const& e); + /// Carry out the computation contained in the given future if + /// the predicate holds. + /// + /// thunk behaves like std::function(void)> + template + friend Future when(bool p, F&& thunk); -/** Make a Future out of a Try */ -template -Future makeFuture(Try&& t); + /// Carry out the computation contained in the given future if + /// while the predicate continues to hold. + /// + /// thunk behaves like std::function(void)> + /// + /// predicate behaves like std::function + template + friend Future whileDo(P&& predicate, F&& thunk); +}; -/* - * 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 -Future 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 input is a Future>> - */ -template -Future::value_type::value_type>>> -whenAll(InputIterator first, InputIterator last); - -/// This version takes a varying number of Futures instead of an iterator. -/// The return type for (Future, Future, ...) input -/// is a Future, Try, ...>>. -/// The Futures are moved in, so your copies are invalid. -template -typename detail::VariadicContext< - typename std::decay::type::value_type...>::type -whenAll(Fs&&... fs); - -/// Like whenAll, but will short circuit on the first exception. Thus, the -/// type of the returned Future is std::vector instead of -/// std::vector> -template -Future::value_type::value_type ->::result_type> -collect(InputIterator first, InputIterator last); - -/** 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 -Future::value_type::value_type>>> -whenAny(InputIterator first, InputIterator last); - -/** 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 -Future::value_type::value_type>>>> -whenN(InputIterator first, InputIterator last, size_t n); - -template -using MaybeTryArg = typename std::conditional< - detail::callableWith&&>::value, Try, ItT>::type; - -template -using isFutureResult = isFuture::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 - */ -template ::value_type::value_type, - class Arg = MaybeTryArg> -typename std::enable_if::value, Future>::type -reduce(It first, It last, T initial, F func); - -template ::value_type::value_type, - class Arg = MaybeTryArg> -typename std::enable_if::value, Future>::type -reduce(It first, It last, T initial, F func); - -} // folly +} // namespace folly #include