/* * Copyright (c) Facebook, Inc. and its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if FOLLY_HAS_COROUTINES #include #include #endif // boring predeclarations and details #include namespace folly { class FOLLY_EXPORT FutureException : public std::logic_error { public: using std::logic_error::logic_error; }; class FOLLY_EXPORT FutureInvalid : public FutureException { public: FutureInvalid() : FutureException("Future invalid") {} }; /// At most one continuation may be attached to any given Future. /// /// If a continuation is attached to a future to which another continuation has /// already been attached, then an instance of FutureAlreadyContinued will be /// thrown instead. class FOLLY_EXPORT FutureAlreadyContinued : public FutureException { public: FutureAlreadyContinued() : FutureException("Future already continued") {} }; class FOLLY_EXPORT FutureNotReady : public FutureException { public: FutureNotReady() : FutureException("Future not ready") {} }; class FOLLY_EXPORT FutureCancellation : public FutureException { public: FutureCancellation() : FutureException("Future was cancelled") {} }; class FOLLY_EXPORT FutureTimeout : public FutureException { public: FutureTimeout() : FutureException("Timed out") {} }; class FOLLY_EXPORT FuturePredicateDoesNotObtain : public FutureException { public: FuturePredicateDoesNotObtain() : FutureException("Predicate does not obtain") {} }; class FOLLY_EXPORT FutureNoTimekeeper : public FutureException { public: FutureNoTimekeeper() : FutureException("No timekeeper available") {} }; class FOLLY_EXPORT FutureNoExecutor : public FutureException { public: FutureNoExecutor() : FutureException("No executor provided to via") {} }; template class Future; template class SemiFuture; template class FutureSplitter; #if FOLLY_FUTURE_USING_FIBER namespace fibers { class Baton; } #endif namespace futures { namespace detail { template class FutureBase { protected: using Core = futures::detail::Core; using CoreCallback = typename Core::Callback; public: typedef T value_type; /// Construct from a value (perfect forwarding) /// /// Postconditions: /// /// - `valid() == true` /// - `isReady() == true` /// - `hasValue() == true` template < class T2 = T, typename = typename std::enable_if< !isFuture::type>::value && !isSemiFuture::type>::value && std::is_constructible, T2>::value>::type> /* implicit */ FutureBase(T2&& val); /// Construct a (logical) FutureBase-of-void. /// /// Postconditions: /// /// - `valid() == true` /// - `isReady() == true` /// - `hasValue() == true` template /* implicit */ FutureBase( typename std::enable_if::value>::type*); template < class... Args, typename std::enable_if::value, int>:: type = 0> explicit FutureBase(in_place_t, Args&&... args) : core_(Core::make(in_place, std::forward(args)...)) {} FutureBase(FutureBase const&) = delete; FutureBase(SemiFuture&&) noexcept; FutureBase(Future&&) noexcept; // not copyable FutureBase(Future const&) = delete; FutureBase(SemiFuture const&) = delete; ~FutureBase(); /// true if this has a shared state; /// false if this has been either moved-out or created without a shared state. bool valid() const noexcept { return core_ != nullptr; } /// Returns a reference to the result value if it is ready, with a reference /// category and const-qualification like those of the future. /// /// Does not `wait()`; see `get()` for that. /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// - `isReady() == true` (else throws FutureNotReady) /// /// Postconditions: /// /// - If an exception has been captured (i.e., if `hasException() == true`), /// throws that exception. /// - This call does not mutate the future's value. /// - However calling code may mutate that value (including moving it out by /// move-constructing or move-assigning another value from it), for /// example, via the `&` or the `&&` overloads or via casts. T& value() &; T const& value() const&; T&& value() &&; T const&& value() const&&; /// Returns a reference to the result's Try if it is ready, with a reference /// category and const-qualification like those of the future. /// /// Does not `wait()`; see `get()` for that. /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// - `isReady() == true` (else throws FutureNotReady) /// /// Postconditions: /// /// - This call does not mutate the future's result. /// - However calling code may mutate that result (including moving it out by /// move-constructing or move-assigning another result from it), for /// example, via the `&` or the `&&` overloads or via casts. Try& result() &; Try const& result() const&; Try&& result() &&; Try const&& result() const&&; /// True when the result (or exception) is ready; see value(), result(), etc. /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) bool isReady() const; /// True if the result is a value (not an exception) on a future for which /// isReady returns true. /// /// Equivalent to result().hasValue() /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// - `isReady() == true` (else throws FutureNotReady) bool hasValue() const; /// True if the result is an exception (not a value) on a future for which /// isReady returns true. /// /// Equivalent to result().hasException() /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// - `isReady() == true` (else throws FutureNotReady) bool hasException() const; /// Returns either an Optional holding the result or an empty Optional /// depending on whether or not (respectively) the promise has been /// fulfilled (i.e., `isReady() == true`). /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - `valid() == true` (note however that this moves-out the result when /// it returns a populated `Try`, which effects any subsequent use of /// that result, e.g., `poll()`, `result()`, `value()`, `get()`, etc.) Optional> poll(); /// 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. void setCallback_( CoreCallback&& func, InlineContinuation = InlineContinuation::forbid); /// Provides a threadsafe back-channel so the consumer's thread can send an /// interrupt-object to the producer's thread. /// /// If the promise-holder registers an interrupt-handler and consumer thread /// raises an interrupt early enough (details below), the promise-holder /// will typically halt its work, fulfilling the future with an exception /// or some special non-exception value. /// /// However this interrupt request is voluntary, asynchronous, & advisory: /// /// - Voluntary: the producer will see the interrupt only if the producer uses /// a `Promise` object and registers an interrupt-handler; /// see `Promise::setInterruptHandler()`. /// - Asynchronous: the producer will see the interrupt only if `raise()` is /// called before (or possibly shortly after) the producer is done producing /// its result, which is asynchronous with respect to the call to `raise()`. /// - Advisory: the producer's interrupt-handler can do whatever it wants, /// including ignore the interrupt or perform some action other than halting /// its producer-work. /// /// Guidelines: /// /// - It is ideal if the promise-holder can both halt its work and fulfill the /// promise early, typically with the same exception that was delivered to /// the promise-holder in the form of an interrupt. /// - If the promise-holder does not do this, and if it holds the promise /// alive for a long time, then the whole continuation chain will not be /// invoked and the whole future chain will be kept alive for that long time /// as well. /// - It is also ideal if the promise-holder can invalidate the promise. /// - The promise-holder must also track whether it has set a result in the /// interrupt handler so that it does not attempt to do so outside the /// interrupt handler, and must track whether it has set a result in its /// normal flow so that it does not attempt to do so in the interrupt /// handler, since setting a result twice is an error. Because the interrupt /// handler can be invoked in some other thread, this tracking may have to /// be done with some form of concurrency control. /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - has no visible effect if `raise()` was previously called on `this` or /// any other Future/SemiFuture that uses the same shared state as `this`. /// - has no visible effect if the producer never (either in the past or in /// the future) registers an interrupt-handler. /// - has no visible effect if the producer fulfills its promise (sets the /// result) before (or possibly also shortly after) receiving the interrupt. /// - otherwise the promise-holder's interrupt-handler is called, passing the /// exception (within an `exception_wrapper`). /// /// The specific thread used to invoke the producer's interrupt-handler (if /// it is called at all) depends on timing: /// /// - if the interrupt-handler is registered prior to `raise()` (or possibly /// concurrently within the call to `raise()`), the interrupt-handler will /// be executed using this current thread within the call to `raise()`. /// - if the interrupt-handler is registered after `raise()` (and possibly /// concurrently within the call to `raise()`), the interrupt-handler will /// be executed using the producer's thread within the call to /// `Promise::setInterruptHandler()`. /// /// Synchronizes between `raise()` (in the consumer's thread) /// and `Promise::setInterruptHandler()` (in the producer's thread). void raise(exception_wrapper interrupt); /// Raises the specified exception-interrupt. /// See `raise(exception_wrapper)` for details. template void raise(E&& exception) { raise(make_exception_wrapper::type>( std::forward(exception))); } /// Raises a FutureCancellation interrupt. /// See `raise(exception_wrapper)` for details. void cancel() { raise(FutureCancellation()); } protected: friend class Promise; template friend class SemiFuture; template friend class Future; // Throws FutureInvalid if there is no shared state object; else returns it // by ref. // // Implementation methods should usually use this instead of `this->core_`. // The latter should be used only when you need the possibly-null pointer. Core& getCore() { return getCoreImpl(*this); } Core const& getCore() const { return getCoreImpl(*this); } template static decltype(auto) getCoreImpl(Self& self) { if (!self.core_) { throw_exception(); } return *self.core_; } Try& getCoreTryChecked() { return getCoreTryChecked(*this); } Try const& getCoreTryChecked() const { return getCoreTryChecked(*this); } template static decltype(auto) getCoreTryChecked(Self& self) { auto& core = self.getCore(); if (!core.hasResult()) { throw_exception(); } return core.getTry(); } // shared core state object // usually you should use `getCore()` instead of directly accessing `core_`. Core* core_; explicit FutureBase(Core* obj) : core_(obj) {} explicit FutureBase(futures::detail::EmptyConstruct) noexcept; void detach(); void throwIfInvalid() const; void throwIfContinued() const; void assign(FutureBase&& other) noexcept; Executor* getExecutor() const { return getCore().getExecutor(); } DeferredExecutor* getDeferredExecutor() const { return getCore().getDeferredExecutor(); } // Sets the Executor within the Core state object of `this`. // Must be called either before attaching a callback or after the callback // has already been invoked, but not concurrently with anything which might // trigger invocation of the callback. void setExecutor(futures::detail::KeepAliveOrDeferred x) { getCore().setExecutor(std::move(x)); } // Variant: returns a value // e.g. f.thenTry([](Try t){ return t.value(); }); template typename std::enable_if::type thenImplementation(F&& func, R, InlineContinuation); // Variant: returns a Future // e.g. f.thenTry([](Try t){ return makeFuture(t); }); template typename std::enable_if::type thenImplementation(F&& func, R, InlineContinuation); }; template Future convertFuture(SemiFuture&& sf, const Future& f); class DeferredExecutor; template DeferredExecutor* getDeferredExecutor(SemiFuture& future); template futures::detail::DeferredWrapper stealDeferredExecutor(SemiFuture& future); } // namespace detail template void detachOn(folly::Executor::KeepAlive<> exec, folly::SemiFuture&& fut); template void detachOnGlobalCPUExecutor(folly::SemiFuture&& fut); } // namespace futures /// The interface (along with Future) for the consumer-side of a /// producer/consumer pair. /// /// Future vs. SemiFuture: /// /// - The consumer-side should generally start with a SemiFuture, not a Future. /// - Example, when a library creates and returns a future, it should usually /// return a `SemiFuture`, not a Future. /// - Reason: so the thread policy for continuations (`.thenValue`, etc.) can be /// specified by the library's caller (using `.via()`). /// - A SemiFuture is converted to a Future using `.via()`. /// - Use `makePromiseContract()` when creating both a Promise and an associated /// SemiFuture/Future. /// /// When practical, prefer SemiFuture/Future's nonblocking style/pattern: /// /// - the nonblocking style uses continuations, e.g., `.thenValue`, etc.; the /// continuations are deferred until the result is available. /// - the blocking style blocks until complete, e.g., `.wait()`, `.get()`, etc. /// - the two styles cannot be mixed within the same future; use one or the /// other. /// /// SemiFuture/Future also provide a back-channel so an interrupt can /// be sent from consumer to producer; see SemiFuture/Future's `raise()` /// and Promise's `setInterruptHandler()`. /// /// The consumer-side SemiFuture/Future objects should generally be accessed /// via a single thread. That thread is referred to as the 'consumer thread.' template class SemiFuture : private futures::detail::FutureBase { private: using Base = futures::detail::FutureBase; using DeferredExecutor = futures::detail::DeferredExecutor; using TimePoint = std::chrono::system_clock::time_point; public: ~SemiFuture(); /// Creates/returns an invalid SemiFuture, that is, one with no shared state. /// /// Postcondition: /// /// - `RESULT.valid() == false` static SemiFuture makeEmpty(); /// Type of the value that the producer, when successful, produces. using typename Base::value_type; /// Construct a SemiFuture from a value (perfect forwarding) /// /// Postconditions: /// /// - `valid() == true` /// - `isReady() == true` /// - `hasValue() == true` /// - `hasException() == false` /// - `value()`, `get()`, `result()` will return the forwarded `T` template < class T2 = T, typename = typename std::enable_if< !isFuture::type>::value && !isSemiFuture::type>::value && std::is_constructible, T2>::value>::type> /* implicit */ SemiFuture(T2&& val) : Base(std::forward(val)) {} /// Construct a (logical) SemiFuture-of-void. /// /// Postconditions: /// /// - `valid() == true` /// - `isReady() == true` /// - `hasValue() == true` template /* implicit */ SemiFuture( typename std::enable_if::value>::type* p = nullptr) : Base(p) {} /// Construct a SemiFuture from a `T` constructed from `args` /// /// Postconditions: /// /// - `valid() == true` /// - `isReady() == true` /// - `hasValue() == true` /// - `hasException() == false` /// - `value()`, `get()`, `result()` will return the newly constructed `T` 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::isReady; using Base::poll; using Base::raise; using Base::result; using Base::setCallback_; using Base::valid; using Base::value; SemiFuture& operator=(SemiFuture const&) = delete; SemiFuture& operator=(SemiFuture&&) noexcept; SemiFuture& operator=(Future&&) noexcept; /// Blocks until the promise is fulfilled, either by value (which is returned) /// or exception (which is thrown). /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// - must not have a continuation, e.g., via `.thenValue()` or similar /// /// Postconditions: /// /// - `valid() == false` T get() &&; /// Blocks until the semifuture is fulfilled, or until `dur` elapses. Returns /// the value (moved-out), or throws the exception (which might be a /// FutureTimeout exception). /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - `valid() == false` T get(HighResDuration dur) &&; /// Blocks until the future is fulfilled. Returns the Try of the result /// (moved-out). /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - `valid() == false` Try getTry() &&; /// Blocks until the future is fulfilled, or until `dur` elapses. /// Returns the Try of the result (moved-out), or throws FutureTimeout /// exception. /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - `valid() == false` Try getTry(HighResDuration dur) &&; /// Blocks the caller's thread until this Future `isReady()`, i.e., until the /// asynchronous producer has stored a result or exception. /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - `valid() == true` /// - `isReady() == true` /// - `&RESULT == this` SemiFuture& wait() &; /// Blocks the caller's thread until this Future `isReady()`, i.e., until the /// asynchronous producer has stored a result or exception. /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - `valid() == true` (but the calling code can trivially move-out `*this` /// by assigning or constructing the result into a distinct object). /// - `&RESULT == this` /// - `isReady() == true` SemiFuture&& wait() &&; /// Blocks until the future is fulfilled, or `dur` elapses. /// Returns true if the future was fulfilled. /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - `valid() == false` bool wait(HighResDuration dur) &&; /// Returns a Future which will call back on the other side of executor. Future via(Executor::KeepAlive<> executor) &&; Future via(Executor::KeepAlive<> executor, int8_t priority) &&; /// Defer work to run on the consumer of the future. /// Function must take a Try as a parameter. /// This work will be run either on 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. /// /// All forms of defer will run the continuation inline with the execution of /// the previous callback in the chain if the callback attached to the /// previous future that triggers execution of func runs on the same executor /// that func would be executed on. /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - `valid() == false` /// - `RESULT.valid() == true` template SemiFuture::value_type> defer(F&& func) &&; /// Defer work to run on the consumer of the future. /// Function must take a const Executor::KeepAlive<>& and a Try as parameters. /// /// As for defer(F&& func) except as the first parameter to func a KeepAlive /// representing the executor running the work will be provided. template SemiFuture< typename futures::detail::tryExecutorCallableResult::value_type> deferExTry(F&& func) &&; /// Defer work to run on the consumer of the future. /// Function must take a Try as a parameter. /// /// As for defer(F&& func) but supporting function references. template auto defer(R (&func)(Args...)) && { return std::move(*this).defer(&func); } /// Defer for functions taking a T rather than a Try. /// /// All forms of defer will run the continuation inline with the execution of /// the previous callback in the chain if the callback attached to the /// previous future that triggers execution of func runs on the same executor /// that func would be executed on. /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - `valid() == false` /// - `RESULT.valid() == true` template SemiFuture::value_type> deferValue(F&& func) &&; /// Defer for functions taking a T rather than a Try. /// Function must take a const Executor::KeepAlive<>& and a T as parameters. /// /// As for deferValue(F&& func) except as the first parameter to func a /// KeepAlive representing the executor running the work will be provided. template SemiFuture< typename futures::detail::valueExecutorCallableResult::value_type> deferExValue(F&& func) &&; /// Defer work to run on the consumer of the future. /// Function must take a T as a parameter. /// /// As for deferValue(F&& func) but supporting function references. template auto deferValue(R (&func)(Args...)) && { return std::move(*this).deferValue(&func); } /// Set an error continuation for this SemiFuture where the continuation can /// be called with a known exception type and returns a `T`, `Future`, or /// `SemiFuture`. /// /// Example: /// /// ``` /// makeSemiFuture() /// .defer([] { /// throw std::runtime_error("oh no!"); /// return 42; /// }) /// .deferError(folly::tag_t{}, [] (auto const& e) { /// LOG(INFO) << "std::runtime_error: " << e.what(); /// return -1; // or makeFuture(-1) or makeSemiFuture(-1) /// }); /// ``` /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - `valid() == false` /// - `RESULT.valid() == true` template SemiFuture deferError(tag_t, F&& func) &&; /// As for deferError(tag_t, F&& func) but supporting function /// references. template SemiFuture deferError(tag_t tag, R (&func)(Args...)) && { return std::move(*this).deferError(tag, &func); } /// As for deferError(tag_t, F&& func) but makes the exception /// explicit as a template argument rather than using a tag type. template SemiFuture deferError(F&& func) && { return std::move(*this).deferError( tag_t{}, std::forward(func)); } /// Set an error continuation for this SemiFuture where the continuation can /// be called with `exception_wrapper&&` and returns a `T`, `Future`, or /// `SemiFuture`. /// /// Example: /// /// makeSemiFuture() /// .defer([] { /// throw std::runtime_error("oh no!"); /// return 42; /// }) /// .deferError([] (exception_wrapper&& e) { /// LOG(INFO) << e.what(); /// return -1; // or makeFuture(-1) or makeSemiFuture(-1) /// }); /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - `valid() == false` /// - `RESULT.valid() == true` template SemiFuture deferError(F&& func) &&; /// As for deferError(tag_t, F&& func) but supporting function /// references. template SemiFuture deferError(R (&func)(Args...)) && { return std::move(*this).deferError(&func); } /// Convenience method for ignoring the value and creating a Future. /// Exceptions still propagate. /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - Calling code should act as if `valid() == false`, /// i.e., as if `*this` was moved into RESULT. /// - `RESULT.valid() == true` SemiFuture unit() &&; /// If this SemiFuture completes within duration dur from now, propagate its /// value. Otherwise satisfy the returned SemiFuture with a FutureTimeout /// exception. /// /// The optional Timekeeper is as with futures::sleep(). /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - Calling code should act as if `valid() == false`, /// i.e., as if `*this` was moved into RESULT. /// - `RESULT.valid() == true` SemiFuture within(HighResDuration dur, Timekeeper* tk = nullptr) && { return std::move(*this).within(dur, FutureTimeout(), tk); } /// If this SemiFuture completes within duration dur from now, propagate its /// value. Otherwise satisfy the returned SemiFuture with exception e. /// /// The optional Timekeeper is as with futures::sleep(). /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - Calling code should act as if `valid() == false`, /// i.e., as if `*this` was moved into RESULT. /// - `RESULT.valid() == true` template SemiFuture within(HighResDuration dur, E e, Timekeeper* tk = nullptr) &&; /// Delay the completion of this SemiFuture for at least this duration from /// now. The optional Timekeeper is as with futures::sleep(). /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - `valid() == false` /// - `RESULT.valid() == true` SemiFuture delayed(HighResDuration dur, Timekeeper* tk = nullptr) &&; /// Returns a future that completes inline, as if the future had no executor. /// Intended for porting legacy code without behavioral change, and for rare /// cases where this is really the intended behavior. /// Future is unsafe in the sense that the executor it completes on is /// non-deterministic in the standard case. /// For new code, or to update code that temporarily uses this, please /// use via and pass a meaningful executor. /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - `valid() == false` /// - `RESULT.valid() == true` Future toUnsafeFuture() &&; #if FOLLY_HAS_COROUTINES // Customise the co_viaIfAsync() operator so that SemiFuture can be // directly awaited within a folly::coro::Task coroutine. friend Future co_viaIfAsync( folly::Executor::KeepAlive<> executor, SemiFuture&& future) noexcept { return std::move(future).via(std::move(executor)); } #endif private: friend class Promise; template friend class futures::detail::FutureBase; template friend class SemiFuture; template friend class Future; friend futures::detail::DeferredWrapper futures::detail::stealDeferredExecutor(SemiFuture&); friend DeferredExecutor* futures::detail::getDeferredExecutor( SemiFuture&); using Base::setExecutor; using Base::throwIfInvalid; using typename Base::Core; template friend SemiFuture makeSemiFuture(Try); explicit SemiFuture(Core* obj) : Base(obj) {} explicit SemiFuture(futures::detail::EmptyConstruct) noexcept : Base(futures::detail::EmptyConstruct{}) {} // Throws FutureInvalid if !this->core_ futures::detail::DeferredWrapper stealDeferredExecutor(); /// Blocks until the future is fulfilled, or `dur` elapses. /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - `valid() == true` /// - `&RESULT == this` /// - `isReady()` will be indeterminate - may or may not be true SemiFuture& wait(HighResDuration dur) &; static void releaseDeferredExecutor(Core* core); }; template std::pair, SemiFuture> makePromiseContract() { auto p = Promise(); auto f = p.getSemiFuture(); return std::make_pair(std::move(p), std::move(f)); } /// The interface (along with SemiFuture) for the consumer-side of a /// producer/consumer pair. /// /// Future vs. SemiFuture: /// /// - The consumer-side should generally start with a SemiFuture, not a Future. /// - Example, when a library creates and returns a future, it should usually /// return a `SemiFuture`, not a Future. /// - Reason: so the thread policy for continuations (`.thenValue`, etc.) can be /// specified by the library's caller (using `.via()`). /// - A SemiFuture is converted to a Future using `.via()`. /// - Use `makePromiseContract()` when creating both a Promise and an associated /// SemiFuture/Future. /// /// When practical, prefer SemiFuture/Future's nonblocking style/pattern: /// /// - the nonblocking style uses continuations, e.g., `.thenValue`, etc.; the /// continuations are deferred until the result is available. /// - the blocking style blocks until complete, e.g., `.wait()`, `.get()`, etc. /// - the two styles cannot be mixed within the same future; use one or the /// other. /// /// SemiFuture/Future also provide a back-channel so an interrupt can /// be sent from consumer to producer; see SemiFuture/Future's `raise()` /// and Promise's `setInterruptHandler()`. /// /// The consumer-side SemiFuture/Future objects should generally be accessed /// via a single thread. That thread is referred to as the 'consumer thread.' template class Future : private futures::detail::FutureBase { private: using Base = futures::detail::FutureBase; public: /// Type of the value that the producer, when successful, produces. using typename Base::value_type; /// Construct a Future from a value (perfect forwarding) /// /// Postconditions: /// /// - `valid() == true` /// - `isReady() == true` /// - `hasValue() == true` /// - `value()`, `get()`, `result()` will return the forwarded `T` template < class T2 = T, typename = typename std::enable_if< !isFuture::type>::value && !isSemiFuture::type>::value && std::is_constructible, T2>::value>::type> /* implicit */ Future(T2&& val) : Base(std::forward(val)) {} /// Construct a (logical) Future-of-void. /// /// Postconditions: /// /// - `valid() == true` /// - `isReady() == true` /// - `hasValue() == true` template /* implicit */ Future( typename std::enable_if::value>::type* p = nullptr) : Base(p) {} /// Construct a Future from a `T` constructed from `args` /// /// Postconditions: /// /// - `valid() == true` /// - `isReady() == true` /// - `hasValue() == true` /// - `hasException() == false` /// - `value()`, `get()`, `result()` will return the newly constructed `T` 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&& other) : Future(std::move(other).thenValue( [](T2&& v) { return T(std::move(v)); })) {} 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&& other) : Future(std::move(other).thenValue( [](T2&& v) { return T(std::move(v)); })) {} template < class T2, typename std::enable_if< !std::is_same::type>::value && std::is_constructible::value, int>::type = 0> Future& operator=(Future&& other) { return operator=( std::move(other).thenValue([](T2&& v) { return T(std::move(v)); })); } using Base::cancel; using Base::hasException; using Base::hasValue; using Base::isReady; using Base::poll; using Base::raise; using Base::result; using Base::setCallback_; using Base::valid; using Base::value; /// Creates/returns an invalid Future, that is, one with no shared state. /// /// Postcondition: /// /// - `RESULT.valid() == false` static Future makeEmpty(); // 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 fulfilled value (moved-out) or throws the fulfilled exception. T getVia(DrivableExecutor* e); /// Call e->drive() repeatedly until the future is fulfilled, or `dur` /// elapses. /// /// Returns the fulfilled value (moved-out), throws the fulfilled exception, /// or on timeout throws FutureTimeout. T getVia(TimedDrivableExecutor* e, HighResDuration dur); /// 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); /// getTryVia but will wait only until `dur` elapses. Returns the /// Try of the value (moved-out) or may throw a FutureTimeout exception. Try& getTryVia(TimedDrivableExecutor* e, HighResDuration dur); /// Unwraps the case of a Future> instance, and returns a simple /// Future instance. /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - Calling code should act as if `valid() == false`, /// i.e., as if `*this` was moved into RESULT. /// - `RESULT.valid() == true` template typename std:: enable_if::value, Future::Inner>>::type unwrap() &&; /// Returns a Future which will call back on the other side of executor. /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - `valid() == false` /// - `RESULT.valid() == true` Future via(Executor::KeepAlive<> executor) &&; Future via(Executor::KeepAlive<> executor, int8_t priority) &&; /// Returns a Future which will call back on the other side of executor. /// /// When practical, use the rvalue-qualified overload instead - it's faster. /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - `valid() == true` /// - `RESULT.valid() == true` /// - when `this` gets fulfilled, it automatically fulfills RESULT Future via(Executor::KeepAlive<> executor) &; Future via(Executor::KeepAlive<> executor, int8_t priority) &; /// When this Future has completed, execute func which is a function that /// can be called with either `T&&` or `Try&&`. /// /// Func shall return either another Future or a value. /// /// thenInline will run the continuation inline with the execution of the /// previous callback in the chain if the callback attached to the previous /// future that triggers execution of func runs on the same executor that func /// would be executed on. /// /// A Future for the return type of func is returned. /// /// Versions of these functions with Inline in the name will run the /// continuation inline if the executor the previous task completes on matches /// the executor the next is to be enqueued on to. /// /// Future f2 = f1.thenTry([](Try&&) { return string("foo"); }); /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - Calling code should act as if `valid() == false`, /// i.e., as if `*this` was moved into RESULT. /// - `RESULT.valid() == true` template Future::value_type> then( F&& func) && { return std::move(*this).thenTry(std::forward(func)); } template Future::value_type> thenInline(F&& func) && { return std::move(*this).thenTryInline(std::forward(func)); } /// Variant where func is an member function /// /// struct Worker { R doWork(Try); } /// /// Worker *w; /// Future f2 = f1.thenTry(&Worker::doWork, w); /// /// This is just sugar for /// /// f1.thenTry(std::bind(&Worker::doWork, w)); /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - Calling code should act as if `valid() == false`, /// i.e., as if `*this` was moved into RESULT. /// - `RESULT.valid() == true` template 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. /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - Calling code should act as if `valid() == false`, /// i.e., as if `*this` was moved into RESULT. /// - `RESULT.valid() == true` template auto then(Executor::KeepAlive<> x, Arg&& arg) && = delete; /// When this Future has completed, execute func which is a function that /// can be called with `Try&&` (often a lambda with parameter type /// `auto&&` or `auto`). /// /// Func shall return either another Future or a value. /// /// Versions of these functions with Inline in the name will run the /// continuation inline with the execution of the previous callback in the /// chain if the callback attached to the previous future that triggers /// execution of func runs on the same executor that func would be executed /// on. /// /// A Future for the return type of func is returned. /// /// Future f2 = std::move(f1).thenTry([](auto&& t) { /// ... /// return string("foo"); /// }); /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - `valid() == false` /// - `RESULT.valid() == true` template Future::value_type> thenTry( F&& func) &&; template Future::value_type> thenTryInline(F&& func) &&; template Future::value_type> thenExTry(F&& func) &&; template Future::value_type> thenExTryInline(F&& func) &&; template auto thenTry(R (&func)(Args...)) && { return std::move(*this).thenTry(&func); } template auto thenTryInline(R (&func)(Args...)) && { return std::move(*this).thenTryInline(&func); } /// When this Future has completed, execute func which is a function that /// can be called with `T&&` (often a lambda with parameter type /// `auto&&` or `auto`). /// /// Func shall return either another Future or a value. /// /// Versions of these functions with Inline in the name will run the /// continuation inline with the execution of the previous callback in the /// chain if the callback attached to the previous future that triggers /// execution of func runs on the same executor that func would be executed /// on. /// /// A Future for the return type of func is returned. /// /// Future f2 = f1.thenValue([](auto&& v) { /// ... /// return string("foo"); /// }); /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - `valid() == false` /// - `RESULT.valid() == true` template Future::value_type> thenValue(F&& func) &&; template Future::value_type> thenValueInline(F&& func) &&; template Future< typename futures::detail::valueExecutorCallableResult::value_type> thenExValue(F&& func) &&; template Future< typename futures::detail::valueExecutorCallableResult::value_type> thenExValueInline(F&& func) &&; template auto thenValue(R (&func)(Args...)) && { return std::move(*this).thenValue(&func); } template auto thenValueInline(R (&func)(Args...)) && { return std::move(*this).thenValueInline(&func); } /// Set an error continuation for this Future where the continuation can /// be called with a known exception type and returns a `T`, `Future`, or /// `SemiFuture`. /// /// Example: /// /// makeFuture() /// .thenTry([] { /// throw std::runtime_error("oh no!"); /// return 42; /// }) /// .thenError(folly::tag_t{}, [] (auto const& e) { /// LOG(INFO) << "std::runtime_error: " << e.what(); /// return -1; // or makeFuture(-1) or makeSemiFuture(-1) /// }); /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - `valid() == false` /// - `RESULT.valid() == true` template typename std::enable_if< isFutureOrSemiFuture>::value, Future>::type thenError(tag_t, F&& func) &&; template typename std::enable_if< !isFutureOrSemiFuture>::value, Future>::type thenError(tag_t, F&& func) &&; template Future thenError(tag_t tag, R (&func)(Args...)) && { return std::move(*this).thenError(tag, &func); } template Future thenError(F&& func) && { return std::move(*this).thenError( tag_t{}, std::forward(func)); } /// Set an error continuation for this Future where the continuation can /// be called with `exception_wrapper&&` and returns a `T`, `Future`, or /// `SemiFuture`. /// /// Example: /// /// makeFuture() /// .thenTry([] { /// throw std::runtime_error("oh no!"); /// return 42; /// }) /// .thenError([] (exception_wrapper&& e) { /// LOG(INFO) << e.what(); /// return -1; // or makeFuture(-1) or makeSemiFuture(-1) /// }); /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - `valid() == false` /// - `RESULT.valid() == true` template typename std::enable_if< isFutureOrSemiFuture>::value, Future>::type thenError(F&& func) &&; template typename std::enable_if< !isFutureOrSemiFuture>::value, Future>::type thenError(F&& func) &&; template Future thenError(R (&func)(Args...)) && { return std::move(*this).thenError(&func); } /// Convenience method for ignoring the value and creating a Future. /// Exceptions still propagate. /// This function is identical to .unit(). /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - Calling code should act as if `valid() == false`, /// i.e., as if `*this` was moved into RESULT. /// - `RESULT.valid() == true` Future then() &&; /// Convenience method for ignoring the value and creating a Future. /// Exceptions still propagate. /// This function is identical to parameterless .then(). /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - Calling code should act as if `valid() == false`, /// i.e., as if `*this` was moved into RESULT. /// - `RESULT.valid() == true` Future unit() && { return std::move(*this).then(); } /// Set an error continuation for this Future. The continuation should take an /// argument of the type that you want to catch, and should return a value of /// the same type as this Future, or a Future of that type (see overload /// below). /// /// Example: /// /// makeFuture() /// .thenValue([] { /// throw std::runtime_error("oh no!"); /// return 42; /// }) /// .thenError([] (std::runtime_error& e) { /// LOG(INFO) << "std::runtime_error: " << e.what(); /// return -1; // or makeFuture(-1) /// }); /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - Calling code should act as if `valid() == false`, /// i.e., as if `*this` was moved into RESULT. /// - `RESULT.valid() == true` template [[deprecated( "onError loses the attached executor and is weakly typed. Please move to thenError instead.")]] typename std::enable_if< !is_invocable_v && !futures::detail::Extract::ReturnsFuture::value, Future>::type onError(F&& func) && = delete; /// Overload of onError where the error continuation returns a Future /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - Calling code should act as if `valid() == false`, /// i.e., as if `*this` was moved into RESULT. /// - `RESULT.valid() == true` template [[deprecated( "onError loses the attached executor and is weakly typed. Please move to thenError instead.")]] typename std::enable_if< !is_invocable_v && futures::detail::Extract::ReturnsFuture::value, Future>::type onError(F&& func) && = delete; /// Overload of onError that takes exception_wrapper and returns Future /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - Calling code should act as if `valid() == false`, /// i.e., as if `*this` was moved into RESULT. /// - `RESULT.valid() == true` template [[deprecated( "onError loses the attached executor and is weakly typed. Please move to thenError instead.")]] typename std::enable_if< is_invocable_v && futures::detail::Extract::ReturnsFuture::value, Future>::type onError(F&& func) && = delete; /// Overload of onError that takes exception_wrapper and returns T /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - Calling code should act as if `valid() == false`, /// i.e., as if `*this` was moved into RESULT. /// - `RESULT.valid() == true` template [[deprecated( "onError loses the attached executor and is weakly typed. Please move to thenError instead.")]] typename std::enable_if< is_invocable_v && !futures::detail::Extract::ReturnsFuture::value, Future>::type onError(F&& func) && = delete; template Future onError(R (&func)(Args...)) && = delete; // clang-format off template [[deprecated( "onError loses the attached executor and is weakly typed. Please move to thenError instead.")]] Future onError(F&& func) & = delete; /// func is like std::function and is executed unconditionally, and /// the value/exception is passed through to the resulting 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. /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - Calling code should act as if `valid() == false`, /// i.e., as if `*this` was moved into RESULT. /// - `RESULT.valid() == true` template Future ensure(F&& func) &&; // clang-format on /// Like thenError, but for timeouts. example: /// /// Future f = makeFuture(42) /// .delayed(long_time) /// .onTimeout(short_time, /// [] { return -1; }); /// /// or perhaps /// /// Future f = makeFuture(42) /// .delayed(long_time) /// .onTimeout(short_time, /// [] { return makeFuture(some_exception); }); /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - Calling code should act as if `valid() == false`, /// i.e., as if `*this` was moved into RESULT. /// - `RESULT.valid() == true` template Future onTimeout(HighResDuration, F&& func, Timekeeper* = nullptr) &&; /// If this Future completes within duration dur from now, propagate its /// value. Otherwise satisfy the returned SemiFuture with a FutureTimeout /// exception. /// /// The optional Timekeeper is as with futures::sleep(). /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - Calling code should act as if `valid() == false`, /// i.e., as if `*this` was moved into RESULT. /// - `RESULT.valid() == true` Future within(HighResDuration dur, Timekeeper* tk = nullptr) &&; /// If this SemiFuture completes within duration dur from now, propagate its /// value. Otherwise satisfy the returned SemiFuture with exception e. /// /// The optional Timekeeper is as with futures::sleep(). /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - Calling code should act as if `valid() == false`, /// i.e., as if `*this` was moved into RESULT. /// - `RESULT.valid() == true` template Future within(HighResDuration dur, E exception, Timekeeper* tk = nullptr) &&; /// Delay the completion of this Future for at least this duration from /// now. The optional Timekeeper is as with futures::sleep(). /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - `valid() == false` /// - `RESULT.valid() == true` Future delayed(HighResDuration, Timekeeper* = nullptr) &&; /// Blocks until the future is fulfilled. Returns the value (moved-out), or /// throws the exception. The future must not already have a continuation. /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - `valid() == false` T get() &&; /// Blocks until the future is fulfilled, or until `dur` elapses. Returns the /// value (moved-out), or throws the exception (which might be a FutureTimeout /// exception). /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - `valid() == false` T get(HighResDuration dur) &&; /// A reference to the Try of the value /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// - `isReady() == true` (else throws FutureNotReady) Try& getTry(); /// Blocks until this Future is complete. /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - `valid() == true` /// - `&RESULT == this` /// - `isReady() == true` Future& wait() &; /// Blocks until this Future is complete. /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - `valid() == true` (but the calling code can trivially move-out `*this` /// by assigning or constructing the result into a distinct object). /// - `&RESULT == this` /// - `isReady() == true` Future&& wait() &&; /// Blocks until this Future is complete, or `dur` elapses. /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - `valid() == true` (so you may call `wait(...)` repeatedly) /// - `&RESULT == this` /// - `isReady()` will be indeterminate - may or may not be true Future& wait(HighResDuration dur) &; /// Blocks until this Future is complete or until `dur` passes. /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - `valid() == true` (but the calling code can trivially move-out `*this` /// by assigning or constructing the result into a distinct object). /// - `&RESULT == this` /// - `isReady()` will be indeterminate - may or may not be true Future&& wait(HighResDuration dur) &&; /// Call e->drive() repeatedly until the future is fulfilled. Examples /// of DrivableExecutor include EventBase and ManualExecutor. Returns a /// reference to this Future so that you can chain calls if desired. /// value (moved-out), or throws the exception. /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - `valid() == true` (does not move-out `*this`) /// - `&RESULT == this` Future& waitVia(DrivableExecutor* e) &; /// Overload of waitVia() for rvalue Futures /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - `valid() == true` (but the calling code can trivially move-out `*this` /// by assigning or constructing the result into a distinct object). /// - `&RESULT == this` Future&& waitVia(DrivableExecutor* e) &&; /// As waitVia but may return early after dur passes. /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - `valid() == true` (does not move-out `*this`) /// - `&RESULT == this` Future& waitVia(TimedDrivableExecutor* e, HighResDuration dur) &; /// Overload of waitVia() for rvalue Futures /// As waitVia but may return early after dur passes. /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - `valid() == true` (but the calling code can trivially move-out `*this` /// by assigning or constructing the result into a distinct object). /// - `&RESULT == this` Future&& waitVia(TimedDrivableExecutor* e, HighResDuration dur) &&; /// If the value in this Future is equal to the given Future, when they have /// both completed, the value of the resulting Future will be true. It /// will be false otherwise (including when one or both Futures have an /// exception) Future willEqual(Future&); /// predicate behaves like std::function /// If the predicate does not obtain with the value, the result /// is a folly::FuturePredicateDoesNotObtain exception /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - Calling code should act as if `valid() == false`, /// i.e., as if `*this` was moved into RESULT. /// - `RESULT.valid() == true` template Future filter(F&& predicate) &&; /// Like reduce, but works on a Future>>, for example /// the result of collect or collectAll /// /// Preconditions: /// /// - `valid() == true` (else throws FutureInvalid) /// /// Postconditions: /// /// - Calling code should act as if `valid() == false`, /// i.e., as if `*this` was moved into RESULT. /// - `RESULT.valid() == true` template Future reduce(I&& initial, F&& func) &&; /// Moves-out `*this`, creating/returning a corresponding SemiFuture. /// Result will behave like `*this` except result won't have an Executor. /// /// Postconditions: /// /// - `RESULT.valid() ==` the original value of `this->valid()` /// - RESULT will not have an Executor regardless of whether `*this` had one SemiFuture semi() && { return SemiFuture{std::move(*this)}; } #if FOLLY_HAS_COROUTINES // Overload needed to customise behaviour of awaiting a Future // inside a folly::coro::Task coroutine. friend Future co_viaIfAsync( folly::Executor::KeepAlive<> executor, Future&& future) noexcept { return std::move(future).via(std::move(executor)); } #endif protected: friend class Promise; template friend class futures::detail::FutureBase; template friend class Future; template friend class SemiFuture; template friend class FutureSplitter; using Base::setExecutor; using Base::throwIfContinued; using Base::throwIfInvalid; using typename Base::Core; explicit Future(Core* obj) : Base(obj) {} explicit Future(futures::detail::EmptyConstruct) noexcept : Base(futures::detail::EmptyConstruct{}) {} template friend Future makeFuture(Try); template friend Future futures::detail::convertFuture( SemiFuture&& sf, const Future& f); using Base::detach; template friend void futures::detachOn( folly::Executor::KeepAlive<> exec, folly::SemiFuture&& fut); }; /// A Timekeeper handles the details of keeping time and fulfilling delay /// promises. The returned Future will either complete after the /// elapsed time, or in the event of some kind of exceptional error may hold /// an exception. These Futures respond to cancellation. If you use a lot of /// Delays and many of them ultimately are unneeded (as would be the case for /// Delays that are used to trigger timeouts of async operations), then you /// can and should cancel them to reclaim resources. /// /// Users will typically get one of these via Future::sleep(HighResDuration dur) /// or use them implicitly behind the scenes by passing a timeout to some Future /// operation. /// /// Although we don't formally alias Delay = Future, /// that's an appropriate term for it. People will probably also call these /// Timeouts, and that's ok I guess, but that term is so overloaded I thought /// it made sense to introduce a cleaner term. /// /// Remember that HighResDuration is a std::chrono duration (millisecond /// resolution at the time of writing). When writing code that uses specific /// durations, prefer using the explicit std::chrono type, e.g. /// std::chrono::milliseconds over HighResDuration. This makes the code more /// legible and means you won't be unpleasantly surprised if we redefine /// HighResDuration to microseconds, or something. /// /// timekeeper.after(std::chrono::duration_cast(someNanoseconds)) class Timekeeper { public: virtual ~Timekeeper() = default; /// Returns a future that will complete after the given duration with the /// elapsed time. Exceptional errors can happen but they must be /// exceptional. Use the steady (monotonic) clock. /// /// The consumer thread may cancel this Future to reclaim resources. virtual SemiFuture after(HighResDuration dur) = 0; /// Unsafe version of after that returns an inline Future. /// Any work added to this future will run inline on the Timekeeper's thread. /// This can potentially cause problems with timing. /// /// Please migrate to use after + a call to via with a valid, non-inline /// executor. Future afterUnsafe(HighResDuration dur) { return after(dur).toUnsafeFuture(); } /// Returns a future that will complete at the requested time. /// /// You may cancel this SemiFuture to reclaim resources. /// /// NB This is sugar for `after(when - now)`, so while you are welcome to /// use a std::chrono::system_clock::time_point it will not track changes to /// the system clock but rather execute that many milliseconds in the future /// according to the steady clock. template SemiFuture at(std::chrono::time_point when); /// Unsafe version of at that returns an inline Future. /// Any work added to this future will run inline on the Timekeeper's thread. /// This can potentially cause problems with timing. /// /// Please migrate to use at + a call to via with a valid, non-inline /// executor. template Future atUnsafe(std::chrono::time_point when) { return at(when).toUnsafeFuture(); } }; template std::pair, Future> makePromiseContract(Executor::KeepAlive<> e) { auto p = Promise(); auto f = p.getSemiFuture().via(std::move(e)); return std::make_pair(std::move(p), std::move(f)); } template auto makeAsyncTask(folly::Executor::KeepAlive<> ka, F&& func) { return [func = std::forward(func), ka = std::move(ka)](auto&& param) mutable { return via( ka, [func = std::move(func), param = std::forward(param)]() mutable { return func(std::forward(param)); }); }; } /// 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 /// HighResDuration 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. SemiFuture sleep(HighResDuration, Timekeeper* = nullptr); [[deprecated( "futures::sleep now returns a SemiFuture. " "sleepUnsafe is deprecated. " "Please call futures::sleep and apply an executor with .via")]] Future sleepUnsafe(HighResDuration, Timekeeper* = nullptr); /** * Set func as the callback for each input Future and return a vector of * Futures containing the results in the input order. */ template < class It, class F, class ItT = typename std::iterator_traits::value_type, class Tag = std::enable_if_t>, class Result = typename decltype( std::declval().thenValue(std::declval()))::value_type> std::vector> mapValue(It first, It last, F func); /** * Set func as the callback for each input Future and return a vector of * Futures containing the results in the input order. */ template < class It, class F, class ItT = typename std::iterator_traits::value_type, class Tag = std::enable_if_t>, class Result = typename decltype( std::declval().thenTry(std::declval()))::value_type> std::vector> mapTry(It first, It last, F func, int = 0); /** * Set func as the callback for each input Future and return a vector of * Futures containing the results in the input order and completing on * exec. */ template < class It, class F, class ItT = typename std::iterator_traits::value_type, class Tag = std::enable_if_t>, class Result = typename decltype(std::move(std::declval()) .via(std::declval()) .thenValue(std::declval()))::value_type> std::vector> mapValue(Executor& exec, It first, It last, F func); /** * Set func as the callback for each input Future and return a vector of * Futures containing the results in the input order and completing on * exec. */ template < class It, class F, class ItT = typename std::iterator_traits::value_type, class Tag = std::enable_if_t>, class Result = typename decltype(std::move(std::declval()) .via(std::declval()) .thenTry(std::declval()))::value_type> std::vector> mapTry(Executor& exec, It first, It last, F func, int = 0); // Sugar for the most common case template auto mapValue(Collection&& c, F&& func) -> decltype(mapValue(c.begin(), c.end(), func)) { return mapValue(c.begin(), c.end(), std::forward(func)); } template auto mapTry(Collection&& c, F&& func) -> decltype(mapTry(c.begin(), c.end(), func)) { return mapTry(c.begin(), c.end(), std::forward(func)); } // Sugar for the most common case template auto mapValue(Executor& exec, Collection&& c, F&& func) -> decltype(mapValue(exec, c.begin(), c.end(), func)) { return mapValue(exec, c.begin(), c.end(), std::forward(func)); } template auto mapTry(Executor& exec, Collection&& c, F&& func) -> decltype(mapTry(exec, c.begin(), c.end(), func)) { return mapTry(exec, c.begin(), c.end(), std::forward(func)); } /// Carry out the computation contained in the given future if /// the predicate holds. /// /// thunk behaves like std::function(void)> or /// std::function(void)> template auto when(bool p, F&& thunk) -> decltype(std::declval>().unit()); #if FOLLY_FUTURE_USING_FIBER SemiFuture wait(std::unique_ptr baton); SemiFuture wait(std::shared_ptr baton); #endif /** * Returns a lazy SemiFuture constructed by f, which also ensures that ensure is * called before completion. * f doesn't get called until the SemiFuture is activated (e.g. through a .get() * or .via() call). If f gets called, ensure is guaranteed to be called as well. */ template auto ensure(F&& f, Ensure&& ensure); } // namespace futures /** Make a completed SemiFuture by moving in a value. e.g. string foo = "foo"; auto f = makeSemiFuture(std::move(foo)); or auto f = makeSemiFuture("foo"); */ template SemiFuture::type> makeSemiFuture(T&& t); /** Make a completed void SemiFuture. */ SemiFuture makeSemiFuture(); /** Make a SemiFuture by executing a function. If the function returns a value of type T, makeSemiFutureWith returns a completed SemiFuture, capturing the value returned by the function. If the function returns a SemiFuture already, makeSemiFutureWith returns just that. Either way, if the function throws, a failed Future is returned that captures the exception. */ // makeSemiFutureWith(SemiFuture()) -> SemiFuture template typename std::enable_if< isFutureOrSemiFuture>::value, SemiFuture::value_type>>::type makeSemiFutureWith(F&& func); // makeSemiFutureWith(T()) -> SemiFuture // makeSemiFutureWith(void()) -> SemiFuture template typename std::enable_if< !(isFutureOrSemiFuture>::value), SemiFuture>>>::type makeSemiFutureWith(F&& func); /// 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 = makeSemiFuture(std::current_exception()); template [[deprecated("use makeSemiFuture(exception_wrapper)")]] SemiFuture makeSemiFuture(std::exception_ptr const& e); /// Make a failed SemiFuture from an exception_wrapper. template SemiFuture makeSemiFuture(exception_wrapper ew); /** Make a SemiFuture from an exception type E that can be passed to std::make_exception_ptr(). */ template typename std:: enable_if::value, SemiFuture>::type makeSemiFuture(E const& e); /** Make a Future out of a Try */ template SemiFuture makeSemiFuture(Try t); /** Make a completed Future by moving in a value. e.g. string foo = "foo"; auto f = makeFuture(std::move(foo)); or auto f = makeFuture("foo"); NOTE: This function is deprecated. Please use makeSemiFuture and pass the appropriate executor to .via on the returned SemiFuture to get a valid Future where necessary. */ template Future::type> makeFuture(T&& t); /** Make a completed void Future. NOTE: This function is deprecated. Please use makeSemiFuture and pass the appropriate executor to .via on the returned SemiFuture to get a valid Future where necessary. */ Future makeFuture(); /** Make a Future by executing a function. If the function returns a value of type T, makeFutureWith returns a completed Future, capturing the value returned by the function. If the function returns a Future already, makeFutureWith returns just that. Either way, if the function throws, a failed Future is returned that captures the exception. Calling makeFutureWith(func) is equivalent to calling makeFuture().then(func). NOTE: This function is deprecated. Please use makeSemiFutureWith and pass the appropriate executor to .via on the returned SemiFuture to get a valid Future where necessary. */ // makeFutureWith(Future()) -> Future template typename std:: enable_if>::value, invoke_result_t>::type makeFutureWith(F&& func); // makeFutureWith(T()) -> Future // makeFutureWith(void()) -> Future template typename std::enable_if< !(isFuture>::value), Future>>>::type makeFutureWith(F&& func); /// 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 [[deprecated("use makeSemiFuture(exception_wrapper)")]] Future makeFuture( std::exception_ptr const& e); /// Make a failed Future from an exception_wrapper. /// NOTE: This function is deprecated. Please use makeSemiFuture and pass the /// appropriate executor to .via on the returned SemiFuture to get a /// valid Future where necessary. template Future makeFuture(exception_wrapper ew); /** Make a Future from an exception type E that can be passed to std::make_exception_ptr(). NOTE: This function is deprecated. Please use makeSemiFuture and pass the appropriate executor to .via on the returned SemiFuture to get a valid Future where necessary. */ template typename std::enable_if::value, Future>:: type makeFuture(E const& e); /** Make a Future out of a Try NOTE: This function is deprecated. Please use makeSemiFuture and pass the appropriate executor to .via on the returned SemiFuture to get a valid Future where necessary. */ template Future makeFuture(Try t); /* * 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 * @param priority optionally, the priority to add with. Defaults to 0 which * represents medium priority. * * @returns a void Future that will call back on the given executor */ inline Future via(Executor::KeepAlive<> executor); inline Future via(Executor::KeepAlive<> executor, int8_t priority); /// Execute a function via the given executor and return a future. /// This is semantically equivalent to via(executor).then(func), but /// easier to read and slightly more efficient. template auto via(Executor::KeepAlive<>, Func&& func) -> Future< typename isFutureOrSemiFuture()())>::Inner>; /** 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 SemiFuture>> for collectX and collectXSemiFuture. collectXUnsafe returns an inline Future that erases the executor from the incoming Futures/SemiFutures. collectXUnsafe should be phased out and replaced with collectX(...).via(e) where e is a valid non-inline executor. */ template SemiFuture::value_type::value_type>>> collectAllSemiFuture(InputIterator first, InputIterator last); /// Sugar for the most common case template auto collectAllSemiFuture(Collection&& c) -> decltype(collectAllSemiFuture(c.begin(), c.end())) { return collectAllSemiFuture(c.begin(), c.end()); } // Unsafe variant, see above comment for details template Future::value_type::value_type>>> collectAllUnsafe(InputIterator first, InputIterator last); // Unsafe variant sugar, see above comment for details template auto collectAllUnsafe(Collection&& c) -> decltype(collectAllUnsafe(c.begin(), c.end())) { return collectAllUnsafe(c.begin(), c.end()); } template SemiFuture::value_type::value_type>>> collectAll(InputIterator first, InputIterator last); template auto collectAll(Collection&& c) -> decltype(collectAll(c.begin(), c.end())) { return collectAll(c.begin(), c.end()); } /// This version takes a varying number of Futures instead of an iterator. /// The return type for (Future, Future, ...) input /// is a SemiFuture, Try, ...>>. /// The Futures are moved in, so your copies are invalid. template SemiFuture::value_type>...>> collectAllSemiFuture(Fs&&... fs); // Unsafe variant of collectAll, see coment above for details. Returns // a Future, Try, ...>> on the Inline executor. template Future::value_type>...>> collectAllUnsafe(Fs&&... fs); template SemiFuture::value_type>...>> collectAll(Fs&&... fs); /// Like collectAll, but will short circuit on the first exception. Thus, the /// type of the returned SemiFuture is std::vector instead of /// std::vector> template SemiFuture::value_type::value_type>> collect(InputIterator first, InputIterator last); /// Sugar for the most common case template auto collect(Collection&& c) -> decltype(collect(c.begin(), c.end())) { return collect(c.begin(), c.end()); } // Unsafe variant of collect. Returns a Future> that // completes inline. template Future::value_type::value_type>> collectUnsafe(InputIterator first, InputIterator last); /// Sugar for the most common unsafe case. Returns a Future> // that completes inline. template auto collectUnsafe(Collection&& c) -> decltype(collectUnsafe(c.begin(), c.end())) { return collectUnsafe(c.begin(), c.end()); } /// Like collectAll, but will short circuit on the first exception. Thus, the /// type of the returned SemiFuture is std::tuple instead of /// std::tuple, Try, ...> template SemiFuture::value_type...>> collect( Fs&&... fs); /** 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 SemiFuture::value_type::value_type>>> collectAny(InputIterator first, InputIterator last); // Unsafe variant of collectAny, Returns a Future that completes inline. template Future::value_type::value_type>>> collectAnyUnsafe(InputIterator first, InputIterator last); template SemiFuture::value_type::value_type>>> collectAnySemiFuture(InputIterator first, InputIterator last); /// Sugar for the most common case template auto collectAny(Collection&& c) -> decltype(collectAny(c.begin(), c.end())) { return collectAny(c.begin(), c.end()); } // Unsafe variant of common form of collectAny, Returns a Future that completes // inline. template auto collectAnyUnsafe(Collection&& c) -> decltype(collectAnyUnsafe(c.begin(), c.end())) { return collectAnyUnsafe(c.begin(), c.end()); } template auto collectAnySemiFuture(Collection&& c) -> decltype(collectAnySemiFuture(c.begin(), c.end())) { return collectAnySemiFuture(c.begin(), c.end()); } /** Similar to collectAny, collectAnyWithoutException return the first Future to * complete without exceptions. If none of the future complete without * exceptions, the last exception will be returned as a result. */ template SemiFuture::value_type::value_type>> collectAnyWithoutException(InputIterator first, InputIterator last); /// Sugar for the most common case template auto collectAnyWithoutException(Collection&& c) -> decltype(collectAnyWithoutException(c.begin(), c.end())) { return collectAnyWithoutException(c.begin(), c.end()); } /** 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 SemiFuture::value_type::value_type>>>> collectN(InputIterator first, InputIterator last, size_t n); /// Sugar for the most common case template auto collectN(Collection&& c, size_t n) -> decltype(collectN(c.begin(), c.end(), n)) { return collectN(c.begin(), c.end(), n); } /** window creates up to n Futures using the values in the collection, and then another Future for each Future that completes this is basically a sliding window of Futures of size n func must return a Future for each value in input */ template < class Collection, class F, class ItT = typename std::iterator_traits< typename Collection::iterator>::value_type, class Result = typename invoke_result_t::value_type> std::vector> window(Collection input, F func, size_t n); template < class Collection, class F, class ItT = typename std::iterator_traits< typename Collection::iterator>::value_type, class Result = typename invoke_result_t::value_type> std::vector> window(Executor::KeepAlive<> executor, Collection input, F func, size_t n); template using MaybeTryArg = typename std:: conditional&&>, Try, ItT>::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 func is called in order of the input, see unorderedReduce if that is not a requirement */ template Future reduce(It first, It last, T&& initial, F&& func); /// Sugar for the most common case template auto reduce(Collection&& c, T&& initial, F&& func) -> decltype(folly::reduce( c.begin(), c.end(), std::forward(initial), std::forward(func))) { return folly::reduce( c.begin(), c.end(), std::forward(initial), std::forward(func)); } /** like reduce, but calls func on finished futures as they complete does NOT keep the order of the input */ template Future unorderedReduce(It first, It last, T initial, F func); /// Sugar for the most common case template auto unorderedReduce(Collection&& c, T&& initial, F&& func) -> decltype(folly::unorderedReduce( c.begin(), c.end(), std::forward(initial), std::forward(func))) { return folly::unorderedReduce( c.begin(), c.end(), std::forward(initial), std::forward(func)); } /// Carry out the computation contained in the given future if /// while the predicate continues to hold. /// /// if thunk behaves like std::function(void)> /// returns Future /// if thunk behaves like std::function(void)> /// returns SemiFuture /// predicate behaves like std::function template typename std::enable_if>::value, Future>::type whileDo(P&& predicate, F&& thunk); template typename std:: enable_if>::value, SemiFuture>::type whileDo(P&& predicate, F&& thunk); /// Repeat the given future (i.e., the computation it contains) n times. /// /// thunk behaves like /// std::function(void)> /// or /// std::function(void)> template auto times(int n, F&& thunk); } // namespace folly #if FOLLY_HAS_COROUTINES namespace folly { namespace detail { template class FutureAwaitable { public: explicit FutureAwaitable(folly::Future&& future) noexcept : future_(std::move(future)) {} bool await_ready() { if (future_.isReady()) { result_ = std::move(future_.getTry()); return true; } return false; } T await_resume() { return std::move(result_).value(); } Try await_resume_try() { return std::move(result_); } FOLLY_CORO_AWAIT_SUSPEND_NONTRIVIAL_ATTRIBUTES void await_suspend( std::experimental::coroutine_handle<> h) { // FutureAwaitable may get destroyed as soon as the callback is executed. // Make sure the future object doesn't get destroyed until setCallback_ // returns. auto future = std::move(future_); future.setCallback_( [this, h](Executor::KeepAlive<>&&, Try&& result) mutable { result_ = std::move(result); h.resume(); }); } private: folly::Future future_; folly::Try result_; }; } // namespace detail template inline detail::FutureAwaitable /* implicit */ operator co_await(Future&& future) noexcept { return detail::FutureAwaitable(std::move(future)); } } // namespace folly #endif #include