-
Notifications
You must be signed in to change notification settings - Fork 0
/
AwaitWrapper.h
84 lines (66 loc) · 2.22 KB
/
AwaitWrapper.h
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
#pragma once
#include "Executor.h"
template <typename FutureRef>
class AwaitWrapper {
public:
struct promise_type {
std::experimental::suspend_always initial_suspend() { return{}; }
std::experimental::suspend_never final_suspend() {
executor_->add([awaiter = std::move(awaiter_)]() mutable {
awaiter();
});
return{};
}
void return_void() {}
AwaitWrapper get_return_object() {
return{ *this };
}
Executor* executor_;
std::experimental::coroutine_handle<> awaiter_;
};
AwaitWrapper(FutureRef futureRef) : futureRef_(std::move(futureRef)) {}
static AwaitWrapper<FutureRef> awaitWrapper() {
co_return;
}
static AwaitWrapper create(FutureRef futureRef, Executor* executor) {
auto ret = awaitWrapper();
new(&ret.futureRef_)FutureRef(std::move(futureRef));
ret.promise_->executor_ = executor;
return ret;
}
bool await_ready() {
return futureRef_.get().await_ready();
}
static constexpr bool await_suspend_returns_void =
std::is_same<decltype((*static_cast<FutureRef*>(nullptr)).get().await_suspend(std::experimental::coroutine_handle<>())), void >::value;
template <typename _ = std::enable_if_t<!await_suspend_returns_void>,
typename __ = void>
bool await_suspend(std::experimental::coroutine_handle<> awaiter) {
if (promise_) {
promise_->awaiter_ = std::move(awaiter);
return futureRef_.get().await_suspend(
std::experimental::coroutine_handle<promise_type>::from_promise(*promise_));
}
return futureRef_.get().await_suspend(awaiter);
}
template <typename _ = std::enable_if_t<await_suspend_returns_void>>
void await_suspend(std::experimental::coroutine_handle<> awaiter) {
if (promise_) {
promise_->awaiter_ = std::move(awaiter);
futureRef_.get().await_suspend(
std::experimental::coroutine_handle<promise_type>::from_promise(*promise_));
return;
}
futureRef_.get().await_suspend(awaiter);
}
decltype((*static_cast<FutureRef*>(nullptr)).get().await_resume()) await_resume() {
return futureRef_.get().await_resume();
}
private:
AwaitWrapper(promise_type& promise) : promise_(&promise) {}
promise_type* promise_{ nullptr };
// Should be std::optional, we don't call it's destructor, but that should be ok for ref types
union {
FutureRef futureRef_;
};
};