userver
C++ Async Framework
Toggle main menu visibility
Loading...
Searching...
No Matches
future.hpp
Go to the documentation of this file.
1
#
pragma
once
2
3
/// @file userver/engine/future.hpp
4
/// @brief @copybrief engine::Future
5
6
#
include
<
chrono
>
7
#
include
<
exception
>
8
#
include
<
future
>
9
#
include
<
memory
>
10
11
#
include
<
userver
/
compiler
/
impl
/
lifetime
.
hpp
>
12
#
include
<
userver
/
engine
/
awaitable
.
hpp
>
13
#
include
<
userver
/
engine
/
deadline
.
hpp
>
14
#
include
<
userver
/
engine
/
future_status
.
hpp
>
15
#
include
<
userver
/
engine
/
impl
/
future_state
.
hpp
>
16
#
include
<
userver
/
utils
/
impl
/
internal_tag
.
hpp
>
17
18
// TODO remove extra includes
19
#
include
<
userver
/
utils
/
assert
.
hpp
>
20
21
USERVER_NAMESPACE_BEGIN
22
23
namespace
engine {
24
25
/// @ingroup userver_concurrency
26
///
27
/// @brief std::promise replacement for asynchronous tasks that works in pair
28
/// with engine::Future
29
///
30
/// engine::Promise can be used both from coroutines and from non-coroutine
31
/// threads.
32
///
33
/// ## Example usage:
34
///
35
/// @snippet engine/future_test.cpp Sample engine::Future usage
36
///
37
/// @see @ref scripts/docs/en/userver/synchronization.md
38
template
<
typename
T>
39
class
Promise
;
40
41
/// @ingroup userver_concurrency
42
///
43
/// @brief std::future replacement for asynchronous tasks that works in pair
44
/// with engine::Promise
45
///
46
/// engine::Future can only be used from coroutine threads.
47
///
48
/// ## Example usage:
49
///
50
/// @snippet engine/future_test.cpp Sample engine::Future usage
51
///
52
/// @see @ref scripts/docs/en/userver/synchronization.md
53
template
<
typename
T>
54
class
Future
final
{
55
public
:
56
/// Creates an Future without a valid state.
57
Future
() =
default
;
58
59
Future(
const
Future&) =
delete
;
60
Future(Future&&)
noexcept
=
default
;
61
Future& operator=(
const
Future&) =
delete
;
62
Future& operator=(Future&&)
noexcept
=
default
;
63
64
/// @brief Returns whether this Future holds a valid state.
65
bool
valid
()
const
noexcept
;
66
67
/// @brief Returns whether the value is available.
68
/// @warning If value is set and task is being canceled or if Promise has been
69
/// destroyed without setting a value, returns true.
70
/// @throw std::future_error if Future holds no state or if the value has
71
/// already been retrieved.
72
bool
is_ready
()
const
;
73
74
/// @brief Waits for value availability and retrieves it.
75
/// @throw WaitInterruptedException if the current task has been cancelled in
76
/// the process.
77
/// @throw std::future_error if Future holds no state, if the Promise has
78
/// been destroyed without setting a value or if the value has already been
79
/// retrieved.
80
T
get
();
81
82
/// @brief Waits for value availability.
83
/// @returns `FutureStatus::kReady` if the value is available.
84
/// @returns `FutureStatus::kCancelled` if current task is being cancelled.
85
/// @throw std::future_error if Future holds no state.
86
[[nodiscard]]
FutureStatus
wait
()
const
;
87
88
/// @brief Waits for value availability until the timeout expires or until the
89
/// task is cancelled.
90
/// @returns `FutureStatus::kReady` if the value is available.
91
/// @returns `FutureStatus::kTimeout` if `timeout` has expired.
92
/// @returns `FutureStatus::kCancelled` if current task is being cancelled.
93
/// @throw std::future_error if Future holds no state.
94
template
<
typename
Rep,
typename
Period>
95
FutureStatus
wait_for
(std::chrono::duration<Rep, Period> timeout)
const
;
96
97
/// @brief Waits for value availability until the deadline is reached or until
98
/// the task is cancelled.
99
/// @returns `FutureStatus::kReady` if the value is available.
100
/// @returns `FutureStatus::kTimeout` if `until` time point was reached.
101
/// @returns `FutureStatus::kCancelled` if current task is being cancelled.
102
/// @throw std::future_error if Future holds no state.
103
template
<
typename
Clock,
typename
Duration>
104
FutureStatus
wait_until
(std::chrono::time_point<Clock, Duration> until)
const
;
105
106
/// @brief Waits for value availability until the deadline is reached or until
107
/// the task is cancelled.
108
/// @returns `FutureStatus::kReady` if the value is available.
109
/// @returns `FutureStatus::kTimeout` if `deadline` was reached.
110
/// @returns `FutureStatus::kCancelled` if current task is being cancelled.
111
/// @throw std::future_error if Future holds no state.
112
FutureStatus
wait_until
(Deadline deadline)
const
;
113
114
/// Satisfies @ref engine::Awaitable, for use with @ref engine::WaitAnyContext and friends.
115
AwaitableToken
GetAwaitableToken
()
noexcept
USERVER_IMPL_LIFETIME_BOUND {
116
return
state_ ? state_->GetAwaitableToken() : AwaitableToken
{
}
;
117
}
118
119
private
:
120
friend
class
Promise
<T>;
121
122
explicit
Future(std::shared_ptr<
impl
::FutureState<T>> state);
123
124
void
CheckValid()
const
;
125
126
std::shared_ptr<
impl
::FutureState<T>> state_;
127
};
128
129
template
<
typename
T>
130
class
Promise
final
{
131
public
:
132
/// Creates a new asynchronous value store.
133
Promise
();
134
135
~Promise();
136
137
Promise(
const
Promise
&) =
delete
;
138
Promise(
Promise
&&)
noexcept
=
default
;
139
Promise
& operator=(
const
Promise
&) =
delete
;
140
Promise
& operator=(
Promise
&&)
noexcept
;
141
142
/// Retrieves the Future associated with this value store.
143
/// @throw std::future_error if the Future has already been retrieved.
144
[[
nodiscard
]] Future<T>
get_future
();
145
146
/// Stores a value for retrieval.
147
/// @throw std::future_error if a value or an exception has already been set.
148
void
set_value
(
const
T&);
149
150
/// Stores a value for retrieval.
151
/// @throw std::future_error if a value or an exception has already been set.
152
void
set_value
(T&&);
153
154
/// Stores an exception to be thrown on retrieval.
155
/// @throw std::future_error if a value or an exception has already been set.
156
void
set_exception
(std::exception_ptr ex);
157
158
private
:
159
std::shared_ptr<
impl
::FutureState<T>> state_;
160
};
161
162
template
<>
163
class
Promise<
void
>
final
{
164
public
:
165
/// Creates a new asynchronous signal store.
166
Promise
();
167
168
~Promise();
169
170
Promise(
const
Promise
&) =
delete
;
171
Promise(
Promise
&&)
noexcept
=
default
;
172
Promise
& operator=(
const
Promise
&) =
delete
;
173
Promise
& operator=(
Promise
&&)
noexcept
;
174
175
/// Retrieves the Future associated with this signal store.
176
/// @throw std::future_error if the Future has already been retrieved.
177
[[nodiscard]] Future<
void
>
get_future
();
178
179
/// Stores a signal for retrieval.
180
/// @throw std::future_error if a signal or an exception has already been set.
181
void
set_value
();
182
183
/// Stores an exception to be thrown on retrieval.
184
/// @throw std::future_error if a signal or an exception has already been set.
185
void
set_exception
(std::exception_ptr ex);
186
187
private
:
188
std::shared_ptr<
impl
::FutureState<
void
>> state_;
189
};
190
191
template
<
typename
T>
192
bool
Future<T>::
valid
()
const
noexcept
{
193
return
!!state_;
194
}
195
196
template
<
typename
T>
197
bool
Future<T>::
is_ready
()
const
{
198
CheckValid();
199
return
state_->IsReady();
200
}
201
202
template
<
typename
T>
203
T Future<T>::
get
() {
204
CheckValid();
205
return
std::exchange(state_,
nullptr
)->Get();
206
}
207
208
template
<
typename
T>
209
FutureStatus
Future<T>::
wait
()
const
{
210
CheckValid();
211
return
state_->WaitUntil({});
212
}
213
214
template
<
typename
T>
215
template
<
typename
Rep,
typename
Period>
216
FutureStatus
Future<T>::
wait_for
(std::chrono::duration<Rep, Period> timeout)
const
{
217
return
wait_until(Deadline::FromDuration(timeout));
218
}
219
220
template
<
typename
T>
221
template
<
typename
Clock,
typename
Duration>
222
FutureStatus
Future<T>::
wait_until
(std::chrono::time_point<Clock, Duration> until)
const
{
223
return
wait_until(Deadline::FromTimePoint(until));
224
}
225
226
template
<
typename
T>
227
FutureStatus
Future<T>::
wait_until
(Deadline deadline)
const
{
228
CheckValid();
229
return
state_->WaitUntil(deadline);
230
}
231
232
template
<
typename
T>
233
Future<T>::Future(std::shared_ptr<
impl
::FutureState<T>> state)
234
: state_(std::move(state))
235
{
236
CheckValid();
237
state_->OnFutureCreated();
238
}
239
240
template
<
typename
T>
241
void
Future<T>::CheckValid()
const
{
242
if
(!state_) {
243
throw
std::future_error(std::future_errc::no_state);
244
}
245
}
246
247
template
<
typename
T>
248
Promise
<T>::
Promise
()
249
: state_(std::make_shared<
impl
::FutureState<T>>())
250
{}
251
252
template
<
typename
T>
253
Promise
<T>&
Promise
<T>::operator=(
Promise
<T>&& other)
noexcept
{
254
if
(
this
== &other) {
255
return
*
this
;
256
}
257
{
258
[[maybe_unused]]
const
auto
for_destruction = std::move(*
this
);
259
}
260
state_ = std::move(other.state_);
261
return
*
this
;
262
}
263
264
template
<
typename
T>
265
Promise
<T>::~Promise() {
266
if
(state_ && !state_->IsReady() && state_->IsFutureCreated()) {
267
try
{
268
state_->SetException(std::make_exception_ptr(std::future_error(std::future_errc::broken_promise)));
269
}
catch
(
const
std::future_error&) {
270
UASSERT_MSG
(
false
,
"Invalid promise usage"
);
271
}
272
}
273
}
274
275
template
<
typename
T>
276
Future<T>
Promise
<T>::
get_future
() {
277
return
Future<T>(state_);
278
}
279
280
template
<
typename
T>
281
void
Promise
<T>::
set_value
(
const
T& value) {
282
state_->SetValue(value);
283
}
284
285
template
<
typename
T>
286
void
Promise
<T>::
set_value
(T&& value) {
287
state_->SetValue(std::move(value));
288
}
289
290
template
<
typename
T>
291
void
Promise
<T>::
set_exception
(std::exception_ptr ex) {
292
state_->SetException(std::move(ex));
293
}
294
295
inline
Promise
<
void
>::
Promise
()
296
: state_(std::make_shared<
impl
::FutureState<
void
>>())
297
{}
298
299
inline
Promise
<
void
>&
Promise
<
void
>::operator=(
Promise
<
void
>&& other)
noexcept
{
300
if
(
this
== &other) {
301
return
*
this
;
302
}
303
{
304
[[maybe_unused]]
const
auto
for_destruction = std::move(*
this
);
305
}
306
state_ = std::move(other.state_);
307
return
*
this
;
308
}
309
310
inline
Promise
<
void
>::~Promise() {
311
if
(state_ && !state_->IsReady() && state_->IsFutureCreated()) {
312
try
{
313
state_->SetException(std::make_exception_ptr(std::future_error(std::future_errc::broken_promise)));
314
}
catch
(
const
std::future_error&) {
315
UASSERT_MSG
(
false
,
"Invalid promise usage"
);
316
}
317
}
318
}
319
320
inline
Future<
void
>
Promise
<
void
>::
get_future
() {
return
Future<
void
>(state_); }
321
322
inline
void
Promise
<
void
>::
set_value
() { state_->SetValue(); }
323
324
inline
void
Promise
<
void
>::
set_exception
(std::exception_ptr ex) { state_->SetException(std::move(ex)); }
325
326
}
// namespace engine
327
328
USERVER_NAMESPACE_END
userver
engine
future.hpp
Generated on
for userver by
Doxygen
1.17.0