summaryrefslogtreecommitdiff
path: root/async/async.h
blob: 80a66f4a9e0554df04c246822146cdad4f27ef4c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#pragma once

#include <coroutine>

template <typename T>
class promise_return {
    private:
        T val;

    public:
        void return_value(T v) {
            val = v;
        }

        T value() {
            return val;
        }
};

template <>
class promise_return<void> {
    public:
        void return_void() {}
        void value() {}
};

/// Coroutine future for asynchronous function. Implements \term{awaitable}, \term{co_await}, \term{co_return}.
///
/// \tparam T Return type.
///
/// Manages coroutine state.
/// Awaiting an empty object or destroying the coroutine state while it's being awaited results in undefined behavior.
///
template <typename T = void, typename initial_awaitable = std::suspend_always>
class async {
    public:
        class promise_type : public promise_return<T> {
            public:
                using handle_type = std::coroutine_handle<promise_type>;

                async get_return_object() {
                    return {handle_type::from_promise(*this)};
                }

                std::coroutine_handle<> parent;

                class final_awaitable {
                    public:
                        bool await_ready() { return false; }

                        std::coroutine_handle<> await_suspend(handle_type h) {
                            return h.promise().parent;
                        }

                        void await_resume() {}
                };

                initial_awaitable initial_suspend() { return {}; }
                final_awaitable final_suspend() { return {}; }
        };

        bool await_ready() {
            return handle.done();
        }

        auto await_suspend(std::coroutine_handle<> h) {
            handle.promise().parent = h;

            return handle;
        }

        T await_resume() {
            return handle.promise().value();
        }

        /// Construct empty object.
        async() : handle(nullptr) {}

        /// Transfer ownership of coroutine state, leaving *other* empty.
        async(async&& other) {
            handle = other.handle;
            other.handle = nullptr;
        }

        /// Transfer ownership of coroutine state, leaving *other* empty.
        async& operator=(async&& other) {
            handle = other.handle;
            other.handle = nullptr;

            return *this;
        }

        /// Destroy coroutine state if not empty.
        ~async() {
            if(handle) {
                handle.destroy();
            }
        }

    private:
        promise_type::handle_type handle;

        async(promise_type::handle_type h) : handle(h) {}

        async(const async&) = delete;
        async& operator=(const async&) = delete;
};