userver
C++ Async Framework
Toggle main menu visibility
Loading...
Searching...
No Matches
resource_scopes.hpp
Go to the documentation of this file.
1
#
pragma
once
2
3
/// @file userver/utils/resource_scopes.hpp
4
/// @brief @copybrief utils::ResourceScopeStorage
5
6
#
include
<
concepts
>
7
#
include
<
memory
>
8
#
include
<
optional
>
9
10
#
include
<
userver
/
compiler
/
impl
/
lifetime
.
hpp
>
11
#
include
<
userver
/
components
/
component_fwd
.
hpp
>
12
#
include
<
userver
/
utils
/
assert
.
hpp
>
13
#
include
<
userver
/
utils
/
move_only_function
.
hpp
>
14
15
USERVER_NAMESPACE_BEGIN
16
17
namespace
utils
{
18
19
namespace
impl {
20
class
ScopeBase {
21
public
:
22
virtual
~ScopeBase() =
default
;
23
24
virtual
void
AfterConstruction() = 0;
25
};
26
27
template
<
typename
Handle>
28
class
Scope
final
:
public
ScopeBase {
29
public
:
30
using
AfterConstructionCallback =
utils
::move_only_function<Handle()>;
31
32
explicit
Scope(AfterConstructionCallback after_construction)
33
: after_construction_(std::move(after_construction))
34
{}
35
36
void
AfterConstruction()
override
{ before_destruction_.emplace(after_construction_()); }
37
38
private
:
39
AfterConstructionCallback after_construction_;
40
std::optional<Handle> before_destruction_;
41
};
42
43
template
<>
44
class
Scope<
void
>
final
:
public
ScopeBase {
45
public
:
46
using
AfterConstructionCallback =
utils
::move_only_function<
void
()>;
47
48
explicit
Scope(AfterConstructionCallback after_construction)
49
: after_construction_(std::move(after_construction))
50
{}
51
52
void
AfterConstruction()
override
{ after_construction_(); }
53
54
private
:
55
AfterConstructionCallback after_construction_;
56
};
57
58
/// @brief An object of ScopePtr defines actions to do after
59
/// a component is constructed and just before it is destroyed.
60
///
61
/// @see @ref components::ComponentContext::Scopes
62
using
ScopePtr = std::unique_ptr<impl::ScopeBase>;
63
64
}
// namespace impl
65
66
/// @brief Defers subscription and callback registration until the object is fully constructed.
67
///
68
/// Components often register external subscriptions (statistics writers, config listeners,
69
/// and similar) that capture `this` and run later on another thread. Registering them
70
/// directly in the constructor is unsafe: the callback may fire before the constructor
71
/// finishes and observe partially initialized fields. Unregistering in the destructor
72
/// is equally unsafe if the callback can still run while members are already being
73
/// destroyed.
74
///
75
/// During construction, call @ref Register to queue a functor that performs the actual
76
/// registration. The component system calls @ref AfterConstruction when the constructor
77
/// (including derived classes) has completed, and @ref BeforeDestruction before the
78
/// destructor body runs. That way registration callbacks see a fully built object, and
79
/// unregistration runs before members used by the callback are torn down.
80
///
81
/// The same storage is available from @ref components::ComponentContext::Scopes in
82
/// components, or as a standalone helper in unit tests and @ref WithResourceScopes.
83
///
84
/// @snippet core/src/components/resource_scopes_test.cpp ResourceScopeStorage - HappyPathOrder
85
class
ResourceScopeStorage
final
{
86
public
:
87
ResourceScopeStorage() =
default
;
88
89
ResourceScopeStorage(ResourceScopeStorage&& other)
noexcept
=
default
;
90
ResourceScopeStorage& operator=(ResourceScopeStorage&& other)
noexcept
=
default
;
91
92
/// @brief Registers a functor to register some resource that will be
93
/// called after the component is successfully created (including all
94
/// class descendants) or after the component creation is emulated in
95
/// unit tests. The functor must return a RAII-style handle object
96
/// that unregisters the previously registered resource. The returned handle's
97
/// destructor is called just before the component destructor is called.
98
///
99
/// @note callback is not called if the component is not created OR
100
/// any previously registered callback throws an exception.
101
/// @note if you don't have an existing RAII-ish class, but still want
102
/// to do a cleanup, you might want to use @ref utils::FastScopeGuard
103
/// to wrap the cleanup function.
104
template
<
std
::invocable<> AfterConstructionCallback>
105
void
Register
(AfterConstructionCallback after_construction)
106
{
107
using
Handle = std::invoke_result_t<AfterConstructionCallback>;
108
auto
scope = std::make_unique<impl::Scope<Handle>>(std::move(after_construction));
109
DoRegister(std::move(scope));
110
}
111
112
/// @brief Call all registered functors.
113
void
AfterConstruction
();
114
115
/// @brief Unregister all previously registered resources.
116
void
BeforeDestruction
();
117
118
private
:
119
void
DoRegister(impl::ScopePtr resource_scope);
120
121
std::vector<impl::ScopePtr> registered_scopes_;
122
std::vector<impl::ScopePtr> initialized_scopes_;
123
bool
scope_registration_finished_{
false
};
124
};
125
126
/// @brief A wrapper that provides @ref utils::ResourceScopeStorage for the wrapped object.
127
///
128
/// The wrapped object is passed `utils::ResourceScopeStorage&` as the first argument to the constructor.
129
template
<
typename
Wrapped>
130
class
WithResourceScopes
final
{
131
public
:
132
/// @brief Constructs the wrapped object and passes the embedded @ref utils::ResourceScopeStorage to it
133
/// as the first argument.
134
template
<
typename
... Args>
135
explicit
WithResourceScopes
(std::in_place_t, Args&&... args)
136
: wrapped_(resource_scope_storage_, std::forward<Args>(args)...)
137
{
138
resource_scope_storage_
.
AfterConstruction
(
)
;
139
}
140
141
WithResourceScopes(WithResourceScopes&& other)
noexcept
=
default
;
142
WithResourceScopes& operator=(WithResourceScopes&& other)
noexcept
=
default
;
143
144
~WithResourceScopes() { resource_scope_storage_
.
BeforeDestruction
(
)
; }
145
146
/// @brief Returns the wrapped object.
147
Wrapped&
operator
*() &
noexcept
USERVER_IMPL_LIFETIME_BOUND {
return
wrapped_; }
148
/// @overload
149
const
Wrapped&
operator
*()
const
&
noexcept
USERVER_IMPL_LIFETIME_BOUND {
return
wrapped_; }
150
151
/// @brief Returns the wrapped object.
152
Wrapped*
operator
->()
noexcept
USERVER_IMPL_LIFETIME_BOUND {
return
&wrapped_; }
153
/// @overload
154
const
Wrapped*
operator
->()
const
noexcept
USERVER_IMPL_LIFETIME_BOUND {
return
&wrapped_; }
155
156
private
:
157
ResourceScopeStorage resource_scope_storage_;
158
Wrapped wrapped_;
159
};
160
161
ResourceScopeStorage&
162
LocateDependency(
components
::
WithType
<ResourceScopeStorage>,
const
components
::ComponentConfig& config,
const
components
::ComponentContext&);
163
164
}
// namespace utils
165
166
USERVER_NAMESPACE_END
userver
utils
resource_scopes.hpp
Generated on
for userver by
Doxygen
1.17.0