userver
C++ Async Framework
Toggle main menu visibility
Documentation
API Groups
Namespaces
Reference
Class List
Class Index
File List
Macros
All
e
i
l
r
t
u
Functions
Macros
e
i
l
r
t
u
Examples
•
All
Classes
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Friends
Macros
Modules
Pages
Concepts
Loading...
Searching...
No Matches
lazy_shared_ptr.hpp
Go to the documentation of this file.
1
#
pragma
once
2
3
/// @file userver/utils/lazy_shared_ptr.hpp
4
/// @brief @copybrief utils::LazySharedPtr
5
6
#
include
<
atomic
>
7
#
include
<
functional
>
8
#
include
<
memory
>
9
#
include
<
utility
>
10
11
#
include
<
userver
/
engine
/
sleep
.
hpp
>
12
#
include
<
userver
/
utils
/
assert
.
hpp
>
13
#
include
<
userver
/
utils
/
shared_readable_ptr
.
hpp
>
14
15
USERVER_NAMESPACE_BEGIN
16
17
namespace
utils
{
18
19
/// @ingroup userver_containers
20
///
21
/// @brief A lazy wrapper around utils::SharedReadablePtr that fetches the data
22
/// on first access.
23
///
24
/// Provides standard thread-safety guarantee: `const` methods can be called
25
/// concurrently. Once fetched, the same data is guaranteed to be returned
26
/// unless the pointer is assigned to.
27
template
<
typename
T>
28
class
LazySharedPtr final {
29
public
:
30
/// @brief The default constructor, initializes with `nullptr`.
31
LazySharedPtr
()
noexcept
: value_(
nullptr
), shared_filled_(
true
), get_data_() {}
32
33
/// @brief The non-lazy constructor
34
LazySharedPtr
(
utils
::SharedReadablePtr<T> ptr)
noexcept
35
: value_(ptr.Get()), shared_filled_(
true
), shared_(std::move(ptr)) {}
34
LazySharedPtr
(
utils
::SharedReadablePtr<T> ptr)
noexcept
{
…
}
36
37
/// @brief The lazy constructor
38
LazySharedPtr
(std::function<
utils
::SharedReadablePtr<T>()> function)
noexcept
: get_data_(std::move(function)) {}
39
40
/// @brief The copy constructor.
41
/// @note If `other` has not been fetched yet, `this` will not fetch
42
/// immediately, so `this` and `other` may end up pointing to different
43
/// objects.
44
LazySharedPtr
(
const
LazySharedPtr& other) : get_data_(other.get_data_) {
45
if
(other.shared_filled_.load()) {
46
value_.store(other.shared_.Get());
47
shared_ = other.shared_;
48
shared_filled_.store(
true
);
49
}
50
}
44
LazySharedPtr
(
const
LazySharedPtr& other) : get_data_(other.get_data_) {
…
}
51
52
/// @brief The move constructor.
53
LazySharedPtr
(LazySharedPtr&& other)
noexcept
54
: value_(other.value_.load()),
55
shared_filled_(other.shared_filled_.load()),
56
shared_(std::move(other.shared_)),
57
get_data_(std::move(other.get_data_)) {}
53
LazySharedPtr
(LazySharedPtr&& other)
noexcept
{
…
}
58
59
/// @brief The copy assignment operator.
60
/// @note Like copy-constructor, it does not generate pointers if `other` do
61
/// not generate them.
62
LazySharedPtr&
operator
=(
const
LazySharedPtr& other) {
63
*
this
= LazySharedPtr(other);
64
return
*
this
;
65
}
62
LazySharedPtr&
operator
=(
const
LazySharedPtr& other) {
…
}
66
67
/// @brief The move assignment operator.
68
LazySharedPtr&
operator
=(LazySharedPtr&& other)
noexcept
{
69
value_.store(other.value_.load(), std::memory_order_relaxed);
70
shared_filled_.store(other.shared_filled_.load(), std::memory_order_relaxed);
71
shared_ = std::move(other.shared_);
72
get_data_ = std::move(other.get_data_);
73
}
68
LazySharedPtr&
operator
=(LazySharedPtr&& other)
noexcept
{
…
}
74
75
/// @brief Get a pointer to the data (may be null). Fetches the data on the
76
/// first access.
77
const
T*
Get
()
const
& {
78
if
(
const
auto
* current_value = value_.load(); current_value != kUnfilled) {
79
return
current_value;
80
}
81
auto
readable = get_data_();
82
if
(
const
auto
* expected = kUnfilled; value_.compare_exchange_strong(expected, readable.Get())) {
83
shared_ = std::move(readable);
84
shared_filled_.store(
true
);
85
}
86
return
value_;
87
}
77
const
T*
Get
()
const
& {
…
}
88
89
/// @brief Get a smart pointer to the data (may be null). Fetches the data on
90
/// the first access.
91
const
utils
::SharedReadablePtr<T>&
GetShared
()
const
& {
92
if
(value_ == kUnfilled) {
93
auto
readable = get_data_();
94
if
(
const
auto
* expected = kUnfilled; value_.compare_exchange_strong(expected, readable.Get())) {
95
shared_ = std::move(readable);
96
shared_filled_.store(
true
);
97
}
98
}
99
while
(!shared_filled_.load()) {
100
// Another thread has filled 'value_', but not yet 'shared_'. It will be
101
// filled in a few CPU cycles. Discovering LazySharedPtr in such a state
102
// is expected to be rare.
103
engine
::
Yield
(
)
;
104
}
105
return
shared_;
106
}
91
const
utils
::SharedReadablePtr<T>&
GetShared
()
const
& {
…
}
107
108
///@returns `*Get()`
109
///@note `Get()` must not be `nullptr`.
110
const
T&
operator
*()
const
& {
111
const
auto
* res =
Get
(
)
;
112
UASSERT
(res);
113
return
*res;
114
}
110
const
T&
operator
*()
const
& {
…
}
115
116
/// @returns `Get()`
117
/// @note `Get()` must not be `nullptr`.
118
const
T*
operator
->()
const
& {
return
&**
this
; }
119
120
/// @returns `Get() != nullptr`
121
explicit
operator
bool
()
const
& {
return
!!
Get
(
)
; }
122
123
/// @returns `GetShared()`
124
operator
const
utils
::SharedReadablePtr<T>&()
const
& {
return
GetShared
(
)
; }
125
126
/// @returns `GetShared()`
127
operator
std::shared_ptr<
const
T>()
const
& {
return
GetShared
(
)
; }
128
129
private
:
130
static
inline
const
auto
kUnfilled =
reinterpret_cast
<
const
T*>(std::uintptr_t{1});
131
132
mutable
std::atomic<
const
T*> value_{kUnfilled};
133
mutable
std::atomic<
bool
> shared_filled_{
false
};
134
mutable
utils
::SharedReadablePtr<T> shared_{
nullptr
};
135
std::function<
utils
::SharedReadablePtr<T>()> get_data_{};
136
};
28
class
LazySharedPtr final {
…
};
137
138
/// @brief Make a lazy pointer to the data of a cache.
139
///
140
/// The cache type must have:
141
/// - `DataType` member type;
142
/// - `Get() -> utils::SharedReadablePtr<DataType>` method.
143
///
144
/// For example, components::CachingComponentBase satisfies these requirements.
145
template
<
typename
Cache>
146
LazySharedPtr<
typename
Cache::
DataType
>
MakeLazyCachePtr
(Cache& cache) {
147
return
utils
::LazySharedPtr<
typename
Cache::DataType>([&cache] {
return
cache.Get(); });
148
}
146
LazySharedPtr<
typename
Cache::
DataType
>
MakeLazyCachePtr
(Cache& cache) {
…
}
149
150
}
// namespace utils
151
152
USERVER_NAMESPACE_END
userver
utils
lazy_shared_ptr.hpp
Generated on Fri Apr 11 2025 14:21:35 for userver by
Doxygen
1.13.2