4 #include "exceptions.h"
6 #include "prepared_coro.h"
35 template<
typename T,
bool atomic = false>
48 class deferred_future;
51 template<
typename T>
class coro_promise_base;
54 template<
typename T,
typename ... Args>
55 concept avoid_same_kind =
sizeof...(Args) != 1 || !std::is_same_v<T, std::decay_t<Args>...>;
57 template<
typename Alloc>
58 concept is_allocator = requires(Alloc alloc, std::size_t n) {
59 {alloc.allocate(n)} -> std::same_as<typename Alloc::value_type *>;
62 template<
typename T,
typename Ret,
typename ... Args>
63 concept invocable_r_exact = std::is_same_v<std::invoke_result_t<T, Args...>, Ret>;
65 template<
typename T,
typename ... U>
66 concept future_constructible = ((
sizeof...(U) == 1 && (invocable_r_exact<U, T> && ...)) || std::is_constructible_v<T, U...>);
69 using atomic_promise = promise<T, true>;
72 template<
typename T,
bool atomic>
98 void cancel() {_ptr->clearStorage();}
111 template<std::invocable<function<prepared_coro()> > Fn>
113 auto ptr = _ptr.release();
114 if (ptr) ptr->set_resolved(std::forward<Fn>(fn));
128 auto ptr = _ptr.release();
131 ptr->set_resolved([&](
auto &&awt){
136 return std::noop_coroutine();
141 explicit operator bool()
const {
return static_cast<bool>(_ptr);}
149 if (_ptr ==
nullptr)
return std::move(other);
150 _ptr->attach(other._ptr.release());
151 return std::move(*
this);
156 if (_ptr ==
nullptr) {
157 _ptr = std::move(other._ptr);
159 _ptr->attach(other._ptr.release());
174 struct NotifyAction {
175 void operator()(
FutureType *fut) {fut->set_resolved([](
auto &c){c();});}
178 std::unique_ptr<FutureType, NotifyAction> _ptr;
206 if (
this != &other) {
208 _ptr.store(other.claim(), std::memory_order_relaxed);
231 template<
typename ... Args>
233 static_assert((std::is_void_v<T> &&
sizeof...(Args) == 0)
234 || future_constructible<T, Args ...>,
"Value is not constructible from arguments");
236 if (fut) fut->set_value(std::forward<Args>(args)...);
247 if (fut) fut->set_exception(std::move(e));
258 auto e = std::current_exception();
265 return reject(std::make_exception_ptr<std::decay_t<E> >(std::forward<E>(exception)));
286 return _ptr.load(std::memory_order_relaxed);
330 static_assert(std::is_void_v<T> || std::is_copy_constructible_v<T>,
"Requires T copy constructible");
332 auto b = other.claim();
338 operator bool ()
const {
339 return _ptr.load(std::memory_order_relaxed) !=
nullptr;
346 non_atomic() =
default;
349 return std::exchange(_ptr, x);
351 void store(
FutureType *x, std::memory_order) {
368 using Holder = std::conditional_t<atomic, std::atomic<FutureType *>, non_atomic>;
372 FutureType *claim() {
return _ptr.exchange(
nullptr, std::memory_order_relaxed);}
375 struct deferred_tag {};
377 inline constexpr deferred_tag deferred= {};
384 wait_awaiter(T *fut):self(fut) {}
385 wait_awaiter(
const wait_awaiter &other) =
delete;
386 wait_awaiter &operator=(
const wait_awaiter &other) =
delete;
387 ~wait_awaiter() {wait_now();}
388 bool await_ready() const noexcept {
return self->await_ready();}
389 auto await_suspend(std::coroutine_handle<> h) noexcept {
return self->await_suspend(h);}
390 void await_resume() const noexcept {}
394 self->wait_internal();
399 template<
typename T,
bool flag>
400 class [[nodiscard]] has_value_awaiter:
public wait_awaiter<T> {
402 using wait_awaiter<T>::wait_awaiter;
403 bool await_resume() const noexcept {
404 return this->
self->has_value() == flag;
406 has_value_awaiter<T, !flag> operator !()
const {
return this->
self;}
409 return await_resume();
446 using value_type = T;
448 using value_store_type = std::conditional_t<std::is_reference_v<T>,
449 std::add_pointer_t<std::remove_reference_t<T> >,
450 std::conditional_t<std::is_void_v<T>, bool, T> >;
457 using cast_ret_value = std::conditional_t<std::is_void_v<T>, bool, std::add_rvalue_reference_t<T> >;
464 using ret_value = std::conditional_t<std::is_void_v<T>, void, std::add_rvalue_reference_t<T> >;
467 using wait_awaiter = _details::wait_awaiter<future>;
468 using canceled_awaiter = _details::has_value_awaiter<future,false>;
476 template<
typename ... Args>
477 requires (std::constructible_from<value_store_type, Args ...> && avoid_same_kind<future, Args...>)
478 future(Args && ... args):_result(Result::value), _value(std::forward<Args>(args)...) {}
485 template<
typename ... Args>
486 future(std::in_place_t, Args &&... args): _result(Result::value), _value(std::forward<Args>(args)...) {}
489 future(std::exception_ptr e):_result(Result::exception), _exception(std::move(e)) {}
495 template<std::invocable<promise_t> Fn>
508 template<std::invocable<promise_t> Fn>
510 setDeferredEvaluation(std::forward<Fn>(fn));
513 template<invocable_r_exact<future<T> > Fn>
515 new(
this)
future(std::forward<Fn>(fn)());
524 if (_state.load(std::memory_order_relaxed) == State::deferred) {
525 std::destroy_at(&_deferred);
547 template<invocable_r_exact<future> Fn>
549 std::destroy_at(
this);
551 std::construct_at(
this, std::forward<Fn>(fn));
553 std::construct_at(
this);
568 auto old = State::resolved;
569 if (!_state.compare_exchange_strong(old, State::pending)) {
570 if (old == State::deferred) {
571 std::destroy_at(&_deferred);
572 _state.store(State::pending);
594 startDeferredEvaluation([&](
auto &&h){out = std::move(h);});
616 template<std::invocable<> Fn>
618 return RegAwtRes::constructed_ready == register_awaiter(std::forward<Fn>(fn), [](
auto &&){});
629 return RegAwtRes::constructed_ready == register_awaiter([]{
return prepared_coro{};}, [](
auto &&){});
646 template<std::invocable<> Fn>
648 auto res = register_awaiter(std::forward<Fn>(fn), [](
auto &&){});
650 case RegAwtRes::resolved: {
653 case RegAwtRes::constructed_resolved: {
671 template<std::invocable<> Fn>
673 return then(std::forward<Fn>(fn));
686 wait_awaiter
wait() noexcept {
return this;}
692 return await_resume();
698 return getInternal();
707 return _state.load(std::memory_order_relaxed) != State::resolved;
716 auto st = _state.load(std::memory_order_relaxed);
717 return st != State::resolved && st != State::deferred;
726 return _state.load(std::memory_order_relaxed) == State::deferred;
734 return _state.load(std::memory_order_relaxed) == State::awaited;
739 return _state.load(std::memory_order_relaxed) == State::resolved;
755 auto cb = [h]{
return h;};
756 auto resume_fn = [&retval](
prepared_coro h){retval = std::move(h);};
757 if (RegAwtRes::constructed_ready == register_awaiter(cb, resume_fn)) {
764 ret_value await_resume() {
765 if constexpr(std::is_void_v<T>) {
768 return getInternal();
780 return _result != Result::not_set;
791 return _result == Result::exception;
823 if (this->is_pending())
return {};
825 case Result::exception:
return prom.reject(_exception);
827 if constexpr(std::is_void_v<X>) {
830 if constexpr(std::is_reference_v<T>) {
831 return prom(*_value);
837 case Result::not_set:
838 return prom.cancel();
845 return forward_to(prom);
862 if (this->is_pending())
return {};
864 case Result::exception:
return prom.reject(_exception);
866 if constexpr(std::is_void_v<X>) {
869 if constexpr(std::is_reference_v<T>) {
870 return prom(std::move(*_value));
872 return prom(std::move(_value));
876 case Result::not_set:
877 return prom.cancel();
885 return std::move(*this).forward_to(prom);
903 template<
typename X, std::invocable<cast_ret_value> Fn>
905 if (this->is_pending())
return {};
908 case Result::exception:
return prom.reject(_exception);
910 if constexpr(std::is_void_v<std::invoke_result_t<Fn,cast_ret_value> >) {
911 if constexpr(std::is_reference_v<T>) {
912 std::forward<Fn>(convert)(_value);
915 std::forward<Fn>(convert)(_value);
919 if constexpr(std::is_reference_v<T>) {
920 return prom(std::forward<Fn>(convert)(std::forward<cast_ret_value>(*_value)));
922 return prom(std::forward<Fn>(convert)(std::forward<cast_ret_value>(_value)));
926 case Result::not_set:
927 return prom.cancel();
931 template<
typename X, std::invocable<cast_ret_value> Fn>
933 return convert_to(prom, std::forward<Fn>(convert));
940 enum class State: char {
954 enum class Result : char{
963 enum class RegAwtRes {
965 constructed_resolved,
973 using ChainPtr = future *;
975 ChainPtr _chain = {};
976 std::atomic<State> _state = {State::resolved};
977 Result _result = Result::not_set;
978 bool _awaiter_cleanup =
false;
984 awaiter_type _awaiter;
985 deferred_eval_fn_type _deferred;
990 value_store_type _value;
991 std::exception_ptr _exception;
992 coro::function<T(), std::max(
sizeof(value_store_type),
sizeof(
void *)*2)> _lambda;
997 void clearStorage() {
1000 case Result::value: std::destroy_at(&_value);
break;
1001 case Result::exception: std::destroy_at(&_exception);
break;
1003 _result = Result::not_set;
1004 check_awaiter_cleanup();
1007 void wait_internal() {
1008 auto st = _state.load(std::memory_order_acquire);
1009 while (st != State::resolved) {
1010 if (st == State::deferred) {
1011 startDeferredEvaluation([](
auto c){c();});
1013 trace::on_block([&]{
1017 st = _state.load(std::memory_order_acquire);
1021 cast_ret_value getInternal() {
1024 if constexpr(std::is_reference_v<T>) {
1025 return std::forward<cast_ret_value>(*_value);
1027 return std::forward<cast_ret_value>(_value);
1030 case Result::exception: std::rethrow_exception(_exception);
break;
1033 throw await_canceled_exception();
1045 template<
typename ResumeFn>
1048 State new_state = State::evaluating;
1049 _state.exchange(new_state, std::memory_order_acquire);
1053 std::destroy_at(&_deferred);
1056 return _state.compare_exchange_strong(new_state, State::pending, std::memory_order_release);
1066 template<std::invocable<promise_t> Fn>
1069 if constexpr(std::is_invocable_r_v<prepared_coro, Fn, promise_t> ) {
1071 State old = State::resolved;
1072 if (!_state.compare_exchange_strong(old,State::deferred, std::memory_order_relaxed)) {
1077 std::construct_at(&_deferred, std::forward<Fn>(fn));
1081 _state.store(old, std::memory_order_relaxed);
1087 setDeferredEvaluation([xfn = std::move(fn)](
promise_t prom) mutable->prepared_coro{
1088 xfn(std::move(prom));
1094 template<
typename ... Args>
1095 void set_value(Args && ... args) {
1098 if constexpr(std::is_reference_v<T>) {
1099 std::construct_at(&_value, &args...);
1100 }
else if constexpr(
sizeof...(Args) == 1 && (invocable_r_exact<Args, value_store_type> && ...)) {
1101 new (&_value) value_store_type(args()...);
1103 std::construct_at(&_value, std::forward<Args>(args)...);
1105 _result = Result::value;
1108 if constexpr(std::is_void_v<T>) {
1109 _chain->set_value();
1110 }
else if constexpr(std::is_reference_v<T>) {
1111 _chain->set_value(*_value);
1112 }
else if constexpr(std::is_copy_constructible_v<T>) {
1113 _chain->set_value(_value);
1119 set_exception(std::current_exception());
1123 void set_exception(std::exception_ptr e) {
1125 std::construct_at(&_exception, std::move(e));
1126 _result = Result::exception;
1127 if (_chain) _chain->set_exception(_exception);
1130 template<
typename SchedulerFn>
1131 void set_resolved(SchedulerFn &&schfn) {
1132 State st = _state.exchange(State::resolved);
1133 auto chain = _chain;
1134 _state.notify_all();
1135 if (st == State::awaited) {
1136 _awaiter_cleanup =
true;
1139 if (chain) chain->set_resolved(std::forward<SchedulerFn>(schfn));
1143 void check_awaiter_cleanup() {
1144 if (_awaiter_cleanup) {
1145 std::destroy_at(&_awaiter);
1146 _awaiter_cleanup =
false;
1151 template<std::invocable<> Awt,
typename ResumeFn >
1152 RegAwtRes register_awaiter(Awt &&awt, ResumeFn &&resumeFn) {
1154 State st = _state.exchange(State::evaluating);
1157 case State::resolved: _state.store(st);
1158 return RegAwtRes::resolved;
1160 case State::pending:
1161 new(&_awaiter)
auto(to_awaiter(awt));
1164 case State::evaluating:
1165 throw still_pending_exception();
1166 case State::awaited:
1167 std::destroy_at(&_awaiter);
1168 new(&_awaiter)
auto(to_awaiter(awt));
1170 case State::deferred:
1171 if (!startDeferredEvaluation(resumeFn))
return RegAwtRes::resolved;
1172 return register_awaiter(std::forward<Awt>(awt),std::forward<ResumeFn>(resumeFn));
1174 st = State::evaluating;
1175 if (!_state.compare_exchange_strong(st, State::awaited)) {
1178 _awaiter_cleanup =
true;
1179 return RegAwtRes::constructed_resolved;
1182 return RegAwtRes::constructed_ready;
1185 template<std::invocable<> Fn>
1186 static awaiter_type to_awaiter(Fn &fn) {
1187 if constexpr (std::is_constructible_v<prepared_coro, std::invoke_result_t<Fn> >) {
1188 return std::move(fn);
1190 return [fn = std::move(fn)]()
mutable -> prepared_coro {
1196 void checkInProgress() {
1197 if (is_in_progress())
throw still_pending_exception();
1220 while (*ch) ch = &((*ch)->_chain);
1234 if (r) _chain = r->_chain;
1238 friend class _details::coro_promise_base<T>;
1239 friend class _details::wait_awaiter<
future>;
1244 template<
typename T>
1249 using State =
typename future<T>::State;
1250 using Result =
typename future<T>::Result;
1253 template<std::invocable<promise_t> Fn>
1255 this->setDeferredEvaluation(std::forward<Fn>(fn));
1258 other.checkInProgress();
1259 if (other._state == State::deferred) {
1260 std::construct_at(&this->_deferred, std::move(other._deferred));
1261 this->_state = State::deferred;
1263 switch (other._result) {
1264 case Result::value: std::construct_at(&this->_value, std::move(other._value));
break;
1265 case Result::exception: std::construct_at(&this->_exception, std::move(other._exception));
break;
1268 this->_result = other._result;
1272 if (
this != &other){
1273 this->checkInProgress();
1274 other.checkInProgress();
1275 std::destroy_at(
this);
1276 std::construct_at(
this, std::move(other));
1286 State st = this->_state;
1287 if (st == State::deferred) {
1288 this->_deferred(std::move(prom));
1289 std::destroy_at(&this->_deferred);
1290 this->_state = State::resolved;
1291 }
else if (st == State::resolved) {
1292 this->forward_to(prom);
1303 State st = this->_state;
1304 if (st == State::deferred) {
1305 this->_deferred(std::move(prom));
1306 std::destroy_at(&this->_deferred);
1307 this->_state = State::resolved;
1308 }
else if (st == State::resolved) {
1309 std::move(*this).forward_to(prom);
1318 namespace _details {
1320 template<
typename T>
1321 class coro_promise_base:
public trace::base_promise_type {
1324 future<T> *fut =
nullptr;
1326 prepared_coro set_resolved() {
1328 auto tmp = std::exchange(fut,
nullptr);
1329 tmp->set_resolved([&](
auto &&fn){ret = fn();});
1332 template<
typename ... Args>
1333 void set_value(Args && ... args)
const {
1334 if (fut) fut->set_value(std::forward<Args>(args)...);
1336 if constexpr ((std::invocable<Args> && ...)) {
1342 coro_promise_base() =
default;
1343 coro_promise_base(
const coro_promise_base &x) =
delete;
1344 coro_promise_base &operator=(
const coro_promise_base &) =
delete;
1345 ~coro_promise_base() {
1346 if (fut) fut->set_resolved([](
auto &&){});
1350 void set_exception(std::exception_ptr e) {
1351 if (fut) fut->set_exception(std::move(e));
1356 void unhandled_exception() {
1357 if (fut) fut->set_exception(std::current_exception());
1363 template<
typename T>
1364 class coro_promise:
public coro_promise_base<T> {
1367 template<
typename Arg>
1368 requires future_constructible<T, Arg>
1369 void return_value(Arg &&arg) {
1370 this->set_value(std::forward<Arg>(arg));
1377 class coro_promise<void>:
public coro_promise_base<void> {
1379 void return_void() {
1405 template<
typename T>
1427 using value_type =
typename future<T>::value_type;
1428 using value_store_type =
typename future<T>::value_store_type;
1432 using wait_awaiter = _details::wait_awaiter<shared_future>;
1433 using canceled_awaiter = _details::has_value_awaiter<shared_future,false>;
1457 template<
typename Arg0,
typename ... Args>
1460 if constexpr(is_allocator<std::decay_t<Arg0> >) {
1461 static_assert(std::is_constructible_v<Shared, Args ...>,
"Invalid arguments");
1462 _shared_future = std::allocate_shared<Shared>(arg0, std::forward<Args>(args)...);
1464 static_assert(std::is_constructible_v<Shared, Arg0, Args ...>,
"Invalid arguments");
1465 _shared_future = std::make_shared<Shared>(arg0, std::forward<Args>(args)...);
1467 _shared_future->init_callback(_shared_future);
1476 this->_shared_future = other._shared_future;
1477 _state.store(State::unused, std::memory_order_relaxed);
1483 check_in_progress();
1488 _shared_future = std::make_shared<Shared>();
1489 promise<T> p = _shared_future->get_promise();
1501 template<
typename stl_allocator>
1503 _shared_future = std::allocate_shared<Shared>(std::forward<allocator>(allocator));
1504 promise<T> p = _shared_future->get_promise();
1511 template<std::invocable<> Fn>
1514 _shared_future = std::make_shared<Shared>(std::forward<Fn>(fn));
1522 template<std::invocable<> Fn,
typename std_allocator>
1525 _shared_future = std::allocate_shared<Shared>(
1526 std::forward<std_allocator>(std::get<std_allocator>(tpl)),
1527 std::forward<Fn>(std::get<Fn>(tpl)));
1538 template<std::invocable<> Fn>
1540 auto st = _state.exchange(State::unused);
1541 if constexpr(std::is_constructible_v<
prepared_coro, std::invoke_result_t<Fn> >) {
1542 _awaiter.emplace(std::forward<Fn>(fn));
1544 _awaiter.emplace([fn = std::move(fn)]()
mutable ->
prepared_coro{
1548 if (st == State::notified)
return false;
1549 auto st2 = State::unused;
1550 if (_state.compare_exchange_strong(st2, State::awaited)) {
1551 if (st == State::unused)
return _shared_future->register_target(
this);
1564 template<std::invocable<> Fn>
1566 if (!set_callback(std::forward<Fn>(fn))) {
1575 template<std::invocable<> Fn>
1577 return when_resolved(std::forward<Fn>(fn));
1591 return _shared_future->get();
1596 operator cast_ret_value (){
1598 return *_shared_future;
1607 return _shared_future && _shared_future->is_pending();
1616 return _shared_future && _shared_future->is_in_progress();
1625 return _state.load(std::memory_order_relaxed) == State::awaited;
1630 return !_shared_future || _shared_future->await_ready();
1645 return set_callback([h]{
return h;});
1649 ret_value await_resume() {
1650 return _shared_future->await_resume();
1659 _shared_future.reset();
1670 return _shared_future->has_value();
1681 return _shared_future->has_exception();
1703 class Shared:
public future<T> {
1708 static void init_callback(std::shared_ptr<Shared>
self) {
1710 auto r =
self->notify_targets();
1716 prepared_coro notify_targets() {
1717 auto n = _await_chain.exchange(disabled_slot());
1718 return n?notify_targets(n):prepared_coro{};
1721 static prepared_coro notify_targets(shared_future *list) {
1723 auto c1 = notify_targets(list->_next);
1724 auto c2 = list->activate();
1734 return list->activate();
1738 bool register_target(shared_future *item) {
1739 while (!_await_chain.compare_exchange_strong(item->_next, item)) {
1740 if (item->_next == disabled_slot())
return false;
1747 std::atomic<shared_future *> _await_chain = {};
1762 std::shared_ptr<Shared> _shared_future;
1764 std::atomic<State> _state = {State::unused};
1765 std::optional<awaiter_cb> _awaiter;
1767 prepared_coro activate() {
1768 auto st = _state.exchange(State::notified);
1769 if (st == State::awaited) {
1770 return (*_awaiter)();
1775 void wait_internal() {
1776 _shared_future->
wait();
1780 void check_in_progress() {
1781 if (_state.load(std::memory_order_relaxed) == State::awaited) {
1782 throw still_pending_exception();
1788 _shared_future->init_callback(_shared_future);
1789 _state.store(State::unused, std::memory_order_relaxed);
1793 friend class _details::wait_awaiter<shared_future>;
1796 static shared_future<T> * disabled_slot() {
return reinterpret_cast<shared_future<T> *
>(1);}
1804 class future_with_callback {
1807 template<
typename Fut>
1808 future_with_callback(Fut &&fut) {
1810 set_cb = [](
void *fut,
function<prepared_coro()>fun){
1811 using FutT = std::decay_t<Fut>;
1812 FutT *f =
reinterpret_cast<FutT *
>(fut);
1813 f->then(std::move(fun));
1817 template<std::invocable<> Fn>
1818 void operator>>(Fn &&fn) {
1819 if constexpr(std::is_same_v<std::invoke_result_t<Fn>, prepared_coro>) {
1820 set_cb(fut, std::forward<Fn>(fn));
1822 set_cb(fut, [fn = std::move(fn)]()
mutable -> prepared_coro {
1831 void (*set_cb)(
void *fut,
function<prepared_coro()>);
1840 class all_of:
public future<void> {
1844 template<
typename Iter>
1845 all_of(Iter from, Iter to) {
1846 result = get_promise();
1847 auto cb = [
this]{
if (--remain == 0) result();};
1848 while (from != to) {
1850 static_cast<future_with_callback
>(*from) >> cb;
1856 all_of(std::initializer_list<future_with_callback> iter)
1857 :all_of(iter.begin(), iter.end()) {}
1860 promise<void> result = {};
1861 std::atomic<int> remain = {1};
1867 class any_of:
public future<unsigned int> {
1870 template<
typename Iter>
1871 any_of(Iter from, Iter to) {
1872 cleanup = [=]{do_cleanup(from, to);};
1873 result = get_promise();
1874 unsigned int idx = 0;
1875 while (from != to) {
1876 static_cast<future_with_callback
>(*from) >> [idx,
this] {
1877 unsigned int r = notset;
1878 if (selected.compare_exchange_strong(r, idx)) {
1885 if (inited.fetch_add(2) > 0) {
1891 any_of(std::initializer_list<future_with_callback> iter)
1892 :any_of(iter.begin(), iter.end()) {}
1898 if (inited.fetch_add(1) > 1) {
1905 static constexpr
unsigned int notset = std::bit_cast<unsigned int>(-1);
1906 promise<unsigned int> result = {};
1907 std::atomic<unsigned int> selected = {notset};
1908 std::atomic<int> inited = {0};
1909 function<void(), 8*
sizeof(
void *)> cleanup;
1911 static void do_cleanup(
auto from,
auto to) {
1912 while (from != to) {
1913 static_cast<future_with_callback
>(*from) >> []{
return prepared_coro();};
void operator()(promise_t &&prom) &
By calling deferred future with a promise, the future is started and result is trensfered to the prom...
void operator()(promise_t &&prom) &&
By calling deferred future with a promise, the future is started and result is trensfered to the prom...
Contains future value of T, where evaluation is deferred until the value is needed.
future(deferred_tag, Fn &&fn)
Construct future with deferred evaluation.
requires(std::constructible_from< value_store_type, Args ... > &&avoid_same_kind< future, Args... >) future(Args &&... args)
Construct future already resolved with a value.
bool startDeferredEvaluation(ResumeFn &&resume_fn) noexcept
Starts evaluation of deferred future.
promise_t get_promise()
Retrieve promise and begin evaluation.
bool has_exception() const
Determines, whether future has exception.
promise< X >::notify forward_to(promise< X > &prom) &noexcept
Forward value, possibly convert it, to different promise.
bool is_deferred() const
Determine deferred status.
std::coroutine_handle await_suspend(std::coroutine_handle<> h) noexcept
co_await support, called with suspended coroutine
void setDeferredEvaluation(Fn &&fn)
Initializes deferred evaluation.
std::conditional_t< std::is_void_v< T >, void, std::add_rvalue_reference_t< T > > ret_value
type which is used as return value of get() and await_resume()
bool has_value() const
Determines, whether future has a value.
future(Fn &&fn)
Construct future which is evaluated inside of lambda function.
bool await_ready() const noexcept
co_await support, returns true, if value is ready (resolved)
future(std::in_place_t, Args &&... args)
Construct future already resolved with a value.
std::conditional_t< std::is_void_v< T >, bool, std::add_rvalue_reference_t< T > > cast_ret_value
type which is used for cast operator ()
bool unset_callback()
unset callback
promise< X >::notify convert_to(promise< X > &prom, Fn &&convert) noexcept
Forward value, possibly convert it, to different promise.
bool is_awaited() const
Determine whether an awaiter is set.
bool is_in_progress() const
Determine in progress status.
ret_value get()
Retrieves value, performs synchronous wait.
void attach(future *x)
Attach future to internal linked list.
future * detach()
Detach linked list from the future.
bool operator>>(Fn &&fn)
Sets function which is called once future is resolved (always)
wait_awaiter wait() noexcept
Perform synchronous wait on resolution.
bool then(Fn &&fn)
Sets function which is called once future is resolved (always)
canceled_awaiter operator!()
awaitable for canceled operation
bool is_pending() const
Determines pending status.
promise< X >::notify forward_to(promise< X > &prom) &&noexcept
Forward value, possibly convert it, to different promise.
bool set_callback(Fn &&fn)
Sets callback which is called once future is resolved (in future)
prepared_coro start()
Start deferred execution.
Contains future value of T, can be co_awaited in coroutine.
std::coroutine_handle symmetric_transfer()
release handle to be used in function await_suspend()
contains prepared coroutine (prepared to run)
std::coroutine_handle symmetric_transfer()
deliver the notification with ability to switch to the coroutine
notify(FutureType *fut)
Construct deferred notify from future.
void deliver()
deliver the notification now
notify operator+(notify &other)
combine notification into one object
notify & operator+=(notify &other)
append a notification
void deliver(Fn &&fn)
deliver notification through the function
void cancel()
cancel the future resolution (notify still needs to be delivered)
notify & operator+=(notify &&other)
append a notification
contain notification to be delivered to the asociated future
FutureType * release()
Release the future pointer from the promise object.
promise(FutureType *ptr)
Bound promise to future.
notify reject(std::exception_ptr e)
reject the future with exception
promise & operator+=(promise< T, f > &other)
Combine two promises into one.
~promise()
Dtor - if future is pending, cancels it.
const FutureType * get_future() const
Retrieve pointer to an associated future.
notify cancel()
cancel the future (resolve without value)
notify reject(E &&exception)
Reject with exception.
notify reject()
reject or cancel the future with exception
promise()=default
construct unbound promise
notify operator()(Args &&... args)
set value
promise & operator=(promise &&other)
Assign by move.
promise(promise &&other)
Move.
promise(promise< T, x > &&other)
Move change MT Safety.
promise operator+(promise< T, f > &other)
Combine two promises into one.
future< T > FutureType
Associated future.
Carries reference to future<T>, callable, sets value of an associated future<T>
bool has_exception() const
Determines, whether future has exception.
bool then(Fn &&fn)
execute callback when future is resolved
bool has_value() const
Determines, whether future has a value.
shared_future(shared_future &other)
shared future is copyable
void operator<<(std::tuple< Fn, std_allocator > &&tpl)
Redirect return value of function returning coro::future to instance of shared_future.
bool await_suspend(std::coroutine_handle<> h)
co_await support, called with suspended coroutine
bool set_callback(Fn &&fn)
set callback which is invoked when future is resolved
void operator<<(Fn &&fn)
Redirect return value of function returning coro::future to instance of shared_future.
shared_future(const shared_future &other)
shared future is copyable
canceled_awaiter operator!()
awaitable for canceled operation
ret_value get()
Retrieves value, performs synchronous wait.
requires(!std::is_same_v< std::decay_t< Arg0 >, shared_future >) shared_future(Arg0 &&arg0
Construct shared future initialize it same way asi coro::future.
bool is_awaited() const
Determine whether an awaiter is set.
bool await_ready() const
co_await support, returns true, if value is ready (resolved)
promise< T > get_promise(stl_allocator &&allocator)
Initialize future and get promise.
shared_future()
Construct shared future uninitialized.
wait_awaiter wait()
Perform synchronous wait on resolution.
bool is_in_progress() const
Determine in progress status.
bool operator>>(Fn &&fn)
alias to then()
~shared_future()
destructor
promise< T > get_promise()
Initialize future and get promise.
shared_future & operator=(const shared_future &other)
you can assign
bool is_pending() const
Determines pending status.
Future which can be shared (by copying - like shared_ptr)
Exception is thrown on attempt to retrieve promise when the future is already pending.