Zserio C++17 runtime library 1.3.0
Built for Zserio 2.20.0
Loading...
Searching...
No Matches
Variant.h
Go to the documentation of this file.
1#ifndef ZSERIO_VARIANT_H_INC
2#define ZSERIO_VARIANT_H_INC
3
5#include "zserio/Any.h"
8#include "zserio/Traits.h"
9
10namespace zserio
11{
12
13namespace detail
14{
15
16template <size_t I, typename... T>
17struct type_at
18{
19 using type = std::tuple_element_t<I, std::tuple<T...>>;
20};
21
22template <auto I, typename... T>
23using type_at_t = typename type_at<static_cast<size_t>(I), T...>::type;
24
25template <size_t N, typename V, typename F>
26void for_active_item(const V&, F&&, std::false_type)
27{}
28
29template <size_t N, typename V, typename F>
30void for_active_item(const V& var, F&& fun, std::true_type = {})
31{
32 using INDEX = typename V::IndexType;
33 if (static_cast<size_t>(var.index()) == N - 1)
34 {
35 std::forward<F>(fun)(*var.template get_if<static_cast<INDEX>(N - 1)>());
36 }
37 for_active_item<N - 1>(var, std::forward<F>(fun), std::bool_constant<(N - 1 > 0)>());
38}
39
40template <size_t N, typename V, typename F>
41void for_active_item(V& var, F&& fun, std::true_type = {})
42{
43 using INDEX = typename V::IndexType;
44 if (static_cast<size_t>(var.index()) == N - 1)
45 {
46 std::forward<F>(fun)(*var.template get_if<static_cast<INDEX>(N - 1)>());
47 }
48 for_active_item<N - 1>(var, std::forward<F>(fun), std::bool_constant<(N - 1 > 0)>());
49}
50
51template <size_t N, typename V, typename F>
52void for_active_item_2(const V&, const V&, F&&, std::false_type)
53{}
54
55template <size_t N, typename V, typename F>
56void for_active_item_2(const V& var1, const V& var2, F&& fun, std::true_type = {})
57{
58 // assert(var1.index() == var2.index());
59 using INDEX = typename V::IndexType;
60 if (static_cast<size_t>(var1.index()) == N - 1)
61 {
62 std::forward<F>(fun)(*var1.template get_if<static_cast<INDEX>(N - 1)>(),
63 *var2.template get_if<static_cast<INDEX>(N - 1)>());
64 }
65 for_active_item_2<N - 1>(var1, var2, std::forward<F>(fun), std::bool_constant<(N - 1 > 0)>());
66}
67
68} // namespace detail
69
80
81template <auto I>
83{};
84
88template <auto I>
90
101template <typename ALLOC, typename INDEX, typename... T>
103{
104 using AllocTraits = std::allocator_traits<ALLOC>;
105
106public:
109
115 {}
116
124 explicit BasicVariant(const ALLOC& allocator) :
125 m_data(allocator)
126 {
127 emplace<INDEX{}>(); // enforce no empty state like std::variant
128 }
129
138 template <INDEX I, typename... ARGS, std::enable_if_t<!is_first_allocator_v<ARGS...>>* = nullptr>
140 {
141 emplace<I>(std::forward<ARGS>(args)...);
142 }
143
153 template <INDEX I, typename... ARGS>
155 m_data(allocator)
156 {
157 emplace<I>(std::forward<ARGS>(args)...);
158 }
159
166 m_data(other.m_data),
167 m_index(other.m_index)
168 {}
169
179 m_data(other.m_data, allocator),
180 m_index(other.m_index)
181 {}
182
193 {
194 m_data = other.m_data;
195 m_index = other.m_index;
196 return *this;
197 }
198
207 m_data(std::move(other.m_data)),
208 m_index(other.m_index)
209 {}
210
220 m_data(std::move(other.m_data), allocator),
221 m_index(other.m_index)
222 {}
223
227 ~BasicVariant() = default;
228
237 {
238 if (this != &other)
239 {
240 m_data = std::move(other.m_data);
241 m_index = other.m_index;
242 }
243
244 return *this;
245 }
246
256 {
257 return static_cast<size_t>(index()) == std::variant_npos || !m_data.hasValue();
258 }
259
265 template <INDEX I, typename... ARGS>
266 decltype(auto) emplace(ARGS&&... args)
267 {
268 using U = detail::type_at_t<I, T...>;
269 auto& ret = m_data.template emplace<U>(std::forward<ARGS>(args)...);
270 m_index = I;
271 return ret;
272 }
273
278 {
279 return m_data.hasValue() ? m_index : static_cast<INDEX>(std::variant_npos);
280 }
281
285 template <INDEX I, typename U = detail::type_at_t<I, T...>>
287 {
288 if (I != index())
289 {
290 return nullptr;
291 }
292 return m_data.template get_if<U>();
293 }
294
298 template <INDEX I, typename U = detail::type_at_t<I, T...>>
300 {
301 if (I != index())
302 {
303 return nullptr;
304 }
305 return m_data.template get_if<U>();
306 }
307
313 template <INDEX I, typename U = detail::type_at_t<I, T...>>
315 {
316 auto ptr = get_if<I>();
317 if (!ptr)
318 {
319 throw BadVariantAccess("Variant: Attempt to retrieve an inactive element at index ")
320 << static_cast<size_t>(I) << ". Active element index is " << static_cast<size_t>(index());
321 }
322 return *ptr;
323 }
324
330 template <INDEX I, typename U = detail::type_at_t<I, T...>>
331 const U& get() const
332 {
333 auto ptr = get_if<I>();
334 if (!ptr)
335 {
336 throw BadVariantAccess("Variant: Attempt to retrieve an inactive element at index ")
337 << static_cast<size_t>(I) << ". Active element index is " << static_cast<size_t>(index());
338 }
339 return *ptr;
340 }
341
348 {
349 m_data.swap(other.m_data);
350 std::swap(m_index, other.m_index);
351 }
352
360 template <typename F>
361 auto visit(F&& fun) -> decltype(fun(std::declval<detail::type_at_t<0, T...>>()))
362 {
364 {
365 throw BadVariantAccess("Variant: Cannot visit variant in valueless state");
366 }
367 using R = decltype(fun(std::declval<detail::type_at_t<0, T...>>()));
368 if constexpr (std::is_same_v<R, void>)
369 {
370 detail::for_active_item<sizeof...(T)>(*this, [func = std::forward<F>(fun)](auto& elem) {
371 std::move(func)(elem);
372 });
373 }
374 else
375 {
376 R ret;
377 detail::for_active_item<sizeof...(T)>(*this, [&ret, func = std::forward<F>(fun)](auto& elem) {
378 ret = std::move(func)(elem);
379 });
380 return ret;
381 }
382 }
383
391 template <typename F>
392 auto visit(F&& fun) const -> decltype(fun(std::declval<detail::type_at_t<0, T...>>()))
393 {
395 {
396 throw BadVariantAccess("Variant: Cannot visit variant in valueless state");
397 }
398 using R = decltype(fun(std::declval<detail::type_at_t<0, T...>>()));
399 if constexpr (std::is_same_v<R, void>)
400 {
401 detail::for_active_item<sizeof...(T)>(*this, [func = std::forward<F>(fun)](auto& elem) {
402 std::move(func)(elem);
403 });
404 }
405 else
406 {
407 R ret;
408 detail::for_active_item<sizeof...(T)>(*this, [&ret, func = std::forward<F>(fun)](auto& elem) {
409 ret = std::move(func)(elem);
410 });
411 return ret;
412 }
413 }
414
420 bool operator==(const BasicVariant& other) const
421 {
422 if (index() != other.index())
423 {
424 return false;
425 }
426
427 bool ret = false;
428 detail::for_active_item_2<sizeof...(T)>(*this, other, [&ret](auto& elem1, auto& elem2) {
429 ret = elem1 == elem2;
430 });
431 return ret;
432 }
433
439 bool operator!=(const BasicVariant& other) const
440 {
441 return !(*this == other);
442 }
443
449 bool operator<(const BasicVariant& other) const
450 {
451 if (index() != other.index())
452 {
453 return index() < other.index();
454 }
455
456 bool ret = false;
457 detail::for_active_item_2<sizeof...(T)>(*this, other, [&ret](auto& elem1, auto& elem2) {
458 ret = elem1 < elem2;
459 });
460 return ret;
461 }
462
468 bool operator>(const BasicVariant& other) const
469 {
470 return other < *this;
471 }
472
478 bool operator<=(const BasicVariant& other) const
479 {
480 return !(other < *this);
481 }
482
488 bool operator>=(const BasicVariant& other) const
489 {
490 return !(other > *this);
491 }
492
493private:
494 BasicAny<ALLOC> m_data;
495 INDEX m_index;
496};
497
498// Using declarations
499
500template <typename INDEX, typename... T>
502
510template <auto I, typename ALLOC, typename INDEX, typename... T>
512{
513 static_assert(std::is_same_v<decltype(I), INDEX>, "Index has a wrong type");
514 return var.template get<I>();
515}
516
524template <auto I, typename ALLOC, typename INDEX, typename... T>
526{
527 static_assert(std::is_same_v<decltype(I), INDEX>, "Index has a wrong type");
528 return var.template get<I>();
529}
530
536template <auto I, typename ALLOC, typename INDEX, typename... T>
538{
539 static_assert(std::is_same_v<decltype(I), INDEX>, "Index has a wrong type");
540 return var->template get_if<I>();
541}
542
548template <auto I, typename ALLOC, typename INDEX, typename... T>
550{
551 static_assert(std::is_same_v<decltype(I), INDEX>, "Index has a wrong type");
552 return var->template get_if<I>();
553}
554
563template <typename F, typename ALLOC, typename INDEX, typename... T>
565{
566 return var.visit(std::forward<F>(fun));
567}
568
577template <typename F, typename ALLOC, typename INDEX, typename... T>
579{
580 return var.visit(std::forward<F>(fun));
581}
582
589template <typename ALLOC, typename INDEX, typename... T>
591{
593 result = calcHashCode(result, static_cast<size_t>(var.index()));
594 var.visit([&result](const auto& value) {
595 result = calcHashCode(result, value);
596 });
597 return result;
598}
599
600} // namespace zserio
601
602namespace std
603{
604
605template <typename ALLOC, typename INDEX, typename... T>
606struct hash<zserio::BasicVariant<ALLOC, INDEX, T...>>
607{
608 size_t operator()(const zserio::BasicVariant<ALLOC, INDEX, T...>& var) const
609 {
610 return zserio::calcHashCode(zserio::HASH_SEED, var);
611 }
612};
613
614} // namespace std
615
616#endif // ZSERIO_VARIANT_H_INC
bool hasValue() const noexcept
Definition Any.h:621
void swap(BasicAny &other)
Definition Any.h:479
BasicVariant(const BasicVariant &other, const ALLOC &allocator)
Definition Variant.h:178
BasicVariant & operator=(BasicVariant &&other)
Definition Variant.h:236
void swap(BasicVariant &other)
Definition Variant.h:347
auto visit(F &&fun) const -> decltype(fun(std::declval< detail::type_at_t< 0, T... > >()))
Definition Variant.h:392
const U & get() const
Definition Variant.h:331
BasicVariant(BasicVariant &&other, const ALLOC &allocator)
Definition Variant.h:219
BasicVariant(const ALLOC &allocator)
Definition Variant.h:124
bool operator<=(const BasicVariant &other) const
Definition Variant.h:478
bool operator<(const BasicVariant &other) const
Definition Variant.h:449
bool operator>(const BasicVariant &other) const
Definition Variant.h:468
BasicVariant & operator=(const BasicVariant &other)
Definition Variant.h:192
U * get_if() noexcept
Definition Variant.h:286
BasicVariant(in_place_index_t< I >, ARGS &&... args)
Definition Variant.h:139
bool valueless_by_exception() const noexcept
Definition Variant.h:255
BasicVariant(in_place_index_t< I >, const ALLOC &allocator, ARGS &&... args)
Definition Variant.h:154
const U * get_if() const noexcept
Definition Variant.h:299
bool operator==(const BasicVariant &other) const
Definition Variant.h:420
bool operator>=(const BasicVariant &other) const
Definition Variant.h:488
auto visit(F &&fun) -> decltype(fun(std::declval< detail::type_at_t< 0, T... > >()))
Definition Variant.h:361
INDEX index() const noexcept
Definition Variant.h:277
BasicVariant(const BasicVariant &other)
Definition Variant.h:165
BasicVariant(BasicVariant &&other)
Definition Variant.h:206
decltype(auto) emplace(ARGS &&... args)
Definition Variant.h:266
bool operator!=(const BasicVariant &other) const
Definition Variant.h:439
CppRuntimeException(const char *message="")
decltype(auto) visit(F &&fun, BasicVariant< ALLOC, INDEX, T... > &var)
Definition Variant.h:564
constexpr in_place_index_t< I > in_place_index
Definition Variant.h:89
decltype(auto) get(BasicVariant< ALLOC, INDEX, T... > &var)
Definition Variant.h:511
uint32_t calcHashCode(uint32_t seedValue, const ArrayView< T, ARRAY_TRAITS > &array)
Definition ArrayView.h:882
decltype(auto) get_if(BasicVariant< ALLOC, INDEX, T... > *var)
Definition Variant.h:537
constexpr bool is_first_allocator_v
Definition Traits.h:122