GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
#ifndef ZSERIO_OPTIONAL_HOLDER_H_INC |
||
2 |
#define ZSERIO_OPTIONAL_HOLDER_H_INC |
||
3 |
|||
4 |
#include <cstddef> |
||
5 |
#include <type_traits> |
||
6 |
|||
7 |
#include "zserio/CppRuntimeException.h" |
||
8 |
#include "zserio/NoInit.h" |
||
9 |
#include "zserio/Types.h" |
||
10 |
#include "zserio/UniquePtr.h" |
||
11 |
|||
12 |
namespace zserio |
||
13 |
{ |
||
14 |
|||
15 |
/** |
||
16 |
* Helper type for specification of an unset optional holder. |
||
17 |
*/ |
||
18 |
struct NullOptType |
||
19 |
{ |
||
20 |
/** |
||
21 |
* Explicit constructor from int. |
||
22 |
* |
||
23 |
* \see https://en.cppreference.com/w/cpp/utility/optional/nullopt_t |
||
24 |
*/ |
||
25 |
constexpr explicit NullOptType(int) {} |
||
26 |
}; |
||
27 |
|||
28 |
/** |
||
29 |
* Constant used to convenient specification of an unset optional holder. |
||
30 |
*/ |
||
31 |
constexpr NullOptType NullOpt{int()}; |
||
32 |
|||
33 |
/** |
||
34 |
* Helper type for specification of in-place construction. |
||
35 |
*/ |
||
36 |
struct InPlaceT |
||
37 |
{ |
||
38 |
constexpr explicit InPlaceT() = default; |
||
39 |
}; |
||
40 |
|||
41 |
/** |
||
42 |
* Constant used as a marker for in-place construction. |
||
43 |
*/ |
||
44 |
constexpr InPlaceT InPlace{}; |
||
45 |
|||
46 |
namespace detail |
||
47 |
{ |
||
48 |
|||
49 |
/** |
||
50 |
* Base class for optional holders. Provides common interface for various types of optional holders. |
||
51 |
*/ |
||
52 |
template <typename T, typename Derived> |
||
53 |
66980 |
class optional_holder_base |
|
54 |
{ |
||
55 |
public: |
||
56 |
/** |
||
57 |
* Operator equality. |
||
58 |
* |
||
59 |
* \param other Other holder to compare. |
||
60 |
* |
||
61 |
* \return True when the other holder has same value as this. False otherwise. |
||
62 |
*/ |
||
63 |
31 |
bool operator==(const optional_holder_base& other) const |
|
64 |
{ |
||
65 |
✗✓✓✓ ✓✓✗✗ |
31 |
if (this == &other) |
66 |
5 |
return true; |
|
67 |
|||
68 |
✗✓✓✓ ✓✓✗✗ |
26 |
if (getDerived()->hasValue() != other.getDerived()->hasValue()) |
69 |
5 |
return false; |
|
70 |
|||
71 |
✓✓✓✓ ✓✓✗✗ |
21 |
if (getDerived()->hasValue()) |
72 |
14 |
return get() == other.get(); |
|
73 |
|||
74 |
7 |
return true; |
|
75 |
} |
||
76 |
|||
77 |
/** |
||
78 |
* Operator less than. |
||
79 |
* |
||
80 |
* \param other Other holder to compare. |
||
81 |
* |
||
82 |
* \return True when the other holder has less value than this. False otherwise. |
||
83 |
*/ |
||
84 |
10 |
bool operator<(const optional_holder_base& other) const |
|
85 |
{ |
||
86 |
✓✓✓✓ ✓✓✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ |
10 |
if (getDerived()->hasValue() && other.getDerived()->hasValue()) |
87 |
4 |
return get() < other.get(); |
|
88 |
|||
89 |
✓✓✓✓ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ |
6 |
return !getDerived()->hasValue() && other.getDerived()->hasValue(); |
90 |
} |
||
91 |
|||
92 |
/** |
||
93 |
* Bool operator. |
||
94 |
* |
||
95 |
* Evaluates to true when this holder has assigned any value. |
||
96 |
*/ |
||
97 |
501 |
explicit operator bool() const noexcept |
|
98 |
{ |
||
99 |
501 |
return getDerived()->hasValue(); |
|
100 |
} |
||
101 |
|||
102 |
/** |
||
103 |
* Dereference operator ->. |
||
104 |
* |
||
105 |
* \return Const reference to the assigned value. |
||
106 |
* |
||
107 |
* \throw CppRuntimeException when the holder is unset. |
||
108 |
*/ |
||
109 |
4 |
const T* operator->() const |
|
110 |
{ |
||
111 |
4 |
return std::addressof(get()); |
|
112 |
} |
||
113 |
|||
114 |
/** |
||
115 |
* Dereference operator ->. |
||
116 |
* |
||
117 |
* \return Reference to the assigned value. |
||
118 |
* |
||
119 |
* \throw CppRuntimeException when the holder is unset. |
||
120 |
*/ |
||
121 |
426 |
T* operator->() |
|
122 |
{ |
||
123 |
426 |
return std::addressof(get()); |
|
124 |
} |
||
125 |
|||
126 |
/** |
||
127 |
* Gets held value. |
||
128 |
* |
||
129 |
* \return Const reference to the assigned value. |
||
130 |
* |
||
131 |
* \throw CppRuntimeException when the holder is unset. |
||
132 |
*/ |
||
133 |
48713 |
const T& value() const |
|
134 |
{ |
||
135 |
48713 |
return get(); |
|
136 |
} |
||
137 |
|||
138 |
/** |
||
139 |
* Gets held value. |
||
140 |
* |
||
141 |
* \return Reference to the assigned value. |
||
142 |
* |
||
143 |
* \throw CppRuntimeException when the holder is unset. |
||
144 |
*/ |
||
145 |
859 |
T& value() |
|
146 |
{ |
||
147 |
859 |
return get(); |
|
148 |
} |
||
149 |
|||
150 |
protected: |
||
151 |
50156 |
void checkHasValue() const |
|
152 |
{ |
||
153 |
✓✓✓✓ ✗✓✓✓ ✓✓✗✓ ✓✓✓✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✓ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✓✗✗ ✗✗✗✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✓ |
50156 |
if (!getDerived()->hasValue()) |
154 |
14 |
throwNonPresentException(); |
|
155 |
50142 |
} |
|
156 |
|||
157 |
private: |
||
158 |
1285 |
T& get() |
|
159 |
{ |
||
160 |
1285 |
return getDerived()->operator*(); |
|
161 |
} |
||
162 |
|||
163 |
48753 |
const T& get() const |
|
164 |
{ |
||
165 |
48753 |
return getDerived()->operator*(); |
|
166 |
} |
||
167 |
|||
168 |
1285 |
Derived* getDerived() |
|
169 |
{ |
||
170 |
1285 |
return static_cast<Derived*>(this); |
|
171 |
} |
||
172 |
|||
173 |
99509 |
const Derived* getDerived() const |
|
174 |
{ |
||
175 |
99509 |
return static_cast<const Derived*>(this); |
|
176 |
} |
||
177 |
|||
178 |
/** Optimization which increases chances to inline checkHasValue(). */ |
||
179 |
14 |
void throwNonPresentException() const |
|
180 |
{ |
||
181 |
✓✗✓✗ ✗✗✓✗ ✓✗✗✗ ✓✗✓✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ |
14 |
throw CppRuntimeException("Trying to access value of non-present optional field!"); |
182 |
} |
||
183 |
}; |
||
184 |
|||
185 |
/** |
||
186 |
* Optional holder implementation that stores the object on heap. |
||
187 |
*/ |
||
188 |
template <typename T, typename ALLOC> |
||
189 |
class heap_optional_holder : public optional_holder_base<T, heap_optional_holder<T, ALLOC>> |
||
190 |
{ |
||
191 |
public: |
||
192 |
using allocator_type = ALLOC; |
||
193 |
using allocator_traits = std::allocator_traits<allocator_type>; |
||
194 |
using value_type = T; |
||
195 |
using storage_type = zserio::unique_ptr<T, allocator_type>; |
||
196 |
|||
197 |
/** |
||
198 |
* Getter for the allocator. |
||
199 |
* |
||
200 |
* \return Allocator that is used for the dynamic memory allocat |
||
201 |
*/ |
||
202 |
98 |
allocator_type get_allocator() const |
|
203 |
{ |
||
204 |
98 |
return m_storage.get_deleter().get_allocator(); |
|
205 |
} |
||
206 |
|||
207 |
/** |
||
208 |
* Empty constructor which creates an unset holder. |
||
209 |
* |
||
210 |
* \param allocator Allocator to be used to perform dynamic memory allocations. |
||
211 |
*/ |
||
212 |
45 |
explicit constexpr heap_optional_holder(const allocator_type& allocator = allocator_type()) noexcept : |
|
213 |
45 |
m_storage(nullptr, allocator) |
|
214 |
45 |
{} |
|
215 |
|||
216 |
/** |
||
217 |
* Constructor from zserio::NullOpt constant to create an unset holder. |
||
218 |
* |
||
219 |
* \param allocator Allocator to be used to perform dynamic memory allocations. |
||
220 |
*/ |
||
221 |
2 |
constexpr heap_optional_holder(NullOptType, |
|
222 |
2 |
const allocator_type& allocator = allocator_type()) noexcept : m_storage(nullptr, allocator) |
|
223 |
2 |
{} |
|
224 |
|||
225 |
/** |
||
226 |
* Constructor from a given value. |
||
227 |
* |
||
228 |
* \param value Value to store in the holder. |
||
229 |
* \param allocator Allocator to be used to perform dynamic memory allocations. |
||
230 |
*/ |
||
231 |
2 |
heap_optional_holder(const T& value, const allocator_type& allocator = allocator_type()) : |
|
232 |
2 |
m_storage(zserio::allocate_unique<T, allocator_type>(allocator, value)) |
|
233 |
2 |
{} |
|
234 |
|||
235 |
/** |
||
236 |
* Constructor from a given value passed by rvalue reference. |
||
237 |
* |
||
238 |
* \param value Value to store in the holder. |
||
239 |
* \param allocator Allocator to be used to perform dynamic memory allocations. |
||
240 |
*/ |
||
241 |
27 |
heap_optional_holder(T&& value, const allocator_type& allocator = allocator_type()) : |
|
242 |
27 |
m_storage(zserio::allocate_unique<T, allocator_type>(allocator, std::move(value))) |
|
243 |
27 |
{} |
|
244 |
|||
245 |
// called from allocatorPropagatingCopy |
||
246 |
/** |
||
247 |
* Constructor from a given value passed by rvalue reference which prevents initialization. |
||
248 |
* |
||
249 |
* \param value Value to store in the holder. |
||
250 |
* \param allocator Allocator to be used to perform dynamic memory allocations. |
||
251 |
*/ |
||
252 |
template <typename U = T, |
||
253 |
typename std::enable_if<std::is_constructible<U, NoInitT, U>::value, int>::type = 0> |
||
254 |
2 |
heap_optional_holder(NoInitT, T&& value, const allocator_type& allocator = allocator_type()) : |
|
255 |
2 |
m_storage(zserio::allocate_unique<T, allocator_type>(allocator, NoInit, std::move(value))) |
|
256 |
2 |
{} |
|
257 |
|||
258 |
/** |
||
259 |
* Constructor that initializes the value inplace by forwarding the arguments to the object's constructor. |
||
260 |
* |
||
261 |
* \param allocator Allocator to be used for dynamic memory allocations. |
||
262 |
* \param u Parameters for object's constructor. |
||
263 |
*/ |
||
264 |
template <typename ...U> |
||
265 |
2 |
explicit heap_optional_holder(const allocator_type& allocator, U&& ...u) : |
|
266 |
2 |
m_storage(zserio::allocate_unique<T, allocator_type>(allocator, std::forward<U>(u)...)) |
|
267 |
2 |
{} |
|
268 |
|||
269 |
/** |
||
270 |
* Destructor. |
||
271 |
*/ |
||
272 |
98 |
~heap_optional_holder() = default; |
|
273 |
|||
274 |
/** |
||
275 |
* Copy constructor. |
||
276 |
* |
||
277 |
* \param other Other holder to copy. |
||
278 |
*/ |
||
279 |
6 |
heap_optional_holder(const heap_optional_holder& other) : |
|
280 |
m_storage(copy_initialize(other, allocator_traits::select_on_container_copy_construction( |
||
281 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗ |
6 |
other.get_allocator()))) |
282 |
6 |
{} |
|
283 |
|||
284 |
/** |
||
285 |
* Copy constructor which prevents initialization. |
||
286 |
* |
||
287 |
* \param other Other holder to copy. |
||
288 |
*/ |
||
289 |
template <typename U = T, |
||
290 |
typename std::enable_if<std::is_constructible<U, NoInitT, U>::value, int>::type = 0> |
||
291 |
2 |
heap_optional_holder(NoInitT, const heap_optional_holder& other) : |
|
292 |
m_storage(copy_initialize(NoInit, other, |
||
293 |
allocator_traits::select_on_container_copy_construction( |
||
294 |
✓✗✓✗ |
2 |
other.get_allocator()))) |
295 |
2 |
{} |
|
296 |
|||
297 |
/** |
||
298 |
* Allocator-extended copy constructor. |
||
299 |
* |
||
300 |
* \param other Other holder to copy. |
||
301 |
* \param allocator Allocator to be used for dynamic memory allocations. |
||
302 |
*/ |
||
303 |
2 |
heap_optional_holder(const heap_optional_holder& other, const allocator_type& allocator) : |
|
304 |
2 |
m_storage(copy_initialize(other, allocator)) |
|
305 |
2 |
{} |
|
306 |
|||
307 |
/** |
||
308 |
* Move constructor. |
||
309 |
* |
||
310 |
* \param other Other holder to move. |
||
311 |
*/ |
||
312 |
1 |
heap_optional_holder(heap_optional_holder&& other) noexcept = default; |
|
313 |
|||
314 |
/** |
||
315 |
* Move constructor which prevents initialization. |
||
316 |
* |
||
317 |
* \param other Other holder to move. |
||
318 |
*/ |
||
319 |
template <typename U = T, |
||
320 |
typename std::enable_if<std::is_constructible<U, NoInitT, U>::value, int>::type = 0> |
||
321 |
4 |
heap_optional_holder(NoInitT, heap_optional_holder&& other) : |
|
322 |
✓✗ | 4 |
m_storage(move_initialize(NoInit, std::move(other), other.get_allocator())) |
323 |
{ |
||
324 |
4 |
} |
|
325 |
|||
326 |
/** |
||
327 |
* Allocator-extended move constructor. |
||
328 |
* |
||
329 |
* \param other Other holder to move. |
||
330 |
* \param allocator Allocator to be used for dynamic memory allocations. |
||
331 |
*/ |
||
332 |
3 |
heap_optional_holder(heap_optional_holder&& other, const allocator_type& allocator) : |
|
333 |
3 |
m_storage(move_initialize(std::move(other), allocator)) |
|
334 |
{ |
||
335 |
3 |
} |
|
336 |
|||
337 |
/** |
||
338 |
* Assignment operator. |
||
339 |
* |
||
340 |
* \param other Other holder to copy-assign. |
||
341 |
* |
||
342 |
* \return Reference to the current holder. |
||
343 |
*/ |
||
344 |
5 |
heap_optional_holder& operator=(const heap_optional_holder& other) |
|
345 |
{ |
||
346 |
✓✗✗✓ ✗✓✓✓ |
5 |
if (this == &other) |
347 |
2 |
return *this; |
|
348 |
|||
349 |
✗✗✗✗ ✗✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ |
3 |
m_storage = copy_initialize(other, select_allocator(other.get_allocator(), |
350 |
typename allocator_traits::propagate_on_container_copy_assignment())); |
||
351 |
|||
352 |
3 |
return *this; |
|
353 |
} |
||
354 |
|||
355 |
/** |
||
356 |
* Assignment operator which prevents initialization. |
||
357 |
* |
||
358 |
* \param other Other holder to copy-assign. |
||
359 |
* |
||
360 |
* \return Reference to the current holder. |
||
361 |
*/ |
||
362 |
template <typename U = T, |
||
363 |
typename std::enable_if<std::is_constructible<U, NoInitT, U>::value, int>::type = 0> |
||
364 |
3 |
heap_optional_holder& assign(NoInitT, const heap_optional_holder& other) |
|
365 |
{ |
||
366 |
✓✓ | 3 |
if (this == &other) |
367 |
1 |
return *this; |
|
368 |
|||
369 |
✓✗✓✗ |
2 |
m_storage = copy_initialize(NoInit, other, select_allocator(other.get_allocator(), |
370 |
typename allocator_traits::propagate_on_container_copy_assignment())); |
||
371 |
|||
372 |
2 |
return *this; |
|
373 |
} |
||
374 |
|||
375 |
/** |
||
376 |
* Move assignment operator. |
||
377 |
* |
||
378 |
* \param other Other holder to move-assign. |
||
379 |
* |
||
380 |
* \return Reference to the current holder. |
||
381 |
*/ |
||
382 |
4 |
heap_optional_holder& operator=(heap_optional_holder&& other) |
|
383 |
{ |
||
384 |
✓✗✗✓ ✓✓ |
4 |
if (this == &other) |
385 |
2 |
return *this; |
|
386 |
|||
387 |
✗✗✗✗ ✓✗✓✗ ✓✗✓✗ ✓✗ |
2 |
m_storage = move_initialize(std::move(other), select_allocator(other.get_allocator(), |
388 |
typename allocator_traits::propagate_on_container_move_assignment())); |
||
389 |
|||
390 |
2 |
return *this; |
|
391 |
} |
||
392 |
|||
393 |
/** |
||
394 |
* Move assignment operator which prevents initialization. |
||
395 |
* |
||
396 |
* \param other Other holder to move-assign. |
||
397 |
* |
||
398 |
* \return Reference to the current holder. |
||
399 |
*/ |
||
400 |
template <typename U = T, |
||
401 |
typename std::enable_if<std::is_constructible<U, NoInitT, U>::value, int>::type = 0> |
||
402 |
5 |
heap_optional_holder& assign(NoInitT, heap_optional_holder&& other) |
|
403 |
{ |
||
404 |
✓✓✓✓ |
5 |
if (this == &other) |
405 |
2 |
return *this; |
|
406 |
|||
407 |
✓✗✓✗ ✓✗✓✗ ✓✗ |
3 |
m_storage = move_initialize(NoInit, std::move(other), |
408 |
select_allocator(other.get_allocator(), |
||
409 |
typename allocator_traits::propagate_on_container_move_assignment())); |
||
410 |
|||
411 |
3 |
return *this; |
|
412 |
} |
||
413 |
|||
414 |
/** |
||
415 |
* Assignment operator from value. |
||
416 |
* |
||
417 |
* \param value Value to assign. |
||
418 |
* |
||
419 |
* \return Reference to the current holder. |
||
420 |
*/ |
||
421 |
8 |
heap_optional_holder& operator=(const T& value) |
|
422 |
{ |
||
423 |
8 |
set(value); |
|
424 |
|||
425 |
8 |
return *this; |
|
426 |
} |
||
427 |
|||
428 |
/** |
||
429 |
* Assignment operator from rvalue reference to value. |
||
430 |
* |
||
431 |
* \param value Value to move-assign. |
||
432 |
* |
||
433 |
* \return Reference to the current holder. |
||
434 |
*/ |
||
435 |
7 |
heap_optional_holder& operator=(T&& value) |
|
436 |
{ |
||
437 |
7 |
set(std::move(value)); |
|
438 |
|||
439 |
7 |
return *this; |
|
440 |
} |
||
441 |
|||
442 |
/** |
||
443 |
* Resets the current holder (switch to the unset state). |
||
444 |
*/ |
||
445 |
17 |
void reset() noexcept |
|
446 |
{ |
||
447 |
17 |
m_storage.reset(); |
|
448 |
17 |
} |
|
449 |
|||
450 |
/** |
||
451 |
* Gets whether the holder has any value. |
||
452 |
* |
||
453 |
* \return True when this holder has assigned any value. False otherwise. |
||
454 |
*/ |
||
455 |
208 |
bool hasValue() const noexcept |
|
456 |
{ |
||
457 |
208 |
return static_cast<bool>(m_storage); |
|
458 |
} |
||
459 |
|||
460 |
/** |
||
461 |
* Dereference operator *. |
||
462 |
* |
||
463 |
* \return Const reference to the assigned value. |
||
464 |
* |
||
465 |
* \throw CppRuntimeException when the holder is unset. |
||
466 |
*/ |
||
467 |
34 |
const T& operator*() const |
|
468 |
{ |
||
469 |
34 |
this->checkHasValue(); |
|
470 |
34 |
return *m_storage.get(); |
|
471 |
} |
||
472 |
|||
473 |
/** |
||
474 |
* Dereference operator *. |
||
475 |
* |
||
476 |
* \return Reference to the assigned value. |
||
477 |
* |
||
478 |
* \throw CppRuntimeException when the holder is unset. |
||
479 |
*/ |
||
480 |
76 |
T& operator*() |
|
481 |
{ |
||
482 |
76 |
this->checkHasValue(); |
|
483 |
68 |
return *m_storage.get(); |
|
484 |
} |
||
485 |
|||
486 |
private: |
||
487 |
7 |
allocator_type select_allocator(allocator_type other_allocator, std::true_type) |
|
488 |
{ |
||
489 |
7 |
return other_allocator; |
|
490 |
} |
||
491 |
|||
492 |
3 |
allocator_type select_allocator(allocator_type, std::false_type) |
|
493 |
{ |
||
494 |
3 |
return get_allocator(); // current allocator |
|
495 |
} |
||
496 |
|||
497 |
template <typename U = T> |
||
498 |
15 |
void set(U&& value) |
|
499 |
{ |
||
500 |
15 |
reset(); |
|
501 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗ |
15 |
m_storage = zserio::allocate_unique<T, allocator_type>(get_allocator(), std::forward<U>(value)); |
502 |
15 |
} |
|
503 |
|||
504 |
11 |
static storage_type copy_initialize(const heap_optional_holder& other, const allocator_type& allocator) |
|
505 |
{ |
||
506 |
✓✗✓✓ ✓✗✓✗ ✓✓ |
11 |
if (other.hasValue()) |
507 |
9 |
return zserio::allocate_unique<T, allocator_type>(allocator, *other); |
|
508 |
else |
||
509 |
2 |
return storage_type(nullptr, allocator); |
|
510 |
} |
||
511 |
|||
512 |
4 |
static storage_type copy_initialize(NoInitT, const heap_optional_holder& other, |
|
513 |
const allocator_type& allocator) |
||
514 |
{ |
||
515 |
✓✓ | 4 |
if (other.hasValue()) |
516 |
2 |
return zserio::allocate_unique<T, allocator_type>(allocator, NoInit, *other); |
|
517 |
else |
||
518 |
2 |
return storage_type(nullptr, allocator); |
|
519 |
} |
||
520 |
|||
521 |
5 |
static storage_type move_initialize(heap_optional_holder&& other, const allocator_type& allocator) |
|
522 |
{ |
||
523 |
✗✗✓✗ ✓✗✓✓ |
5 |
if (other.hasValue()) |
524 |
{ |
||
525 |
✗✗✗✓ ✓✗✓✓ |
4 |
if (allocator == other.get_allocator()) |
526 |
2 |
return std::move(other.m_storage); |
|
527 |
|||
528 |
2 |
return zserio::allocate_unique<T, allocator_type>(allocator, std::move(*other)); |
|
529 |
} |
||
530 |
else |
||
531 |
{ |
||
532 |
1 |
return storage_type(nullptr, allocator); |
|
533 |
} |
||
534 |
} |
||
535 |
|||
536 |
7 |
static storage_type move_initialize(NoInitT, heap_optional_holder&& other, |
|
537 |
const allocator_type& allocator) |
||
538 |
{ |
||
539 |
✓✓✓✓ |
7 |
if (other.hasValue()) |
540 |
{ |
||
541 |
✓✓✓✗ |
4 |
if (allocator == other.get_allocator()) |
542 |
3 |
return std::move(other.m_storage); |
|
543 |
|||
544 |
return zserio::allocate_unique<T, allocator_type>(allocator, NoInit, |
||
545 |
1 |
std::move(*other)); |
|
546 |
} |
||
547 |
else |
||
548 |
{ |
||
549 |
3 |
return storage_type(nullptr, allocator); |
|
550 |
} |
||
551 |
} |
||
552 |
|||
553 |
storage_type m_storage; |
||
554 |
}; |
||
555 |
|||
556 |
/** |
||
557 |
* In place storage for optional holder. |
||
558 |
*/ |
||
559 |
template <typename T> |
||
560 |
class in_place_storage |
||
561 |
{ |
||
562 |
public: |
||
563 |
/** |
||
564 |
* Constructor. |
||
565 |
*/ |
||
566 |
66883 |
in_place_storage() = default; |
|
567 |
|||
568 |
/** |
||
569 |
* Destructor. |
||
570 |
*/ |
||
571 |
~in_place_storage() = default; |
||
572 |
|||
573 |
/** Copying is disabled. */ |
||
574 |
/** \{ */ |
||
575 |
in_place_storage(const in_place_storage&) = delete; |
||
576 |
in_place_storage& operator=(const in_place_storage&) = delete; |
||
577 |
/** \} */ |
||
578 |
|||
579 |
/** Move constructor is disabled. */ |
||
580 |
in_place_storage(in_place_storage&& other) = delete; |
||
581 |
|||
582 |
/** |
||
583 |
* Move assignment operator. |
||
584 |
* |
||
585 |
* \param other Other storage to move. |
||
586 |
* |
||
587 |
* \return Reference to the current storage. |
||
588 |
*/ |
||
589 |
16313 |
in_place_storage& operator=(in_place_storage&& other) |
|
590 |
{ |
||
591 |
✓✗✗✗ ✓✗✗✗ ✓✗✗✗ ✗✓✗✗ ✗✗✓✗ ✗✗✗✓ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✓✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✓ ✓✗✗✗ ✗✗✗✗ ✓✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✓✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗ |
16313 |
new (&m_inPlace) T(std::move(*other.getObject())); |
592 |
16313 |
other.getObject()->~T(); // ensure that destructor of object in original storage is called |
|
593 |
|||
594 |
16313 |
return *this; |
|
595 |
} |
||
596 |
|||
597 |
/** |
||
598 |
* Move assignment operator which prevents initialization. |
||
599 |
* |
||
600 |
* \param other Other storage to move. |
||
601 |
* |
||
602 |
* \return Reference to the current storage. |
||
603 |
*/ |
||
604 |
10 |
in_place_storage& assign(NoInitT, in_place_storage&& other) |
|
605 |
{ |
||
606 |
✓✗✗✗ |
10 |
new (&m_inPlace) T(NoInit, std::move(*other.getObject())); |
607 |
10 |
other.getObject()->~T(); // ensure that destructor of object in original storage is called |
|
608 |
|||
609 |
10 |
return *this; |
|
610 |
} |
||
611 |
|||
612 |
/** |
||
613 |
* Gets pointer to the underlying in-place memory. |
||
614 |
* |
||
615 |
* \return Pointer to the storage. |
||
616 |
*/ |
||
617 |
50425 |
void* getStorage() |
|
618 |
{ |
||
619 |
50425 |
return &m_inPlace; |
|
620 |
} |
||
621 |
|||
622 |
/** |
||
623 |
* Gets pointer to the stored object. |
||
624 |
* |
||
625 |
* \return Pointer to the object. |
||
626 |
*/ |
||
627 |
84370 |
T* getObject() |
|
628 |
{ |
||
629 |
84370 |
return reinterpret_cast<T*>(&m_inPlace); |
|
630 |
} |
||
631 |
|||
632 |
/** |
||
633 |
* Gets pointer to the stored object. |
||
634 |
* |
||
635 |
* \return Const pointer to the object. |
||
636 |
*/ |
||
637 |
48852 |
const T* getObject() const |
|
638 |
{ |
||
639 |
48852 |
return reinterpret_cast<const T*>(&m_inPlace); |
|
640 |
} |
||
641 |
|||
642 |
private: |
||
643 |
// Caution! |
||
644 |
// We use static constants as a WORKAROUND for a GCC 8/9 bug observed when cross-compiling with -m32 flag. |
||
645 |
// The compilers somehow spoils the aligned storage when alignof(T) is used directly as the template |
||
646 |
// argument which leads to "*** stack smashing detected ***" error (as observed in some language tests). |
||
647 |
static constexpr size_t SIZEOF_T = sizeof(T); |
||
648 |
static constexpr size_t ALIGNOF_T = alignof(T); |
||
649 |
using AlignedStorage = typename std::aligned_storage<SIZEOF_T, ALIGNOF_T>::type; |
||
650 |
AlignedStorage m_inPlace; |
||
651 |
}; |
||
652 |
|||
653 |
/** |
||
654 |
* Optional holder implementation for Zserio which allows usage of in place storage. |
||
655 |
*/ |
||
656 |
template <typename T> |
||
657 |
class inplace_optional_holder : public optional_holder_base<T, inplace_optional_holder<T>> |
||
658 |
{ |
||
659 |
public: |
||
660 |
using value_type = T; |
||
661 |
|||
662 |
/** |
||
663 |
* Empty constructor which creates an unset holder. |
||
664 |
*/ |
||
665 |
66421 |
constexpr inplace_optional_holder() noexcept = default; |
|
666 |
|||
667 |
/** |
||
668 |
* Constructor from zserio::NullOpt constant to create an unset holder. |
||
669 |
*/ |
||
670 |
293 |
constexpr inplace_optional_holder(NullOptType) noexcept |
|
671 |
293 |
{} |
|
672 |
|||
673 |
/** |
||
674 |
* Constructor from a given value. |
||
675 |
* |
||
676 |
* \param value Value to store in the holder. |
||
677 |
*/ |
||
678 |
42 |
inplace_optional_holder(const T& value) |
|
679 |
42 |
{ |
|
680 |
✓✗✓✓ ✗✓✓✗ ✓✗ |
42 |
new (m_storage.getStorage()) T(value); |
681 |
42 |
m_hasValue = true; |
|
682 |
42 |
} |
|
683 |
|||
684 |
/** |
||
685 |
* Constructor from a given value passed by rvalue reference. |
||
686 |
* |
||
687 |
* \param value Value to store in the holder. |
||
688 |
*/ |
||
689 |
36 |
inplace_optional_holder(T&& value) |
|
690 |
36 |
{ |
|
691 |
✓✗✗✗ ✓✓✗✗ ✓✗✓✗ ✗✗✓✗ ✗✗ |
36 |
new (m_storage.getStorage()) T(std::move(value)); |
692 |
36 |
m_hasValue = true; |
|
693 |
36 |
} |
|
694 |
|||
695 |
// called from allocatorPropagatingCopy |
||
696 |
/** |
||
697 |
* Constructor from a given value passed by rvalue reference which prevents initialization. |
||
698 |
* |
||
699 |
* \param value Value to store in the holder. |
||
700 |
*/ |
||
701 |
template <typename U = T, |
||
702 |
typename std::enable_if<std::is_constructible<U, NoInitT, U>::value, int>::type = 0> |
||
703 |
6 |
inplace_optional_holder(NoInitT, T&& value) |
|
704 |
6 |
{ |
|
705 |
✓✗✗✗ |
6 |
new (m_storage.getStorage()) T(NoInit, std::move(value)); |
706 |
6 |
m_hasValue = true; |
|
707 |
6 |
} |
|
708 |
|||
709 |
/** |
||
710 |
* Copy constructor. |
||
711 |
* |
||
712 |
* \param other Other holder to copy. |
||
713 |
*/ |
||
714 |
72 |
inplace_optional_holder(const inplace_optional_holder& other) |
|
715 |
72 |
{ |
|
716 |
✓✗✓✓ ✓✗ |
72 |
if (other.hasValue()) |
717 |
{ |
||
718 |
✓✗✓✗ ✓✗✓✓ ✗✓✗✓ ✗✗✗ |
44 |
new (m_storage.getStorage()) T(*other.m_storage.getObject()); |
719 |
44 |
m_hasValue = true; |
|
720 |
} |
||
721 |
72 |
} |
|
722 |
|||
723 |
/** |
||
724 |
* Copy constructor which prevents initialization. |
||
725 |
* |
||
726 |
* \param other Other holder to copy. |
||
727 |
*/ |
||
728 |
template <typename U = T, |
||
729 |
typename std::enable_if<std::is_constructible<U, NoInitT, U>::value, int>::type = 0> |
||
730 |
2 |
inplace_optional_holder(NoInitT, const inplace_optional_holder& other) |
|
731 |
2 |
{ |
|
732 |
✓✓ | 2 |
if (other.hasValue()) |
733 |
{ |
||
734 |
✓✗✗✗ |
1 |
new (m_storage.getStorage()) T(NoInit, *other.m_storage.getObject()); |
735 |
1 |
m_hasValue = true; |
|
736 |
} |
||
737 |
2 |
} |
|
738 |
|||
739 |
/** |
||
740 |
* Move constructor. |
||
741 |
* |
||
742 |
* \param other Other holder to move. |
||
743 |
*/ |
||
744 |
4 |
inplace_optional_holder(inplace_optional_holder&& other) |
|
745 |
noexcept(std::is_nothrow_move_constructible<in_place_storage<T>>::value) |
||
746 |
4 |
{ |
|
747 |
✓✓✓✓ ✗✗ |
4 |
if (other.hasValue()) |
748 |
{ |
||
749 |
2 |
m_storage = std::move(other.m_storage); |
|
750 |
2 |
other.m_hasValue = false; |
|
751 |
2 |
m_hasValue = true; |
|
752 |
} |
||
753 |
4 |
} |
|
754 |
|||
755 |
/** |
||
756 |
* Move constructor which prevents initialization. |
||
757 |
* |
||
758 |
* \param other Other holder to move. |
||
759 |
*/ |
||
760 |
template <typename U = T, |
||
761 |
typename std::enable_if<std::is_constructible<U, NoInitT, U>::value, int>::type = 0> |
||
762 |
4 |
inplace_optional_holder(NoInitT, inplace_optional_holder&& other) |
|
763 |
noexcept(std::is_nothrow_move_constructible<in_place_storage<T>>::value) |
||
764 |
4 |
{ |
|
765 |
✓✓ | 4 |
if (other.hasValue()) |
766 |
{ |
||
767 |
2 |
m_storage.assign(NoInit, std::move(other.m_storage)); |
|
768 |
2 |
other.m_hasValue = false; |
|
769 |
2 |
m_hasValue = true; |
|
770 |
} |
||
771 |
4 |
} |
|
772 |
|||
773 |
/** |
||
774 |
* Constructor that initializes the value inplace by forwarding the arguments to the object's constructor. |
||
775 |
* |
||
776 |
* \param u Parameters for object's constructor. |
||
777 |
*/ |
||
778 |
template <typename ...U> |
||
779 |
3 |
explicit inplace_optional_holder(InPlaceT, U&& ...u) |
|
780 |
3 |
{ |
|
781 |
✓✗✓✗ ✓✗ |
3 |
new (m_storage.getStorage()) T(std::forward<U>(u)...); |
782 |
3 |
m_hasValue = true; |
|
783 |
3 |
} |
|
784 |
|||
785 |
/** |
||
786 |
* Destructor. |
||
787 |
*/ |
||
788 |
66883 |
~inplace_optional_holder() |
|
789 |
{ |
||
790 |
66883 |
reset(); |
|
791 |
66883 |
} |
|
792 |
|||
793 |
/** |
||
794 |
* Assignment operator. |
||
795 |
* |
||
796 |
* \param other Other holder to copy-assign. |
||
797 |
* |
||
798 |
* \return Reference to the current holder. |
||
799 |
*/ |
||
800 |
61 |
inplace_optional_holder& operator=(const inplace_optional_holder& other) |
|
801 |
{ |
||
802 |
✓✓✓✗ ✗✗✓✗ ✓✗✓✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ |
61 |
if (this != &other) |
803 |
{ |
||
804 |
60 |
reset(); |
|
805 |
✓✗✓✗ ✗✗✓✗ ✓✗✓✓ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ |
60 |
if (other.hasValue()) |
806 |
{ |
||
807 |
✓✗✗✗ ✓✗✗✗ ✗✗✗✗ ✗✓✗✗ ✗✗✓✗ ✗✗✗✓ ✗✗✓✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗ |
59 |
new (m_storage.getStorage()) T(*other.m_storage.getObject()); |
808 |
59 |
m_hasValue = true; |
|
809 |
} |
||
810 |
} |
||
811 |
|||
812 |
61 |
return *this; |
|
813 |
} |
||
814 |
|||
815 |
/** |
||
816 |
* Assignment operator which prevents initialization. |
||
817 |
* |
||
818 |
* \param other Other holder to copy-assign. |
||
819 |
* |
||
820 |
* \return Reference to the current holder. |
||
821 |
*/ |
||
822 |
template <typename U = T, |
||
823 |
typename std::enable_if<std::is_constructible<U, NoInitT, U>::value, int>::type = 0> |
||
824 |
9 |
inplace_optional_holder& assign(NoInitT, const inplace_optional_holder& other) |
|
825 |
{ |
||
826 |
✓✓ | 9 |
if (this != &other) |
827 |
{ |
||
828 |
8 |
reset(); |
|
829 |
✓✓ | 8 |
if (other.hasValue()) |
830 |
{ |
||
831 |
✓✗✗✗ |
7 |
new (m_storage.getStorage()) T(NoInit, *other.m_storage.getObject()); |
832 |
7 |
m_hasValue = true; |
|
833 |
} |
||
834 |
} |
||
835 |
|||
836 |
9 |
return *this; |
|
837 |
} |
||
838 |
|||
839 |
/** |
||
840 |
* Move assignment operator. |
||
841 |
* |
||
842 |
* \param other Other holder to move-assign. |
||
843 |
* |
||
844 |
* \return Reference to the current holder. |
||
845 |
*/ |
||
846 |
16329 |
inplace_optional_holder& operator=(inplace_optional_holder&& other) |
|
847 |
{ |
||
848 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✓ ✗✗✓✗ ✓✗✗✗ ✗✗✗✗ ✗✗✓✗ ✓✗✓✗ ✗✗✗✗ ✗✗✓✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ |
16329 |
if (this != &other) |
849 |
{ |
||
850 |
16328 |
reset(); |
|
851 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✓ ✗✗✗✓ ✓✓✗✗ ✗✗✗✗ ✗✗✓✗ ✓✗✓✗ ✗✗✗✗ ✗✗✓✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ |
16328 |
if (other.hasValue()) |
852 |
{ |
||
853 |
16311 |
m_storage = std::move(other.m_storage); |
|
854 |
16311 |
other.m_hasValue = false; |
|
855 |
16311 |
m_hasValue = true; |
|
856 |
} |
||
857 |
} |
||
858 |
|||
859 |
16329 |
return *this; |
|
860 |
} |
||
861 |
|||
862 |
/** |
||
863 |
* Move assignment operator which prevents initialization. |
||
864 |
* |
||
865 |
* \param other Other holder to move-assign. |
||
866 |
* |
||
867 |
* \return Reference to the current holder. |
||
868 |
*/ |
||
869 |
template <typename U = T, |
||
870 |
typename std::enable_if<std::is_constructible<U, NoInitT, U>::value, int>::type = 0> |
||
871 |
10 |
inplace_optional_holder& assign(NoInitT, inplace_optional_holder&& other) |
|
872 |
{ |
||
873 |
✓✓ | 10 |
if (this != &other) |
874 |
{ |
||
875 |
9 |
reset(); |
|
876 |
✓✓ | 9 |
if (other.hasValue()) |
877 |
{ |
||
878 |
8 |
m_storage.assign(NoInit, std::move(other.m_storage)); |
|
879 |
8 |
other.m_hasValue = false; |
|
880 |
8 |
m_hasValue = true; |
|
881 |
} |
||
882 |
} |
||
883 |
|||
884 |
10 |
return *this; |
|
885 |
} |
||
886 |
|||
887 |
/** |
||
888 |
* Assignment operator from value. |
||
889 |
* |
||
890 |
* \param value Value to assign. |
||
891 |
* |
||
892 |
* \return Reference to the current holder. |
||
893 |
*/ |
||
894 |
33378 |
inplace_optional_holder& operator=(const T& value) |
|
895 |
{ |
||
896 |
33378 |
set(value); |
|
897 |
|||
898 |
33378 |
return *this; |
|
899 |
} |
||
900 |
|||
901 |
/** |
||
902 |
* Assignment operator from rvalue reference to value. |
||
903 |
* |
||
904 |
* \param value Value to move-assign. |
||
905 |
* |
||
906 |
* \return Reference to the current holder. |
||
907 |
*/ |
||
908 |
16849 |
inplace_optional_holder& operator=(T&& value) |
|
909 |
{ |
||
910 |
16849 |
set(std::move(value)); |
|
911 |
|||
912 |
16849 |
return *this; |
|
913 |
} |
||
914 |
|||
915 |
/** |
||
916 |
* Resets the current holder (switch to the unset state). |
||
917 |
*/ |
||
918 |
133563 |
void reset() noexcept |
|
919 |
{ |
||
920 |
✓✓✓✓ ✓✓✓✓ ✓✓✗✗ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✗✗ ✗✗✓✓ ✓✓✓✓ ✓✓✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✗✗✓✓ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✓✓✗✗ |
133563 |
if (hasValue()) |
921 |
{ |
||
922 |
50425 |
m_storage.getObject()->~T(); |
|
923 |
50425 |
m_hasValue = false; |
|
924 |
} |
||
925 |
133563 |
} |
|
926 |
|||
927 |
/** |
||
928 |
* Gets whether the holder has any value. |
||
929 |
* |
||
930 |
* \return True when this holder has assigned any value. False otherwise. |
||
931 |
*/ |
||
932 |
201187 |
bool hasValue() const noexcept |
|
933 |
{ |
||
934 |
201187 |
return m_hasValue; |
|
935 |
} |
||
936 |
|||
937 |
/** |
||
938 |
* Dereference operator *. |
||
939 |
* |
||
940 |
* \return Const reference to the assigned value. |
||
941 |
* |
||
942 |
* \throw CppRuntimeException when the holder is unset. |
||
943 |
*/ |
||
944 |
48741 |
const T& operator*() const |
|
945 |
{ |
||
946 |
48741 |
this->checkHasValue(); |
|
947 |
48741 |
return *m_storage.getObject(); |
|
948 |
} |
||
949 |
|||
950 |
/** |
||
951 |
* Dereference operator *. |
||
952 |
* |
||
953 |
* \return Reference to the assigned value. |
||
954 |
* |
||
955 |
* \throw CppRuntimeException when the holder is unset. |
||
956 |
*/ |
||
957 |
1305 |
T& operator*() |
|
958 |
{ |
||
959 |
1305 |
this->checkHasValue(); |
|
960 |
1299 |
return *m_storage.getObject(); |
|
961 |
} |
||
962 |
|||
963 |
private: |
||
964 |
template <typename U = T> |
||
965 |
50227 |
void set(U&& value) |
|
966 |
{ |
||
967 |
50227 |
reset(); |
|
968 |
✓✗✗✗ ✓✗✗✗ ✓✗✗✓ ✗✓✓✗ ✗✓✓✗ ✗✓✗✓ ✗✗✓✓ ✗✓✗✗ ✓✓✗✓ ✗✓✓✓ ✓✗✓✗ ✓✗✗✓ ✗✓✗✗ ✓✗✓✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✓ ✗✗✓✗ ✓✗✗✗ ✗✓✗✗ ✗✗✓✗ ✗✓✗✓ ✗✓✓✗ ✓✗✗✗ ✓✓✗✓ ✗✗✓✗ ✓✗✗✓ ✗✗✗✗ ✓✗✗✗ ✗✓✗✗ ✗✓✓✗ ✓✓✗✗ ✗✓✓✗ ✗✓✓✗ ✓✓✗✗ ✗✗✗✓ ✗✗✓✗ ✗✓✗✗ ✓✗✓✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✗✗✓✗ ✗✗✗✗ ✗✗✗✗ ✓✗✓✗ ✗✗ |
50227 |
new (m_storage.getStorage()) T(std::forward<U>(value)); |
969 |
50227 |
m_hasValue = true; |
|
970 |
50227 |
} |
|
971 |
|||
972 |
in_place_storage<T> m_storage; |
||
973 |
bool m_hasValue = false; |
||
974 |
}; |
||
975 |
|||
976 |
} // namespace detail |
||
977 |
|||
978 |
// Be aware that if Inplace/HeapOptionalHolder is defined by typename, C++ compiler will have problem with |
||
979 |
// template function overload, see HashCodeUtil.h (overloads for objects and for Inplace/HeapOptionalHolder). |
||
980 |
/** |
||
981 |
* Optional holder which uses in place storage. |
||
982 |
*/ |
||
983 |
template <typename T> |
||
984 |
using InplaceOptionalHolder = detail::inplace_optional_holder<T>; |
||
985 |
|||
986 |
/** |
||
987 |
* Optional holder which uses heap storage. |
||
988 |
*/ |
||
989 |
template <typename T, typename ALLOC = std::allocator<T>> |
||
990 |
using HeapOptionalHolder = detail::heap_optional_holder<T, ALLOC>; |
||
991 |
|||
992 |
} // namespace zserio |
||
993 |
|||
994 |
#endif // ifndef ZSERIO_OPTIONAL_HOLDER_H_INC |
Generated by: GCOVR (Version 4.2) |