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();
585 decltype(
auto)
operator()()
590 decltype(
auto)
fiber(
char const* name =
nullptr)
593 name =
"coro::fiber";
603 auto&
operator co_await()
noexcept
613 std::coroutine_handle<promise_type>
await_suspend(std::coroutine_handle<> h)
noexcept
617 p->set_continuation(h);
618 return p->typedHandle();
652 return m_future.
valid();
664 m_future.
set(std::current_exception());
680 template <typename T_>
697 void return_void() noexcept
736 std::coroutine_handle<>
waiter() const noexcept
759 m_waiter = std::coroutine_handle<>{};
780 while(!
valid(assigned)) {
789 bool prio)
noexcept override
798 m_waiter = std::coroutine_handle<>::from_address(user);
805 std::coroutine_handle<> m_waiter;
814 std::coroutine_handle<> waiter{};
816 char const* id_str() const noexcept
818 return mailbox.owner().
id_str();
821 bool await_ready() noexcept
823 return mailbox.abandoned()
825 || mailbox.owner().running();
828 std::coroutine_handle<> await_suspend(std::coroutine_handle<> h)
noexcept
831 mailbox.
wait(item, waiter);
832 return mailbox.owner().handle();
835 decltype(
auto) await_resume()
837 if(mailbox.
valid(waiter)) {
839 return mailbox.
take(waiter);
840 }
else if(mailbox.abandoned()) {
846 return mailbox.
take();
854template <
typename Generator,
typename Fiber>
859 template <
typename M>
860 requires(std::is_base_of_v<FiberManipulator, M>)
generator_fiber&
operator<<(M
const& m) &
867 template <
typename M>
868 requires(std::is_base_of_v<FiberManipulator, M>)
generator_fiber&&
operator<<(M
const& m) &&
871 return std::move(*
this);
884template <
typename Generator,
typename Fiber>
887template <
typename G,
typename F>
894template <
typename... T>
895class generator_promise;
903template <
typename... T>
904requires(
sizeof...(T) >= 1, (!std::is_void_v<T> && ...))
class generator {
909 explicit generator(std::coroutine_handle<promise_type> h) noexcept
910 : m_promise{h.promise()}
918 : m_promise{std::move(p)}
927 return m_promise.get();
933 return p ? p->id_str() :
"coro::generator";
940 p->setName(std::move(name));
945 auto* p = m_promise.get();
946 return !p || p->completed();
949 template <
typename U =
typename promise_type::first_yield_type>
952 auto* p = m_promise.get();
956 return p->template mailbox<U>();
959 template <
typename U>
960 decltype(
auto)
as()
const
965 template <
typename U =
typename promise_type::first_yield_type>
968 auto* p = m_promise.get();
969 return p && p->template mailbox<U>().valid();
972 template <
typename U =
typename promise_type::first_yield_type>
975 auto* p = m_promise.get();
979 return p->template value<U>();
982 template <
typename U =
typename promise_type::first_yield_type>
985 auto* p = m_promise.get();
989 p->template generate<U>();
994 auto* p = m_promise.get();
1003# ifdef ZTH_FUTURE_EXCEPTION
1004 auto exc = p->mailbox().exception();
1006 std::rethrow_exception(exc);
1010 decltype(
auto)
fiber(
char const* name =
nullptr)
1013 name =
"coro::fiber";
1030 auto* p = m_promise.get();
1046template <
template <
typename...>
class G,
typename... T>
1047requires(std::is_same_v<std::remove_reference_t<G<T...>>, generator<T...>>)
1048 static inline decltype(
auto)
awaitable(G<T...> g) noexcept
1051 sizeof...(T) == 1,
"Use generator.as<type>() to select the yield type to await on");
1057template <
typename T>
1059 std::is_reference_v<T>, std::reference_wrapper<std::remove_reference_t<T>>, T>>;
1061template <
typename A,
typename B>
1062inline constexpr bool is_identical_v = std::is_same_v<A, B>;
1064template <
typename A,
typename B>
1065inline constexpr bool is_similar_v =
1066 is_identical_v<A, B> || std::is_same_v<std::decay_t<A>, std::decay_t<B>>;
1068template <
typename A,
typename B>
1069inline constexpr bool is_convertible_v = is_similar_v<A, B> || std::is_convertible_v<A, B&>;
1071template <
typename Needle,
typename... Haystack>
1072struct has_identical_type : std::false_type {};
1074template <
typename Needle,
typename First,
typename... Rest>
1075struct has_identical_type<Needle, First, Rest...>
1076 : std::conditional_t<
1077 is_identical_v<Needle, First>, std::true_type,
1078 has_identical_type<Needle, Rest...>> {};
1080template <
typename Needle,
typename... Haystack>
1081struct find_identical_type {};
1083template <
typename Needle,
typename First,
typename... Rest>
1084struct find_identical_type<Needle, First, Rest...> {
1085 using type = std::conditional_t<
1086 is_identical_v<Needle, First>, First,
1087 typename find_identical_type<Needle, Rest...>::type>;
1090template <
typename Needle,
typename... Haystack>
1091struct has_similar_type : std::false_type {};
1093template <
typename Needle,
typename First,
typename... Rest>
1094struct has_similar_type<Needle, First, Rest...>
1095 : std::conditional_t<
1096 is_similar_v<Needle, First> && !has_identical_type<Needle, Rest...>::value,
1097 std::true_type, has_similar_type<Needle, Rest...>> {};
1099template <
typename Needle,
typename... Haystack>
1100struct find_similar_type {
1104template <
typename Needle,
typename First,
typename... Rest>
1105struct find_similar_type<Needle, First, Rest...> {
1106 using type = std::conditional_t<
1107 is_similar_v<Needle, First> && !has_identical_type<Needle, Rest...>::value, First,
1108 typename find_similar_type<Needle, Rest...>::type>;
1111template <
typename Needle,
typename... Haystack>
1112struct find_convertible_type {
1116template <
typename Needle,
typename First,
typename... Rest>
1117struct find_convertible_type<Needle, First, Rest...> {
1118 using type = std::conditional_t<
1119 is_convertible_v<Needle, First> && !has_similar_type<Needle, Rest...>::value, First,
1120 typename find_convertible_type<Needle, Rest...>::type>;
1123template <
typename A,
typename T>
1124static inline A repeat(A a)
1131template <
typename Needle,
typename... Haystack>
1132struct find_type : impl::find_convertible_type<Needle, Haystack...> {};
1134template <
typename... T>
1147 :
base{
"coro::generator"}
1156 return std::get<impl::generator_Mailbox_type<U>>(m_mailbox);
1159 template <
typename U = first_yield_type>
1162 return std::get<impl::generator_Mailbox_type<U>>(m_mailbox);
1170 template <
typename U = first_yield_type>
1173 return mailbox<U>().valid() && !
completed();
1176 template <
typename U = first_yield_type>
1182 return mailbox<U>().take();
1185 template <
typename U = first_yield_type>
1190 if(mailbox<U>().
valid())
1213 std::coroutine_handle<>
waiter() const noexcept
1215 std::array<std::coroutine_handle<>,
sizeof...(T)> waiters = {waiter<T>()...};
1217 for(
size_t i = 0; i <
sizeof...(T); ++i)
1224 template <
typename U>
1225 std::coroutine_handle<>
waiter() const noexcept
1227 return mailbox<U>().waiter();
1230 template <
typename T_>
1233 using M =
typename find_type<T_, T...>::type;
1235 mailbox<M>().put(std::forward<T_>(v));
1240 char const* id_str()
const noexcept
1245 bool await_ready()
noexcept
1250 std::coroutine_handle<>
1251 await_suspend(std::coroutine_handle<>
UNUSED_PAR(h))
noexcept
1256 void await_resume()
noexcept {}
1267 decltype(std::declval<base>().final_suspend()) awaitable;
1269 bool await_ready()
noexcept
1271 return awaitable.await_ready();
1274 std::coroutine_handle<> await_suspend(std::coroutine_handle<> h)
noexcept
1280 return awaitable.await_suspend(h);
1283 decltype(
auto) await_resume()
noexcept
1285 return awaitable.await_resume();
1310 template <
typename U>
1319 return m_promise ==
end;
1324 return m_promise !=
end;
1333 decltype(
auto)
operator++(
int)
1338 decltype(
auto)
operator*()
1343 decltype(
auto) operator->()
1345 return &(*m_promise);
1352 template <
typename U = first_yield_type>
1375 template <
typename U = first_yield_type>
1382 template <
typename U = first_yield_type>
1383 decltype(
auto)
operator++(
int)
1390 template <
typename U = first_yield_type>
1391 decltype(
auto)
operator*()
1397 template <
typename U = first_yield_type>
1398 decltype(
auto) operator->()
1406 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.