forked from andreasbuhr/cppcoro
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathresume_on.hpp
More file actions
131 lines (110 loc) · 3.56 KB
/
Copy pathresume_on.hpp
File metadata and controls
131 lines (110 loc) · 3.56 KB
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
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Lewis Baker
// Licenced under MIT license. See LICENSE.txt for details.
///////////////////////////////////////////////////////////////////////////////
#ifndef CPPCORO_RESUME_ON_HPP_INCLUDED
#define CPPCORO_RESUME_ON_HPP_INCLUDED
#include <cppcoro/task.hpp>
#include <cppcoro/async_generator.hpp>
#include <cppcoro/awaitable_traits.hpp>
#include <cppcoro/detail/get_awaiter.hpp>
#include <exception>
#include <type_traits>
namespace cppcoro
{
template<typename SCHEDULER>
struct resume_on_transform
{
explicit resume_on_transform(SCHEDULER& s) noexcept
: scheduler(s)
{}
SCHEDULER& scheduler;
};
template<typename SCHEDULER>
resume_on_transform<SCHEDULER> resume_on(SCHEDULER& scheduler) noexcept
{
return resume_on_transform<SCHEDULER>(scheduler);
}
template<typename T, typename SCHEDULER>
decltype(auto) operator|(T&& value, resume_on_transform<SCHEDULER> transform)
{
return resume_on(transform.scheduler, std::forward<T>(value));
}
template<
typename SCHEDULER,
typename AWAITABLE,
typename AWAIT_RESULT = detail::remove_rvalue_reference_t<typename awaitable_traits<AWAITABLE>::await_result_t>,
std::enable_if_t<!std::is_void_v<AWAIT_RESULT>, int> = 0>
auto resume_on(SCHEDULER& scheduler, AWAITABLE awaitable)
-> task<AWAIT_RESULT>
{
bool rescheduled = false;
std::exception_ptr ex;
try
{
// We manually get the awaiter here so that we can keep
// it alive across the call to `scheduler.schedule()`
// just in case the result is a reference to a value
// in the awaiter that would otherwise be a temporary
// and destructed before the value could be returned.
auto&& awaiter = detail::get_awaiter(static_cast<AWAITABLE&&>(awaitable));
auto&& result = co_await static_cast<decltype(awaiter)>(awaiter);
// Flag as rescheduled before scheduling in case it is the
// schedule() operation that throws an exception as we don't
// want to attempt to schedule twice if scheduling fails.
rescheduled = true;
co_await scheduler.schedule();
co_return static_cast<decltype(result)>(result);
}
catch (...)
{
ex = std::current_exception();
}
// We still want to resume on the scheduler even in the presence
// of an exception.
if (!rescheduled)
{
co_await scheduler.schedule();
}
std::rethrow_exception(ex);
}
template<
typename SCHEDULER,
typename AWAITABLE,
typename AWAIT_RESULT = detail::remove_rvalue_reference_t<typename awaitable_traits<AWAITABLE>::await_result_t>,
std::enable_if_t<std::is_void_v<AWAIT_RESULT>, int> = 0>
auto resume_on(SCHEDULER& scheduler, AWAITABLE awaitable)
-> task<>
{
std::exception_ptr ex;
try
{
co_await static_cast<AWAITABLE&&>(awaitable);
}
catch (...)
{
ex = std::current_exception();
}
// NOTE: We're assuming that `schedule()` operation is noexcept
// here. If it were to throw what would we do if 'ex' was non-null?
// Presumably we'd treat it the same as throwing an exception while
// unwinding and call std::terminate()?
co_await scheduler.schedule();
if (ex)
{
std::rethrow_exception(ex);
}
}
template<typename SCHEDULER, typename T>
async_generator<T> resume_on(SCHEDULER& scheduler, async_generator<T> source)
{
for (detail::async_generator_iterator<T> iter = co_await source.begin(); iter != source.end();)
{
auto& value = *iter;
co_await scheduler.schedule();
co_yield value;
co_await ++iter; // moved due to error: insufficient contextual information to determine type on old compilers
}
}
}
#endif