Rocket.Chat.ReactNative/ios/Pods/Flipper-Folly/folly/futures/Promise.h

462 lines
17 KiB
C
Raw Normal View History

/*
* 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 <functional>
#include <folly/Portability.h>
#include <folly/Try.h>
#include <folly/futures/detail/Core.h>
#include <folly/lang/Exception.h>
namespace folly {
class FOLLY_EXPORT PromiseException : public std::logic_error {
public:
using std::logic_error::logic_error;
};
class FOLLY_EXPORT PromiseInvalid : public PromiseException {
public:
PromiseInvalid() : PromiseException("Promise invalid") {}
};
class FOLLY_EXPORT PromiseAlreadySatisfied : public PromiseException {
public:
PromiseAlreadySatisfied() : PromiseException("Promise already satisfied") {}
};
class FOLLY_EXPORT FutureAlreadyRetrieved : public PromiseException {
public:
FutureAlreadyRetrieved() : PromiseException("Future already retrieved") {}
};
class FOLLY_EXPORT BrokenPromise : public PromiseException {
public:
explicit BrokenPromise(const std::string& type)
: PromiseException("Broken promise for type name `" + type + '`') {}
explicit BrokenPromise(const char* type) : BrokenPromise(std::string(type)) {}
};
// forward declaration
template <class T>
class SemiFuture;
template <class T>
class Future;
template <class T>
class Promise;
namespace futures {
namespace detail {
template <class T>
class FutureBase;
struct EmptyConstruct {};
template <typename T, typename F>
class CoreCallbackState;
template <typename T>
void setTry(Promise<T>& p, Executor::KeepAlive<>&& ka, Try<T>&& t);
} // namespace detail
} // namespace futures
/// Promises and futures provide a potentially nonblocking mechanism
/// to execute a producer/consumer operation concurrently, with
/// threading/pools controlled via an executor. There are multiple potential
/// patterns for using promises and futures including some that block the
/// caller, though that is discouraged; it should be used only when necessary.
///
/// One typical pattern uses a series of calls to set up a small, limited
/// program that...
///
/// - ...performs the desired operations (based on a lambda)...
/// - ...on an asynchronously provided input (an exception or a value)...
/// - ...lazily, when that input is ready (without blocking the caller)...
/// - ...using appropriate execution resources (determined by the executor)...
/// - ...then after constructing the 'program,' launches the asynchronous
/// producer.
///
/// That usage pattern looks roughly like this:
///
/// auto [p, f] = makePromiseContract(executor);
/// g = std::move(f).then([](MyValue&& x) {
/// ...executor runs this code if/when a MyValue is ready...
/// });
/// ...launch the async producer that eventually calls p.setResult()...
///
/// This is just one of many potential usage patterns. It has the desired
/// property of being nonblocking to the caller. Of course the `.then()`
/// code is deferred until the produced value (or exception) is ready,
/// but no code actually blocks pending completion of other operations.
///
/// The promise/future mechanism is limited to a single object of some arbitrary
/// type. It also supports a (logically) void result, i.e., in cases where the
/// continuation/consumer (the `.then()` code if using the above pattern) is not
/// expecting a value because the 'producer' is running for its side-effects.
///
/// The primary data movement is from producer to consumer, however Promise and
/// Future also provide a mechanism where the consumer can send an interruption
/// message to the producer. The meaning and response to that interruption
/// message is controlled by the promise; see `Promise::setInterruptHandler()`.
///
/// Neither Promise nor Future is thread-safe. All internal interactions
/// between a promise and its associated future are thread-safe, provided that
/// callers otherwise honor the promise's contract and the future's contract.
///
/// Logically there are up to three threads (though in practice there are often
/// fewer - one thread might take on more than one role):
///
/// - Set-up thread: thread used to construct the Promise, and often also to
/// set up the SemiFuture/Future.
/// - Producer thread: thread that produces the result.
/// - Consumer thread: thread in which the continuation is invoked (a
/// continuation is a callback provided to `.then` or to a variant).
///
/// For description purposes, the term 'shared state' is used to describe the
/// logical state shared by the promise and the future. This 'third object'
/// represents things like whether the result has been fulfilled, the value or
/// exception in that result, and the data needed to handle interruption
/// requests.
///
/// A promise can be in various logical states:
///
/// - valid vs. invalid (has vs. does not have a shared state, respectfully).
/// - fulfilled vs. unfulfilled (an invalid promise is always fulfilled; a valid
/// promise is fulfilled if the shared-state has a result).
///
/// A promise `p` may optionally have an associated future. This future, if it
/// exists, may be either a SemiFuture or a Future, and is defined as the
/// future (if any) that holds the same shared state as promise `p`.
/// The associated future is initially the future returned from
/// `p.getFuture()` or `p.getSemiFuture()`, but various operations
/// may transfer the shared state from one future to another.
template <class T>
class Promise {
public:
/// Returns an invalid promise.
///
/// Postconditions:
///
/// - `RESULT.valid() == false`
/// - `RESULT.isFulfilled() == true`
static Promise<T> makeEmpty() noexcept;
/// Constructs a valid but unfulfilled promise.
///
/// Postconditions:
///
/// - `valid() == true` (it will have a shared state)
/// - `isFulfilled() == false` (its shared state won't have a result)
Promise();
/// Postconditions:
///
/// - If `valid()` and `!isFulfilled()`, the associated future (if any) will
/// be completed with a `BrokenPromise` exception *as if* by
/// `setException(...)`.
/// - If `valid()`, releases, possibly destroying, the shared state.
~Promise();
// not copyable
Promise(Promise const&) = delete;
Promise& operator=(Promise const&) = delete;
/// Move ctor
///
/// Postconditions:
///
/// - `this` will have whatever shared-state was previously held by `other`
/// (if any)
/// - `other.valid()` will be false (`other` will not have any shared state)
Promise(Promise<T>&& other) noexcept;
/// Move assignment
///
/// Postconditions:
///
/// - If `valid()` and `!isFulfilled()`, the associated future (if any) will
/// be completed with a `BrokenPromise` exception *as if* by
/// `setException(...)`.
/// - If `valid()`, releases, possibly destroying, the original shared state.
/// - `this` will have whatever shared-state was previously held by `other`
/// (if any)
/// - `other.valid()` will be false (`other` will not have any shared state)
Promise& operator=(Promise<T>&& other) noexcept;
/// Return a SemiFuture associated with this Promise, sharing the same shared
/// state as `this`.
///
/// Preconditions:
///
/// - `valid() == true` (else throws PromiseInvalid)
/// - neither getSemiFuture() nor getFuture() may have been called previously
/// on `this` Promise (else throws FutureAlreadyRetrieved)
///
/// Postconditions:
///
/// - `RESULT.valid() == true`
/// - RESULT will share the same shared-state as `this`
///
/// DEPRECATED: use `folly::makePromiseContract()` instead.
SemiFuture<T> getSemiFuture();
/// Return a Future associated with this Promise, sharing the same shared
/// state as `this`.
///
/// Preconditions:
///
/// - `valid() == true` (else throws PromiseInvalid)
/// - neither getSemiFuture() nor getFuture() may have been called previously
/// on `this` Promise (else throws FutureAlreadyRetrieved)
///
/// Postconditions:
///
/// - `RESULT.valid() == true`
/// - RESULT will share the same shared-state as `this`
///
/// DEPRECATED: use `folly::makePromiseContract()` instead. If you can't use
/// that, use `this->getSemiFuture()` then get a Future by calling `.via()`
/// with an appropriate executor.
Future<T> getFuture();
/// Fulfill the Promise with an exception_wrapper.
///
/// Sample usage:
///
/// Promise<MyValue> p = ...
/// ...
/// auto const ep = std::exception_ptr();
/// auto const ew = exception_wrapper::from_exception_ptr(ep);
/// p.setException(ew);
///
/// Functionally equivalent to `setTry(Try<T>(std::move(ew)))`
///
/// Preconditions:
///
/// - `valid() == true` (else throws PromiseInvalid)
/// - `isFulfilled() == false` (else throws PromiseAlreadySatisfied)
///
/// Postconditions:
///
/// - `isFulfilled() == true`
/// - `valid() == true` (unchanged)
/// - The associated future (if any) will complete with the exception.
void setException(exception_wrapper ew);
/// Fulfill the Promise with exception `e` *as if* by
/// `setException(make_exception_wrapper<E>(e))`.
///
/// Please see `setException(exception_wrapper)` for semantics/contract.
template <class E>
typename std::enable_if<std::is_base_of<std::exception, E>::value>::type
setException(E const& e);
/// Sets a handler for the producer to receive a (logical) interruption
/// request (exception) sent from the consumer via `future.raise()`.
///
/// Details: The consumer calls `future.raise()` when it wishes to send a
/// logical interruption message (an exception), and that exception/message
/// is passed to `fn()`. The thread used to call `fn()` depends on timing
/// (see Postconditions for threading details).
///
/// Handler `fn()` can do anything you want, but if you bother to set one
/// then you probably will want to (more or less immediately) fulfill the
/// promise with an exception (or other special value) indicating how the
/// interrupt was handled.
///
/// This call silently does nothing if `isFulfilled()`.
///
/// Preconditions:
///
/// - `valid() == true` (else throws PromiseInvalid)
/// - `fn` must be copyable and must be invocable with
/// `exception_wrapper const&`
/// - the code within `fn()` must be safe to run either synchronously within
/// the `setInterruptHandler()` call or asynchronously within the consumer
/// thread's call to `future.raise()`.
/// - the code within `fn()` must also be safe to run after this promise is
/// fulfilled; this may have lifetime/race-case ramifications, e.g., if the
/// code of `fn()` might access producer-resources that will be destroyed,
/// then the destruction of those producer-resources must be deferred beyond
/// the moment when this promise is fulfilled.
///
/// Postconditions:
///
/// - if the consumer calls `future.raise()` early enough (up to a particular
/// moment within the `setInterruptHandler()` call), `fn()` will be called
/// synchronously (in the current thread, during this call).
/// - if the consumer calls `future.raise()` after that moment within
/// `setInterruptHandler()` but before this promise is fulfilled, `fn()`
/// will be called asynchronously (in the consumer's thread, within the call
/// to `future.raise()`).
/// - if the consumer calls `future.raise()` after this promise is fulfilled,
/// `fn()` may or may not be called at all, and if it is called, it will be
/// called asynchronously (within the consumer's call to `future.raise()`).
///
/// IMPORTANT: `fn()` should return quickly since it could block this call
/// to `promise.setInterruptHandler()` and/or a concurrent call to
/// `future.raise()`. Those two functions contend on the same lock; those
/// calls could block if `fn()` is invoked within one of those while the
/// lock is held.
template <typename F>
void setInterruptHandler(F&& fn);
/// Fulfills a (logically) void Promise, that is, Promise<Unit>.
/// (If you want a void-promise, use Promise<Unit>, not Promise<void>.)
///
/// Preconditions:
///
/// - `valid() == true` (else throws PromiseInvalid)
/// - `isFulfilled() == false` (else throws PromiseAlreadySatisfied)
///
/// Postconditions:
///
/// - `isFulfilled() == true`
/// - `valid() == true` (unchanged)
template <class B = T>
typename std::enable_if<std::is_same<Unit, B>::value, void>::type setValue() {
setTry(Try<T>(T()));
}
/// Fulfill the Promise with the specified value using perfect forwarding.
///
/// Functionally equivalent to `setTry(Try<T>(std::forward<M>(value)))`
///
/// Preconditions:
///
/// - `valid() == true` (else throws PromiseInvalid)
/// - `isFulfilled() == false` (else throws PromiseAlreadySatisfied)
///
/// Postconditions:
///
/// - `isFulfilled() == true`
/// - `valid() == true` (unchanged)
/// - The associated future will see the value, e.g., in its continuation.
template <class M>
void setValue(M&& value);
/// Fulfill the Promise with the specified Try (value or exception).
///
/// Preconditions:
///
/// - `valid() == true` (else throws PromiseInvalid)
/// - `isFulfilled() == false` (else throws PromiseAlreadySatisfied)
///
/// Postconditions:
///
/// - `isFulfilled() == true`
/// - `valid() == true` (unchanged)
/// - The associated future will see the result, e.g., in its continuation.
void setTry(Try<T>&& t);
/// Fulfill this Promise with the result of a function that takes no
/// arguments and returns something implicitly convertible to T.
///
/// Example:
///
/// p.setWith([] { do something that may throw; return a T; });
///
/// Functionally equivalent to `setTry(makeTryWith(static_cast<F&&>(func)));`
///
/// Preconditions:
///
/// - `valid() == true` (else throws PromiseInvalid)
/// - `isFulfilled() == false` (else throws PromiseAlreadySatisfied)
///
/// Postconditions:
///
/// - `func()` will be run synchronously (in this thread, during this call)
/// - If `func()` returns, the return value will be captured as if via
/// `setValue()`
/// - If `func()` throws, the exception will be captured as if via
/// `setException()`
/// - `isFulfilled() == true`
/// - `valid() == true` (unchanged)
/// - The associated future will see the result, e.g., in its continuation.
template <class F>
void setWith(F&& func);
/// true if this has a shared state;
/// false if this has been consumed/moved-out.
bool valid() const noexcept {
return core_ != nullptr;
}
/// True if either this promise was fulfilled or is invalid.
///
/// - True if `!valid()`
/// - True if `valid()` and this was fulfilled (a prior call to `setValue()`,
/// `setTry()`, `setException()`, or `setWith()`)
bool isFulfilled() const noexcept;
private:
template <class>
friend class futures::detail::FutureBase;
template <class>
friend class SemiFuture;
template <class>
friend class Future;
template <class, class>
friend class futures::detail::CoreCallbackState;
friend void futures::detail::setTry<T>(
Promise<T>& p,
Executor::KeepAlive<>&& ka,
Try<T>&& t);
// Whether the Future has been retrieved (a one-time operation).
bool retrieved_;
using Core = futures::detail::Core<T>;
// Throws PromiseInvalid 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(core_);
}
Core const& getCore() const {
return getCoreImpl(core_);
}
template <typename CoreT>
static CoreT& getCoreImpl(CoreT* core) {
if (!core) {
throw_exception<PromiseInvalid>();
}
return *core;
}
/// Fulfill the Promise with the specified Try (value or exception) and
/// propagate the completing executor.
void setTry(Executor::KeepAlive<>&& ka, Try<T>&& t);
// shared core state object
// usually you should use `getCore()` instead of directly accessing `core_`.
Core* core_;
explicit Promise(futures::detail::EmptyConstruct) noexcept;
void throwIfFulfilled() const;
void detach();
};
} // namespace folly
#include <folly/futures/Future.h>
#include <folly/futures/Promise-inl.h>