2#include <asyncpp/detail/concepts.h>
3#include <asyncpp/detail/promise_allocator_base.h>
5#include <asyncpp/policy.h>
21 template<
bool Eager = false, ByteAllocator Allocator = default_allocator_type>
22 struct fire_and_forget_task_impl {
24 class promise_type :
public promise_allocator_base<Allocator> {
25 std::atomic<size_t> m_ref_count{1};
26 std::function<void()> m_exception_handler{};
29 constexpr promise_type() noexcept = default;
30 promise_type(const promise_type&) = delete;
31 promise_type(promise_type&&) = delete;
33 auto get_return_object() noexcept {
return coroutine_handle<promise_type>::from_promise(*
this); }
34 constexpr auto initial_suspend() noexcept {
38 [[nodiscard]]
constexpr bool await_ready() const noexcept {
return Eager; }
39 constexpr void await_suspend(coroutine_handle<>)
const noexcept {}
40 constexpr void await_resume() const noexcept { self->ref(); }
44 auto final_suspend() noexcept {
47 [[nodiscard]]
constexpr bool await_ready() const noexcept {
48 return self->m_ref_count.fetch_sub(1) == 1;
50 void await_suspend(coroutine_handle<>)
const noexcept {}
51 constexpr void await_resume() const noexcept {}
55 constexpr void return_void() noexcept {}
56 void unhandled_exception() noexcept {
57 if (m_exception_handler)
58 m_exception_handler();
63 auto await_transform(exception_policy policy) {
64 m_exception_handler = std::move(policy.handler);
65 return suspend_never{};
68 constexpr U&& await_transform(U&& awaitable)
noexcept {
69 return static_cast<U&&
>(awaitable);
72 void unref() noexcept {
73 if (m_ref_count.fetch_sub(1) == 1) coroutine_handle<promise_type>::from_promise(*this).destroy();
75 void ref() noexcept { m_ref_count.fetch_add(1); }
80 fire_and_forget_task_impl(coroutine_handle<promise_type> hndl) noexcept : m_coro(hndl) {}
83 fire_and_forget_task_impl(fire_and_forget_task_impl&& other) noexcept
84 : m_coro(std::exchange(other.m_coro, {})) {}
87 fire_and_forget_task_impl& operator=(fire_and_forget_task_impl&& other)
noexcept {
88 m_coro = std::exchange(other.m_coro, m_coro);
92 fire_and_forget_task_impl(
const fire_and_forget_task_impl& other) : m_coro{other.m_coro} {
93 if (m_coro) m_coro.promise().ref();
96 fire_and_forget_task_impl& operator=(
const fire_and_forget_task_impl& other) {
98 if (m_coro) m_coro.promise().unref();
99 m_coro = other.m_coro;
100 if (m_coro) m_coro.promise().ref();
105 ~fire_and_forget_task_impl() {
106 if (m_coro) m_coro.promise().unref();
110 void start() noexcept
113 if (m_coro && !m_coro.done()) {
116 m_coro.promise().unref();
122 coroutine_handle<promise_type> m_coro;
127 template<
class Allocator = default_allocator_type>
128 using eager_fire_and_forget_task = detail::fire_and_forget_task_impl<true, Allocator>;
130 template<
class Allocator = default_allocator_type>
131 using fire_and_forget_task = detail::fire_and_forget_task_impl<false, Allocator>;
Provides a consistent import interface for coroutine, experimental/coroutine or a best effort fallbac...