-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathcoroutine.hpp
151 lines (129 loc) · 3.56 KB
/
coroutine.hpp
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#pragma once
#include "specific.hpp"
#include "stack.hpp"
#include <unistd/context.hpp>
#include <vector>
#include <functional>
#include <type_traits>
#include <system_error>
#include <stddef.h>
extern "C"
{
int yurco_swapcontext(ucontext_t* oucp, const ucontext_t* ucp);
}
namespace yurco
{
inline void swapcontext(ucontext_t* oucp, const ucontext_t* ucp)
{
const int ret = yurco_swapcontext(oucp, ucp);
if (-1 == ret)
throw std::system_error(errno, std::system_category(), "swapcontext()");
}
class Coroutine
{
public:
Coroutine(const Coroutine&) = delete;
template <class Func, class... Args>
inline Coroutine(Stack&& stack, Func&& func, Args&&... args) noexcept;
inline bool is_completed() const noexcept;
inline bool is_running() const noexcept;
inline void yield();
void operator() ();
void operator() (const std::nothrow_t&) noexcept;
inline void set_exception(const std::exception_ptr& e) noexcept;
inline const std::exception_ptr& get_exception() const noexcept;
inline void rethrow();
inline Stack&& take_away_stack() noexcept;
protected:
union ptr2int
{
struct
{
int a;
int b;
} u;
Coroutine* ptr;
};
bool m_completed = true;
std::exception_ptr m_exception;
unistd::ucontext m_context;
unistd::ucontext* m_retpoint = nullptr;
Stack m_stack;
std::function<void(Coroutine&)> m_func;
inline void complete() noexcept;
inline void uncomplete() noexcept;
void entry() noexcept;
static void entry(int a, int b) noexcept;
template <bool pass_coro>
struct generate_func;
}; // class Coroutine
template <>
struct Coroutine::generate_func<true>
{
template <class Func, class... Args>
inline static std::function<void(Coroutine&)> get(Func&& func, Args&&... args) noexcept
{
return std::bind(std::forward<Func>(func), std::placeholders::_1, std::forward<Args>(args)...);
}
};
template <>
struct Coroutine::generate_func<false>
{
template <class Func, class... Args>
inline static std::function<void(Coroutine&)> get(Func&& func, Args&&... args) noexcept
{
return std::bind(std::forward<Func>(func), std::forward<Args>(args)...);
}
};
bool Coroutine::is_completed() const noexcept
{
return m_completed;
}
void Coroutine::complete() noexcept
{
m_completed = true;
}
void Coroutine::uncomplete() noexcept
{
m_completed = false;
}
bool Coroutine::is_running() const noexcept
{
return m_retpoint != nullptr;
}
void Coroutine::yield()
{
assert(is_running());
assert(!std::current_exception());
yurco::swapcontext(&m_context, m_retpoint);
yurco::set_coroutine(this);
rethrow();
}
void Coroutine::set_exception(const std::exception_ptr& e) noexcept
{
m_exception = e;
}
const std::exception_ptr& Coroutine::get_exception() const noexcept
{
return m_exception;
}
void Coroutine::rethrow()
{
if (m_exception)
{
std::exception_ptr e = get_exception();
set_exception(nullptr);
std::rethrow_exception(e);
}
}
Stack&& Coroutine::take_away_stack() noexcept
{
return std::move(m_stack);
}
template <class Func, class... Args>
Coroutine::Coroutine(Stack&& stack, Func&& func, Args&&... args) noexcept:
m_stack(std::forward<Stack>(stack)),
m_func(generate_func<std::is_invocable_r_v<void, Func, Coroutine&, Args&...>>::get(std::forward<Func>(func), std::forward<Args>(args)...))
{
}
} // namespace yurco