24 #ifndef LELY_EV_FUTURE_HPP_ 25 #define LELY_EV_FUTURE_HPP_ 46 using ::std::runtime_error::runtime_error;
49 template <
class,
class = ::std::error_code>
59 template <
class T,
class E = ::std::error_code>
74 if (!promise_) util::throw_errc(
"Promise");
78 [](
void* ptr) noexcept {
95 other.promise_ =
nullptr;
106 if (promise_ != other.promise_) {
124 swap(promise_, other.promise_);
136 operator ev_promise_t*()
const noexcept {
return promise_; }
139 explicit operator bool() const noexcept {
return promise_ !=
nullptr; }
198 template <
class F,
class... Args,
class R = compat::invoke_result_t<F, Args...>>
199 inline typename ::std::enable_if<!::std::is_void<R>::value,
201 catch_result(F&& f, Args&&... args) {
203 return util::success(
204 compat::invoke(::std::forward<F>(f), ::std::forward<Args>(args)...));
206 return util::failure(::std::current_exception());
210 template <
class F,
class... Args,
class R = compat::invoke_result_t<F, Args...>>
211 inline typename ::std::enable_if<::std::is_void<R>::value,
213 catch_result(F&& f, Args&&... args) {
215 compat::invoke(::std::forward<F>(f), ::std::forward<Args>(args)...);
216 return util::success();
218 return util::failure(::std::current_exception());
225 template <
class T,
class E>
228 template <
class,
class =
void>
231 template <
class Invoker>
232 class AsyncTask<Invoker, typename ::std::enable_if<!is_future<
233 compat::invoke_result_t<Invoker>>::value>::type>
236 using value_type = compat::invoke_result_t<Invoker>;
237 using error_type = ::std::exception_ptr;
240 template <
class F,
class... Args>
242 Args&&... args) noexcept
245 auto self =
static_cast<AsyncTask*
>(task);
246 auto promise = ::std::move(self->promise_);
248 self->result_ = catch_result(self->invoker_);
250 promise, ::std::addressof(self->result_));
254 invoker_(::std::forward<F>(f), ::std::forward<Args>(args)...) {}
261 get_executor()
const noexcept {
266 get_future()
const noexcept {
267 return promise_.get_future();
276 template <
class Invoker>
277 class AsyncTask<Invoker, typename ::std::enable_if<is_future<
278 compat::invoke_result_t<Invoker>>::value>::type>
280 using inner_future_type = compat::invoke_result_t<Invoker>;
283 using value_type =
typename inner_future_type::result_type::value_type;
284 using error_type = ::std::exception_ptr;
287 template <
class F,
class... Args>
289 Args&&... args) noexcept
293 auto self =
static_cast<AsyncTask*
>(task);
296 auto self =
static_cast<AsyncTask*
>(task);
297 auto promise = ::std::move(self->promise_);
302 self->result_ = catch_result(
303 [](inner_future_type future) {
304 return future.get().value();
306 ::std::move(self->inner_future_));
308 promise, ::std::addressof(self->result_));
314 self->inner_future_ =
self->invoker_();
316 self->inner_future_.submit(*
self);
320 auto promise = ::std::move(self->promise_);
322 self->result_ = ::std::current_exception();
324 promise, ::std::addressof(self->result_));
329 invoker_(::std::forward<F>(f), ::std::forward<Args>(args)...) {}
336 get_executor()
const noexcept {
341 get_future()
const noexcept {
342 return promise_.get_future();
348 inner_future_type inner_future_;
358 template <
class F,
class... Args>
365 template <
class F,
class... Args>
374 if (!promise) util::throw_errc(
"make_async_task");
379 promise, exec, ::std::forward<F>(f), ::std::forward<Args>(args)...);
383 template <
class T,
class E>
394 Future() noexcept = default;
408 other.future_ =
nullptr;
419 if (future_ != other.future_) {
437 swap(future_, other.future_);
449 operator ev_future_t*()
const noexcept {
return future_; }
452 explicit operator bool() const noexcept {
return future_ !=
nullptr; }
562 auto future = task->get_future();
575 if (!f) util::throw_errc(
"when_all");
580 template <
class Allocator>
583 const ::std::vector<ev_future_t*, Allocator>& futures) {
584 return when_all(exec, futures.size(), futures.data());
588 template <
class InputIt>
589 inline typename ::std::enable_if<
590 !::std::is_convertible<InputIt, ev_future_t*>::value,
593 return when_all(exec, ::std::vector<ev_future_t*>(first, last));
597 template <
class... Futures>
598 inline typename ::std::enable_if<
604 if (!f) util::throw_errc(
"when_all");
612 if (!f) util::throw_errc(
"when_any");
617 template <
class Allocator>
620 const ::std::vector<ev_future_t*, Allocator>& futures) {
621 return when_any(exec, futures.size(), futures.data());
625 template <
class InputIt>
626 inline typename ::std::enable_if<
627 !::std::is_convertible<InputIt, ev_future_t*>::value,
630 return when_any(exec, ::std::vector<ev_future_t*>(first, last));
634 template <
class... Futures>
635 inline typename ::std::enable_if<
641 if (!f) util::throw_errc(
"when_any");
652 template <
class E = ::std::error_code>
656 p.
set(util::success());
668 template <
class T,
class E = ::std::error_code,
669 class V = typename ::std::decay<T>::type>
673 p.
set(util::success(::std::forward<T>(value)));
685 template <class T, class E, class V = typename ::std::decay<E>::type>
689 p.
set(util::failure(::std::forward<E>(
error)));
698 template <
class F,
class... Args>
699 inline typename AsyncTask<F, Args...>::future_type
702 ::std::forward<Args>(args)...);
705 auto future = task->get_future();
706 task->get_executor().submit(*task);
713 #endif // !LELY_EV_FUTURE_HPP_ int ev_future_is_unique(const ev_future_t *future)
Returns 1 if future is the only reference to the future and no references to its associated promise a...
Future & operator=(Future &&other) noexcept
Abandons the shared state of *this as if by ~Future(), then moves the shared state of other to *this...
const struct ev_exec_vtbl *const ev_exec_t
An abstract task executor.
Future<::std::size_t, void > when_any(ev_exec_t *exec, ::std::size_t n, ev_future_t *const *futures)
void * ev_promise_data(const ev_promise_t *promise)
Returns a pointer to the shared state of a promise.
AsyncTask< F, Future >::future_type then(ev_exec_t *exec, F &&f)
Attaches a continuation function to a future and returns a new future which becomes ready once the co...
Future(Future &&other) noexcept
Moves the shared state of other to *this.
void ev_promise_release(ev_promise_t *promise)
Releases a reference to a promise.
TaskWrapper< F, Args... > * make_task_wrapper(ev_exec_t *exec, F &&f, Args &&... args)
Creates a temporary task from a callable object with an associated executor (can be nullptr)...
Promise()
Constructs a promise with (a reference to) an empty shared state.
Future< void, E > make_empty_future()
Creates a shared state of type lely::util::Result<void, E> that is immediately ready, with a successful result, then returns a future associated with that shared state.
#define EV_TASK_INIT(exec, func)
The static initializer for ev_task.
Future< V, E > make_ready_future(T &&value)
Creates a shared state of type lely::util::Result<V, E> that is immediately ready, with a successul result constructed from std::forward<T>(value), then returns a future associated with that shared state.
Promise(Promise &&other) noexcept
Moves the shared state of other to *this.
void submit(ev_task &task) noexcept
bool is_unique() const noexcept
Checks whether *this contains a unique reference to its shared state.
ev_future_t * ev_future_when_any(ev_exec_t *exec, ev_future_t *future,...)
Equivalent to ev_future_when_any_n(), except that it accepts a variable number of arguments instead o...
ev_future_t * ev_future_when_any_n(ev_exec_t *exec, size_t n, ev_future_t *const *futures)
Creates a future that becomes ready when at least one of the input futures becomes ready or is abando...
::std::size_t cancel_all() noexcept
int ev_promise_is_unique(const ev_promise_t *promise)
Returns 1 if promise is the only reference to the promise and no references to its associated future ...
The exception thrown when retrieving the result of a future which is not ready or does not contain a ...
ev_promise_t * ev_promise_create(size_t size, ev_promise_dtor_t *dtor)
Constructs a new promise with an optional empty shared state.
Promise(const Promise &other) noexcept
Constructs a promise with a reference to the shared state of other.
AsyncTask< F, Args... > * make_async_task(ev_exec_t *exec, F &&f, Args &&... args)
Creates a task containing a Callable and its arguments and a future that will eventually hold the res...
This header file is part of the utilities library; it contains a generic type that can represent both...
bool abort(ev_task &task) noexcept
size_t ev_future_cancel(ev_future_t *future, struct ev_task *task)
Cancels the specified task submitted with ev_future_submit(), if it has not yet been scheduled for ex...
bool cancel(ev_task &task) noexcept
Future< T, V > make_error_future(E &&error)
Creates a shared state of type lely::util::Result<T, V> that is immediately ready, with a failure result constructed from std::forward<E>(error), then returns a future associated with that shared state.
void ev_future_release(ev_future_t *future)
Releases a reference to a future.
AsyncTask< F, Args... >::future_type async(ev_exec_t *exec, F &&f, Args &&... args)
Creates a task containing a Callable and its arguments, submits it for execution to the specified exe...
Future< T, E > get_future() const noexcept
Returns a lely::ev::Future with (a reference to) the same shared state as *this.
ev_future_t * ev_future_acquire(ev_future_t *future)
Acquires a reference to a future.
Future<::std::size_t, void > when_all(ev_exec_t *exec, ::std::size_t n, ev_future_t *const *futures)
::std::size_t abort_all() noexcept
bool is_unique() const noexcept
Checks whether *this contains a unique reference to its shared state.
void ev_promise_set_release(ev_promise_t *promise, void *value)
Satisfies a promise prepared by ev_promise_set_acquire(), and stores the specified value for retrieva...
ev_future_t * ev_promise_get_future(ev_promise_t *promise)
Returns (a reference to) a future associated with the specified promise.
A type capable of representing both the successful and failure result of an operation.
The type of objects thrown as exceptions to report a system error with an associated error code...
void submit(ev_exec_t *exec, F &&f)
ev_future_t * ev_future_when_all(ev_exec_t *exec, ev_future_t *future,...)
Equivalent to ev_future_when_all_n(), except that it accepts a variable number of arguments instead o...
This header file is part of the event library; it contains the futures and promises declarations...
ev_promise_t * ev_promise_acquire(ev_promise_t *promise)
Acquires a reference to a promise.
Promise & operator=(Promise &&other) noexcept
Abandons the shared state of *this as if by ~Promise(), then moves the shared state of other to *this...
Future & operator=(const Future &other) noexcept
Abandons the shared state of *this as if by ~Future(), then creates a reference to the shared state o...
Promise & operator=(const Promise &other) noexcept
Abandons the shared state of *this as if by ~Promise(), then creates a reference to the shared state ...
This header file is part of the event library; it contains the C++ interface for the abstract task ex...
int ev_future_is_ready(const ev_future_t *future)
Checks if the specified future is ready, i.e., its associated promise has been satisfied.
This header file is part of the compatibility library; it includes <type_traits> and defines any miss...
An abstract task executor. This class is a wrapper around ev_exec_t*.
bool is_ready() const noexcept
Checks whether the future is ready, i.e., its associated promise has been satisfied and a result has ...
This header file is part of the utilities library; it contains a function object that can be used to ...
size_t ev_future_abort(ev_future_t *future, struct ev_task *task)
Aborts the specified task submitted with ev_future_submit(), if it has not yet been scheduled for exe...
~Future()
Abandons the shared state.
int ev_promise_set_acquire(ev_promise_t *promise)
Checks if the specified promise can be satisfied by the caller and, if so, prevents others from satis...
ev_task_func_t * func
The function to be invoked when the task is run.
Future(const Future &other) noexcept
Constructs a future with a reference to the shared state of other.
void * ev_future_get(const ev_future_t *future)
Returns the result of a ready future.
ev_future_t * ev_future_when_all_n(ev_exec_t *exec, size_t n, ev_future_t *const *futures)
Creates a future that becomes ready when all of the input futures become ready or one of the input fu...
~Promise()
Abandons the shared state.
bool set(U &&u)
Satisfies a promise, if it was not aready satisfied, and stores the specified value as the result in ...
Forms the logical conjunction of the type traits B..., effectively performing a logical AND on the se...
void ev_future_submit(ev_future_t *future, struct ev_task *task)
Submits a task to be executed once the specified future is ready.