userver
C++ Async Framework
Toggle main menu visibility
Loading...
Searching...
No Matches
lazy_value.hpp
Go to the documentation of this file.
1
#
pragma
once
2
3
/// @file userver/concurrent/lazy_value.hpp
4
/// @brief @copybrief concurrent::LazyValue
5
6
#
include
<
atomic
>
7
#
include
<
exception
>
8
#
include
<
utility
>
9
10
#
include
<
userver
/
engine
/
condition_variable
.
hpp
>
11
#
include
<
userver
/
engine
/
exception
.
hpp
>
12
#
include
<
userver
/
engine
/
task
/
cancel
.
hpp
>
13
#
include
<
userver
/
utils
/
assert
.
hpp
>
14
#
include
<
userver
/
utils
/
result_store
.
hpp
>
15
16
USERVER_NAMESPACE_BEGIN
17
18
namespace
concurrent
{
19
20
/// @brief lazy value computation with multiple users
21
template
<
typename
T>
22
class
LazyValue final {
23
public
:
24
explicit
LazyValue(std::function<T()> f)
25
: f_(std::move(f))
26
{
27
UASSERT
(f_);
28
}
29
30
/// @brief Get an already calculated result or calculate it.
31
/// It is guaranteed that `f` is called exactly once.
32
/// Can be called concurrently from multiple coroutines.
33
/// @throws anything `f` throws.
34
const
T&
operator
()();
35
36
private
:
37
std::function<T()> f_;
38
std::atomic<
bool
> started_{
false
};
39
utils
::ResultStore<T> result_;
40
41
engine::ConditionVariable cv_finished_;
42
engine::Mutex m_finished_;
43
std::atomic<
bool
> finished_{
false
};
44
};
45
46
template
<
typename
T>
47
const
T& LazyValue<T>::
operator
()() {
48
if
(finished_) {
49
return
result_.Get();
50
}
51
52
auto
old = started_.exchange(
true
);
53
if
(!old) {
54
try
{
55
result_.SetValue(f_());
56
57
const
std::lock_guard lock(m_finished_);
58
finished_ =
true
;
59
cv_finished_
.
NotifyAll
(
)
;
60
}
catch
(...) {
61
result_.SetException(std::current_exception());
62
63
const
std::lock_guard lock(m_finished_);
64
finished_ =
true
;
65
cv_finished_
.
NotifyAll
(
)
;
66
throw
;
67
}
68
}
else
{
69
std::unique_lock lock(m_finished_);
70
auto
rc = cv_finished_.Wait(lock, [
this
]() {
return
finished_.load(); });
71
if
(!rc) {
72
throw
engine::
WaitInterruptedException
(engine
::
current_task
::
CancellationReason
(
)
);
73
}
74
}
75
76
return
result_.Get();
77
}
78
79
}
// namespace concurrent
80
81
USERVER_NAMESPACE_END
userver
concurrent
lazy_value.hpp
Generated on
for userver by
Doxygen
1.17.0