userver
C++ Async Framework
Toggle main menu visibility
Loading...
Searching...
No Matches
any_movable.hpp
Go to the documentation of this file.
1
#
pragma
once
2
3
/// @file userver/utils/any_movable.hpp
4
/// @brief @copybrief utils::AnyMovable
5
6
#
include
<
any
>
// for std::bad_any_cast
7
#
include
<
initializer_list
>
8
#
include
<
memory
>
9
#
include
<
type_traits
>
10
#
include
<
utility
>
11
12
#
include
<
userver
/
compiler
/
impl
/
lifetime
.
hpp
>
13
14
USERVER_NAMESPACE_BEGIN
15
16
/// Utilities
17
namespace
utils
{
18
19
/// @ingroup userver_universal userver_containers
20
///
21
/// @brief Replacement for `std::any` that is not copyable. It allows to store
22
/// non-copyable and even non-movable types.
23
///
24
/// Usage example:
25
/// @snippet universal/src/utils/any_movable_test.cpp AnyMovable example usage
26
class
AnyMovable
final
{
27
public
:
28
/// Creates an empty `AnyMovable`
29
constexpr
AnyMovable
()
noexcept
=
default
;
30
31
/// `AnyMovable` is movable, but not copyable
32
AnyMovable
(AnyMovable&&)
noexcept
=
default
;
33
AnyMovable& operator=(AnyMovable&&)
noexcept
=
default
;
34
35
/// Copies or moves the provided object inside the `AnyMovable`. `const`,
36
/// reference, arrays and function pointers are decayed.
37
template
<
typename
ValueType>
38
requires
(!std::is_same_v<AnyMovable, std::decay_t<ValueType>>)
39
/*implicit*/
AnyMovable
(ValueType&& value);
40
41
/// In-place constructs an object of the specified type
42
template
<
typename
ValueType,
typename
... Args>
43
explicit
AnyMovable
(std::in_place_type_t<ValueType> tag, Args&&... args);
44
45
/// In-place constructs an object of the specified type
46
template
<
typename
ValueType,
typename
Item,
typename
... Args>
47
explicit
AnyMovable
(std::in_place_type_t<ValueType> tag, std::initializer_list<Item> list, Args&&... args);
48
49
/// Copies or moves the provided object inside the `AnyMovable`. `const`,
50
/// reference, arrays and function pointers are decayed.
51
template
<
typename
ValueType>
52
AnyMovable&
operator
=(ValueType&& rhs);
53
54
/// Check if the `AnyMovable` is empty
55
bool
HasValue
()
const
noexcept
;
56
57
/// Destroy the old contents, making `*this` empty
58
void
Reset
()
noexcept
;
59
60
/// In-place constructs an object of the specified type
61
template
<
typename
ValueType,
typename
... Args>
62
ValueType&
Emplace
(Args&&... args) USERVER_IMPL_LIFETIME_BOUND;
63
64
/// In-place constructs an object of the specified type
65
template
<
typename
ValueType,
typename
Item,
typename
... Args>
66
ValueType&
Emplace
(std::initializer_list<Item> list, Args&&... args) USERVER_IMPL_LIFETIME_BOUND;
67
68
private
:
69
struct
HolderBase
;
70
71
template
<
typename
ValueType>
72
struct
Holder;
73
74
struct
HolderDeleter {
75
void
operator()(
HolderBase
* holder)
noexcept
;
76
};
77
78
template
<
typename
ValueType>
79
friend
ValueType*
AnyCast
(AnyMovable*)
noexcept
;
80
81
template
<
typename
ValueType>
82
friend
const
ValueType*
AnyCast
(
const
AnyMovable*)
noexcept
;
83
84
std::unique_ptr<
HolderBase
, HolderDeleter> content_;
85
};
86
87
/// @brief The exception that is thrown when `AnyCast` fails
88
class
BadAnyMovableCast
final
:
public
std::bad_any_cast {
89
public
:
90
const
char
* what()
const
noexcept
override
;
91
};
92
93
/// @return nullptr if operand is nullptr or type of the data stored in operand
94
/// does not match ValueType
95
template
<
typename
ValueType>
96
ValueType*
AnyCast
(AnyMovable* operand)
noexcept
;
97
98
/// @return nullptr if operand is nullptr or type of the data stored in operand
99
/// does not match ValueType
100
template
<
typename
ValueType>
101
const
ValueType*
AnyCast
(
const
AnyMovable* operand)
noexcept
;
102
103
/// @note Cast to a reference type to avoid extra copies
104
/// @throw BadAnyMovableCast if type of the data stored in operand
105
/// does not match ValueType
106
template
<
typename
ValueType>
107
ValueType
AnyCast
(AnyMovable& operand);
108
109
/// @note Cast to a reference type to avoid extra copies
110
/// @throw BadAnyMovableCast if type of the data stored in operand
111
/// does not match ValueType
112
template
<
typename
ValueType>
113
ValueType
AnyCast
(
const
AnyMovable& operand);
114
115
/// @note Cast to a reference type to avoid extra moves
116
/// @throw BadAnyMovableCast if type of the data stored in operand
117
/// does not match ValueType
118
template
<
typename
ValueType>
119
ValueType
AnyCast
(AnyMovable&& operand);
120
121
struct
AnyMovable::
HolderBase
{
122
using
DeleterType =
void
(*)(
HolderBase
&)
noexcept
;
123
124
DeleterType deleter;
125
};
126
127
template
<
typename
ValueType>
128
struct
AnyMovable::Holder
final
:
public
HolderBase
{
129
static_assert
(
130
std::is_same_v<ValueType, std::decay_t<ValueType>>,
131
"The requested type can't be stored in an AnyMovable"
132
);
133
134
ValueType held;
135
136
static
void
Deleter(
HolderBase
& holder)
noexcept
{
delete
&
static_cast
<Holder&>(holder); }
137
138
template
<
typename
... Args>
139
static
std::unique_ptr<
HolderBase
, HolderDeleter> Make(Args&&... args) {
140
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
141
return
std::unique_ptr<
HolderBase
, HolderDeleter>{
142
// intended raw ctor call, sometimes casts
143
// NOLINTNEXTLINE(google-readability-casting)
144
new
Holder{{&Deleter}, ValueType(std::forward<Args>(args)...)}
145
};
146
}
147
148
static
ValueType* GetIf(
const
AnyMovable* any)
noexcept
{
149
return
(any && any->content_ && any->content_->deleter == &Deleter)
150
? &
static_cast
<Holder&>(*any->content_).held
151
:
nullptr
;
152
}
153
};
154
155
template
<
typename
ValueType>
156
requires
(!std::is_same_v<AnyMovable, std::decay_t<ValueType>>)
157
AnyMovable::
AnyMovable
(ValueType&& value)
158
: content_(Holder<std::decay_t<ValueType>>::Make(std::forward<ValueType>(value)))
159
{
160
static_assert
(
161
!std::is_same_v<AnyMovable*, std::decay_t<ValueType>> &&
162
!std::is_same_v<
const
AnyMovable*, std::decay_t<ValueType>>,
163
"AnyMovable misuse detected: trying to wrap AnyMovable* in another "
164
"AnyMovable. The pointer was probably meant to be dereferenced."
165
);
166
}
167
168
template
<
typename
ValueType,
typename
... Args>
169
AnyMovable::
AnyMovable
(std::in_place_type_t<ValueType>
/*tag*/
, Args&&... args)
170
: content_(Holder<ValueType>::Make(std::forward<Args>(args)...))
171
{}
172
173
template
<
typename
ValueType,
typename
Item,
typename
... Args>
174
AnyMovable::
AnyMovable
(std::in_place_type_t<ValueType>
/*tag*/
, std::initializer_list<Item> list, Args&&... args)
175
: content_(Holder<ValueType>::Make(list, std::forward<Args>(args)...))
176
{}
177
178
template
<
typename
ValueType>
179
AnyMovable& AnyMovable::
operator
=(ValueType&& rhs) {
180
*
this
= AnyMovable(std::forward<ValueType>(rhs));
181
return
*
this
;
182
}
183
184
template
<
typename
ValueType,
typename
... Args>
185
ValueType&
AnyMovable
::
Emplace
(Args&&... args) USERVER_IMPL_LIFETIME_BOUND {
186
content_ = Holder<ValueType>::Make(std::forward<Args>(args)...);
187
return
static_cast
<Holder<ValueType>&>(*content_).held;
188
}
189
190
template
<
typename
ValueType,
typename
Item,
typename
... Args>
191
ValueType&
AnyMovable
::
Emplace
(std::initializer_list<Item> list, Args&&... args) USERVER_IMPL_LIFETIME_BOUND {
192
content_ = Holder<ValueType>::Make(list, std::forward<Args>(args)...);
193
return
static_cast
<Holder<ValueType>&>(*content_).held;
194
}
195
196
template
<
typename
ValueType>
197
ValueType*
AnyCast
(AnyMovable* operand)
noexcept
{
198
return
AnyMovable::Holder<ValueType>::GetIf(operand);
199
}
200
201
template
<
typename
ValueType>
202
const
ValueType*
AnyCast
(
const
AnyMovable* operand)
noexcept
{
203
return
AnyMovable::Holder<ValueType>::GetIf(operand);
204
}
205
206
template
<
typename
ValueType>
207
// might be requested by user
208
// NOLINTNEXTLINE(readability-const-return-type)
209
ValueType
AnyCast
(AnyMovable& operand) {
210
using
NonRef = std::remove_cv_t<std::remove_reference_t<ValueType>>;
211
auto
* result = AnyCast<NonRef>(&operand);
212
if
(!result) {
213
throw
BadAnyMovableCast();
214
}
215
return
static_cast
<ValueType>(*result);
216
}
217
218
template
<
typename
ValueType>
219
// might be requested by user
220
// NOLINTNEXTLINE(readability-const-return-type)
221
ValueType
AnyCast
(
const
AnyMovable& operand) {
222
using
NonRef = std::remove_cv_t<std::remove_reference_t<ValueType>>;
223
auto
* result = AnyCast<NonRef>(&operand);
224
if
(!result) {
225
throw
BadAnyMovableCast();
226
}
227
return
static_cast
<ValueType>(*result);
228
}
229
230
template
<
typename
ValueType>
231
ValueType
AnyCast
(AnyMovable&& operand) {
232
using
NonRef = std::remove_cv_t<std::remove_reference_t<ValueType>>;
233
auto
* result = AnyCast<NonRef>(&operand);
234
if
(!result) {
235
throw
BadAnyMovableCast();
236
}
237
return
static_cast
<ValueType>(std::move(*result));
238
}
239
240
}
// namespace utils
241
242
USERVER_NAMESPACE_END
userver
utils
any_movable.hpp
Generated on
for userver by
Doxygen
1.17.0