15#if defined(__cplusplus) && __cplusplus >= 202002L
47 char const* id_str()
const noexcept
52 bool await_ready()
const noexcept
57 void await_suspend(std::coroutine_handle<>
UNUSED_PAR(h))
noexcept {}
73 char const* id_str()
const noexcept
78 bool await_ready()
const noexcept
83 void await_suspend(std::coroutine_handle<>
UNUSED_PAR(h))
noexcept {}
85 decltype(
auto) await_resume()
const
99 char const* id_str()
const noexcept
104 bool await_ready()
const noexcept
109 void await_suspend(std::coroutine_handle<>
UNUSED_PAR(h))
noexcept {}
111 decltype(
auto) await_resume()
const
113 return signal.
wait();
126 char const* id_str()
const noexcept
131 bool await_ready()
const noexcept
136 void await_suspend(std::coroutine_handle<>
UNUSED_PAR(h))
noexcept {}
138 decltype(
auto) await_resume()
const
153 char const* id_str()
const noexcept
158 bool await_ready()
const noexcept
163 void await_suspend(std::coroutine_handle<>
UNUSED_PAR(h))
noexcept {}
165 decltype(
auto) await_resume()
const
167 return mailbox.
take();
171 return impl{mailbox};
179 char const* id_str()
const noexcept
184 bool await_ready()
const noexcept
189 void await_suspend(std::coroutine_handle<>
UNUSED_PAR(h))
noexcept {}
191 void await_resume()
const
206template <
typename Promise,
typename Awaitable>
212 char const*
id_str() const noexcept requires(requires(Awaitable a) { a.id_str(); })
226 if constexpr(
requires(Awaitable a) { a.id_str(); })
235 if constexpr(std::is_void_v<
decltype(
awaitable.await_suspend(h))>) {
238 }
else if constexpr(std::is_same_v<bool,
decltype(
awaitable.await_suspend(h))>) {
241 }
else if constexpr(std::is_convertible_v<
243 std::coroutine_handle<>>) {
248 (
sizeof(Awaitable),
false),
249 "await_suspend must return void, bool, or std::coroutine_handle<>");
263template <
typename Promise,
typename Awaitable>
270 ::zth::deallocate<char>(
static_cast<char*
>(ptr), n);
274 __attribute__((returns_nonnull, warn_unused_result)) static
void*
275 operator new(
std::
size_t n)
277 return ::zth::allocate<char>(n);
287 auto c = m_continuation;
289 return c ? c : std::noop_coroutine();
294 return static_cast<bool>(m_continuation);
299 zth_assert(!m_continuation || !cont || m_continuation == cont);
300 m_continuation = cont;
309 std::coroutine_handle<> m_continuation;
312template <
typename Promise>
330 return std::coroutine_handle<promise_type>::from_promise(
self());
333 virtual std::coroutine_handle<>
handle() noexcept final
343 bool await_ready()
noexcept
348 void await_suspend(std::coroutine_handle<>)
noexcept {}
350 void await_resume()
noexcept
357 return awaiter{*
this};
365 bool await_ready()
noexcept
370 std::coroutine_handle<> await_suspend(std::coroutine_handle<>)
noexcept
373 return p.continuation();
376 void await_resume()
noexcept {}
382 template <
typename A>
388 template <
typename P,
typename A>
407 while(!
self().completed())
430 virtual void cleanup() noexcept final
437 bool m_running =
false;
451template <
typename Task,
typename Fiber>
456 decltype(
auto)
operator*()
461 decltype(
auto) operator->()
466 template <
typename M>
467 requires(std::is_base_of_v<FiberManipulator, M>)
task_fiber&
operator<<(M
const& m) &
474 template <
typename M>
475 requires(std::is_base_of_v<FiberManipulator, M>)
task_fiber&&
operator<<(M
const& m) &&
478 return std::move(*
this);
487 operator typename Task::Future_type &()
noexcept
499template <
typename Task,
typename Fiber>
502template <
typename T,
typename F>
514template <
typename T =
void>
521 explicit task(std::coroutine_handle<promise_type> h) noexcept
522 : m_promise{h.promise()}
530 : m_promise{std::move(p)}
539 return m_promise.get();
545 return p ? p->id_str() :
"coro::task";
552 p->setName(std::move(name));
558 return !p || p->completed();
587 decltype(
auto)
operator()()
592 decltype(
auto)
fiber(
char const* name =
nullptr)
595 name =
"coro::fiber";
605 auto&
operator co_await()
noexcept
615 std::coroutine_handle<promise_type>
await_suspend(std::coroutine_handle<> h)
noexcept
619 p->set_continuation(h);
620 return p->typedHandle();
654 return m_future.
valid();
666 m_future.
set(std::current_exception());
682 template <typename T_>
699 void return_void() noexcept
738 std::coroutine_handle<>
waiter() const noexcept
761 m_waiter = std::coroutine_handle<>{};
782 while(!
valid(assigned)) {
791 bool prio)
noexcept override
800 m_waiter = std::coroutine_handle<>::from_address(user);
807 std::coroutine_handle<> m_waiter;
816 std::coroutine_handle<> waiter{};
818 char const* id_str() const noexcept
820 return mailbox.owner().
id_str();
823 bool await_ready() noexcept
825 return mailbox.abandoned()
827 || mailbox.owner().running();
830 std::coroutine_handle<> await_suspend(std::coroutine_handle<> h)
noexcept
833 mailbox.
wait(item, waiter);
834 return mailbox.owner().handle();
837 decltype(
auto) await_resume()
839 if(mailbox.
valid(waiter)) {
841 return mailbox.
take(waiter);
842 }
else if(mailbox.abandoned()) {
848 return mailbox.
take();
856template <
typename Generator,
typename Fiber>
861 template <
typename M>
862 requires(std::is_base_of_v<FiberManipulator, M>)
generator_fiber&
operator<<(M
const& m) &
869 template <
typename M>
870 requires(std::is_base_of_v<FiberManipulator, M>)
generator_fiber&&
operator<<(M
const& m) &&
873 return std::move(*
this);
886template <
typename Generator,
typename Fiber>
889template <
typename G,
typename F>
896template <
typename... T>
897class generator_promise;
905template <
typename... T>
906requires(
sizeof...(T) >= 1, (!std::is_void_v<T> && ...))
class generator {
911 explicit generator(std::coroutine_handle<promise_type> h) noexcept
912 : m_promise{h.promise()}
920 : m_promise{std::move(p)}
929 return m_promise.get();
935 return p ? p->id_str() :
"coro::generator";
942 p->setName(std::move(name));
947 auto* p = m_promise.get();
948 return !p || p->completed();
951 template <
typename U =
typename promise_type::first_yield_type>
954 auto* p = m_promise.get();
959 return p->template mailbox<U>();
962 template <
typename U>
963 decltype(
auto)
as()
const
968 template <
typename U =
typename promise_type::first_yield_type>
971 auto* p = m_promise.get();
972 return p && p->template mailbox<U>().valid();
975 template <
typename U =
typename promise_type::first_yield_type>
978 auto* p = m_promise.get();
983 return p->template value<U>();
986 template <
typename U =
typename promise_type::first_yield_type>
989 auto* p = m_promise.get();
994 p->template generate<U>();
999 auto* p = m_promise.get();
1009# ifdef ZTH_FUTURE_EXCEPTION
1010 auto exc = p->mailbox().exception();
1012 std::rethrow_exception(exc);
1016 decltype(
auto)
fiber(
char const* name =
nullptr)
1019 name =
"coro::fiber";
1036 auto* p = m_promise.get();
1053template <
template <
typename...>
class G,
typename... T>
1054requires(std::is_same_v<std::remove_reference_t<G<T...>>, generator<T...>>)
1055 static inline decltype(
auto)
awaitable(G<T...> g) noexcept
1058 sizeof...(T) == 1,
"Use generator.as<type>() to select the yield type to await on");
1064template <
typename T>
1066 std::is_reference_v<T>, std::reference_wrapper<std::remove_reference_t<T>>, T>>;
1068template <
typename A,
typename B>
1069inline constexpr bool is_identical_v = std::is_same_v<A, B>;
1071template <
typename A,
typename B>
1072inline constexpr bool is_similar_v =
1073 is_identical_v<A, B> || std::is_same_v<std::decay_t<A>, std::decay_t<B>>;
1075template <
typename A,
typename B>
1076inline constexpr bool is_convertible_v = is_similar_v<A, B> || std::is_convertible_v<A, B&>;
1078template <
typename Needle,
typename... Haystack>
1079struct has_identical_type : std::false_type {};
1081template <
typename Needle,
typename First,
typename... Rest>
1082struct has_identical_type<Needle, First, Rest...>
1083 : std::conditional_t<
1084 is_identical_v<Needle, First>, std::true_type,
1085 has_identical_type<Needle, Rest...>> {};
1087template <
typename Needle,
typename... Haystack>
1088struct find_identical_type {};
1090template <
typename Needle,
typename First,
typename... Rest>
1091struct find_identical_type<Needle, First, Rest...> {
1092 using type = std::conditional_t<
1093 is_identical_v<Needle, First>, First,
1094 typename find_identical_type<Needle, Rest...>::type>;
1097template <
typename Needle,
typename... Haystack>
1098struct has_similar_type : std::false_type {};
1100template <
typename Needle,
typename First,
typename... Rest>
1101struct has_similar_type<Needle, First, Rest...>
1102 : std::conditional_t<
1103 is_similar_v<Needle, First> && !has_identical_type<Needle, Rest...>::value,
1104 std::true_type, has_similar_type<Needle, Rest...>> {};
1106template <
typename Needle,
typename... Haystack>
1107struct find_similar_type {
1111template <
typename Needle,
typename First,
typename... Rest>
1112struct find_similar_type<Needle, First, Rest...> {
1113 using type = std::conditional_t<
1114 is_similar_v<Needle, First> && !has_identical_type<Needle, Rest...>::value, First,
1115 typename find_similar_type<Needle, Rest...>::type>;
1118template <
typename Needle,
typename... Haystack>
1119struct find_convertible_type {
1123template <
typename Needle,
typename First,
typename... Rest>
1124struct find_convertible_type<Needle, First, Rest...> {
1125 using type = std::conditional_t<
1126 is_convertible_v<Needle, First> && !has_similar_type<Needle, Rest...>::value, First,
1127 typename find_convertible_type<Needle, Rest...>::type>;
1130template <
typename A,
typename T>
1131static inline A repeat(A a)
1138template <
typename Needle,
typename... Haystack>
1139struct find_type : impl::find_convertible_type<Needle, Haystack...> {};
1141template <
typename... T>
1154 :
base{
"coro::generator"}
1163 return std::get<impl::generator_Mailbox_type<U>>(m_mailbox);
1166 template <
typename U = first_yield_type>
1169 return std::get<impl::generator_Mailbox_type<U>>(m_mailbox);
1177 template <
typename U = first_yield_type>
1180 return mailbox<U>().valid() && !
completed();
1183 template <
typename U = first_yield_type>
1189 return mailbox<U>().take();
1192 template <
typename U = first_yield_type>
1197 if(mailbox<U>().
valid())
1220 std::coroutine_handle<>
waiter() const noexcept
1222 std::array<std::coroutine_handle<>,
sizeof...(T)> waiters = {waiter<T>()...};
1224 for(
size_t i = 0; i <
sizeof...(T); ++i)
1231 template <
typename U>
1232 std::coroutine_handle<>
waiter() const noexcept
1234 return mailbox<U>().waiter();
1237 template <
typename T_>
1240 using M =
typename find_type<T_, T...>::type;
1242 mailbox<M>().put(std::forward<T_>(v));
1247 char const* id_str()
const noexcept
1252 bool await_ready()
noexcept
1257 std::coroutine_handle<>
1258 await_suspend(std::coroutine_handle<>
UNUSED_PAR(h))
noexcept
1263 void await_resume()
noexcept {}
1274 decltype(std::declval<base>().final_suspend()) awaitable;
1276 bool await_ready()
noexcept
1278 return awaitable.await_ready();
1281 std::coroutine_handle<> await_suspend(std::coroutine_handle<> h)
noexcept
1287 return awaitable.await_suspend(h);
1290 decltype(
auto) await_resume()
noexcept
1292 return awaitable.await_resume();
1317 template <
typename U>
1326 return m_promise ==
end;
1331 return m_promise !=
end;
1340 decltype(
auto)
operator++(
int)
1345 decltype(
auto)
operator*()
1350 decltype(
auto) operator->()
1352 return &(*m_promise);
1359 template <
typename U = first_yield_type>
1382 template <
typename U = first_yield_type>
1389 template <
typename U = first_yield_type>
1390 decltype(
auto)
operator++(
int)
1397 template <
typename U = first_yield_type>
1398 decltype(
auto)
operator*()
1404 template <
typename U = first_yield_type>
1405 decltype(
auto) operator->()
1413 bool m_completed =
false;
#define ZTH_MALLOC_INLINE
void set(type const &value=type()) noexcept
bool valid() const noexcept
Fiber-aware barrier/gate.
user_type const & user() const noexcept
Mutex RAII, that locks and unlocks the mutex automatically.
bool valid() const noexcept
virtual void wakeup(Listable &item, queue_type::user_type user, bool prio, size_t q) noexcept final
virtual char const * id_str() const noexcept override
string const & name() const noexcept
void acquire(count_type count=1)
queue_type::iterator enqueue(Listable &item, size_t q=0) noexcept
bool unblockAll(size_t q=0, bool prio=false) noexcept
friend cow_string str(UniqueIDBase const &)
Keeps track of a process-wide unique ID within the type T.
void wait(Listable &item, std::coroutine_handle<> waiter) noexcept
Mailbox(promise_base &owner, cow_string const &name="coro::Mailbox")
std::coroutine_handle waiter() const noexcept
bool abandoned() const noexcept
virtual void wait(typename base::assigned_type assigned) override
virtual ~Mailbox() noexcept override=default
virtual base::assigned_type wakeup(Listable &item, typename base::queue_type::user_type user, bool prio) noexcept override
promise_base & owner() const noexcept
bool valid(std::coroutine_handle<> waiter) const noexcept
bool valid() const noexcept
type take(std::coroutine_handle<> waiter)
iterator(generator_promise &p)
bool operator!=(end_type end) const noexcept
bool operator==(end_type end) const noexcept
auto & mailbox() noexcept
bool operator!=(end_type) const noexcept
decltype(auto) yield_value(T_ &&v) noexcept
void unhandled_exception() noexcept
bool operator==(end_type) const noexcept
decltype(auto) final_suspend() noexcept
bool valid() const noexcept
void return_void() noexcept
virtual ~generator_promise() noexcept override=default
std::coroutine_handle waiter() const noexcept
bool completed() const noexcept
typename std::tuple_element_t< 0, std::tuple< T... > > first_yield_type
auto get_return_object() noexcept
std::tuple< impl::generator_Mailbox_type< T >... > Mailbox_types
generator_promise & operator++()
std::coroutine_handle waiter() const noexcept
auto const & mailbox() const noexcept
A coroutine generator producing a sequence of values.
decltype(auto) fiber(char const *name=nullptr)
void setName(string name) noexcept
decltype(auto) as() const
generator(std::coroutine_handle< promise_type > h) noexcept
char const * id_str() const noexcept
bool completed() const noexcept
generator(zth::SharedPointer< promise_type > const &p) noexcept
bool valid() const noexcept
promise_type::end_type end()
generator(promise_type *p=nullptr) noexcept
generator(zth::SharedPointer< promise_type > &&p) noexcept
typename promise_type::Mailbox_types Mailbox_types
promise_type * promise() const noexcept
std::coroutine_handle continuation() noexcept
promise_base(cow_string const &name)
virtual bool running() const noexcept=0
void set_continuation(std::coroutine_handle<> cont={}) noexcept
ZTH_MALLOC_ATTR((malloc, alloc_size(1))) static void *operator new(std
virtual std::coroutine_handle handle() noexcept=0
virtual ~promise_base() noexcept override=default
bool has_continuation() const noexcept
decltype(auto) final_suspend() noexcept
promise_type & self() noexcept
decltype(auto) initial_suspend() noexcept
decltype(auto) await_transform(A &&a) noexcept
virtual std::coroutine_handle handle() noexcept final
virtual bool running() const noexcept final
promise_type const & self() const noexcept
virtual ~promise() noexcept override
promise(cow_string const &name)
void running(bool set) noexcept
auto typedHandle() noexcept
virtual ~task_promise() noexcept override=default
void unhandled_exception() noexcept
bool completed() const noexcept
Future< return_type > Future_type
virtual ~task_promise_base() noexcept override=default
Future_type & future() noexcept
auto get_return_object() noexcept
Future< return_type > Future_type
void return_value(T_ &&v) noexcept
virtual ~task_promise() noexcept override=default
A coroutine task producing a single result value.
decltype(auto) await_resume()
task(zth::SharedPointer< promise_type > const &p) noexcept
char const * id_str() const noexcept
void setName(string name) noexcept
task(promise_type *p=nullptr) noexcept
typename promise_type::Future_type Future_type
promise_type * promise() const noexcept
std::coroutine_handle< promise_type > await_suspend(std::coroutine_handle<> h) noexcept
bool await_ready() const noexcept
task(zth::SharedPointer< promise_type > &&p) noexcept
decltype(auto) fiber(char const *name=nullptr)
Future_type & future() const
bool completed() const noexcept
task(std::coroutine_handle< promise_type > h) noexcept
fiber_type< F >::factory factory(F &&f, char const *name=nullptr)
Create a new fiber.
@ awaitable
Start fiber, returning a future to await.
#define zth_dbg(group, fmt, a...)
Debug printf()-like function.
#define ZTH_CLASS_NEW_DELETE(T)
Define new/delete operators for a class, which are allocator-aware.
::std::future< zth::type< T > > future
Forces the fiber to have a future that outlives the fiber.
generator_fiber & operator<<(M const &m) &
decltype(auto) await_resume()
std::coroutine_handle await_suspend(std::coroutine_handle<> h) noexcept
char const * id_str() const noexcept
decltype(auto) await_ready() noexcept
Exception thrown when a coroutine has already completed.
Exception thrown when an operation cannot be performed due to an invalid coroutine state.
Makes the fiber pass the given gate upon exit.
#define zth_assert(expr)
assert(), but better integrated in Zth.