-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcoFuture.cpp
109 lines (94 loc) · 2.9 KB
/
coFuture.cpp
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
#include <fmt/core.h>
#include <chrono>
#include <coroutine>
#include <exception>
#include <future>
#include <thread>
#include <type_traits>
#include <vector>
// Enable the use of std::future<T> as a coroutine type
// by using a std::promise<T> as the promise type.
template <typename T, typename... Args>
requires(!std::is_void_v<T> &&
!std::is_reference_v<T>) struct std::coroutine_traits<std::future<T>,
Args...> {
struct promise_type : std::promise<T> {
auto get_return_object() noexcept -> std::future<T> {
fmt::print("get_return_object()\n");
return this->get_future();
}
[[nodiscard]] auto initial_suspend() const noexcept -> std::suspend_never {
fmt::print("initial_suspend()\n");
return {};
}
[[nodiscard]] auto final_suspend() const noexcept -> std::suspend_never {
fmt::print("final_suspend()\n");
return {};
}
auto return_value(const T &value) noexcept(
std::is_nothrow_copy_constructible_v<T>) -> void {
fmt::print("return_value()\n");
this->set_value(value);
}
auto
return_value(T &&value) noexcept(std::is_nothrow_move_constructible_v<T>)
-> void {
fmt::print("return_value()\n");
this->set_value(std::move(value));
}
auto unhandled_exception() noexcept -> void {
fmt::print("unhandled_exception()\n");
this->set_exception(std::current_exception());
}
};
};
// Allow co_await'ing std::future<T> and std::future<void>
// by naively spawning a new thread for each co_await.
template <typename T>
requires(!std::is_reference_v<T>) [[nodiscard]] auto
operator co_await(std::future<T> future) noexcept {
struct awaiter : std::future<T> {
[[nodiscard]] auto await_ready() const noexcept -> bool {
fmt::print("await_ready()\n");
using namespace std::chrono_literals;
return this->wait_for(0s) != std::future_status::timeout;
}
auto await_suspend(std::coroutine_handle<> cont) const -> void {
fmt::print("await_suspend()\n");
std::thread([this, cont] {
this->wait();
cont();
}).detach();
}
[[nodiscard]] auto await_resume() -> T {
fmt::print("await_resume()\n");
return this->get();
}
};
fmt::print("operator co_await()\n");
return awaiter{std::move(future)};
}
auto compute(int id) -> std::future<int> {
fmt::print("compute({})\n", id);
int a = co_await std::async([] {
using namespace std::chrono_literals;
std::this_thread::sleep_for(1s);
return 6;
});
int b = co_await std::async([] {
using namespace std::chrono_literals;
std::this_thread::sleep_for(1s);
return 7;
});
co_return a *b;
}
auto main() -> int {
auto v = std::vector<std::future<int>>{};
for (int i = 0; i < 10; i++) {
v.push_back(compute(i));
}
for (auto &&fut : v) {
fmt::print("{}\n", fut.get());
}
return 0;
}