Embedded Template Library 1.0
Loading...
Searching...
No Matches
variant_variadic.h
Go to the documentation of this file.
1
2
3/******************************************************************************
4The MIT License(MIT)
5
6Embedded Template Library.
7https://github.com/ETLCPP/etl
8https://www.etlcpp.com
9
10Copyright(c) 2021 jwellbelove, Robin S�derholm
11
12Permission is hereby granted, free of charge, to any person obtaining a copy
13of this software and associated documentation files(the "Software"), to deal
14in the Software without restriction, including without limitation the rights
15to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
16copies of the Software, and to permit persons to whom the Software is
17furnished to do so, subject to the following conditions :
18
19The above copyright notice and this permission notice shall be included in all
20copies or substantial portions of the Software.
21
22THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
25AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28SOFTWARE.
29******************************************************************************/
30
31#include "../platform.h"
32#include "../utility.h"
33#include "../largest.h"
34#include "../exception.h"
35#include "../type_traits.h"
36#include "../integral_limits.h"
37#include "../static_assert.h"
38#include "../alignment.h"
39#include "../error_handler.h"
40#include "../parameter_pack.h"
41#include "../placement_new.h"
42#include "../visitor.h"
43#include "../memory.h"
44#include "../compare.h"
45#include "../initializer_list.h"
46
47#include <stdint.h>
48
49#if defined(ETL_COMPILER_KEIL)
50 #pragma diag_suppress 940
51 #pragma diag_suppress 111
52#endif
53
54#if ETL_CPP11_NOT_SUPPORTED
55 #if !defined(ETL_IN_UNIT_TEST)
56 #error NOT SUPPORTED FOR C++03 OR BELOW
57 #endif
58#else
59//*****************************************************************************
63//*****************************************************************************
64
65namespace etl
66{
67 namespace private_variant
68 {
69 //***************************************************************************
70 // This is a copy of the normal etl::parameter_pack, but without the static_assert
71 // so that the C++11 versions of do_visitor() & do_operator() do not throw a compile time error.
72 //***************************************************************************
73 template <typename... TTypes>
74 class parameter_pack
75 {
76 public:
77
78 static constexpr size_t size = sizeof...(TTypes);
79
80 //***************************************************************************
82 //***************************************************************************
83 template <typename T>
84 class index_of_type
85 {
86 private:
87
88 using type = etl::remove_cvref_t<T>;
89
90 //***********************************
91 template <typename Type, typename T1, typename... TRest>
92 struct index_of_type_helper
93 {
94 static constexpr size_t value = etl::is_same<Type, T1>::value ? 1 : 1 + index_of_type_helper<Type, TRest...>::value;
95 };
96
97 //***********************************
98 template <typename Type, typename T1>
99 struct index_of_type_helper<Type, T1>
100 {
101 static constexpr size_t value = 1UL;
102 };
103
104 public:
105
106 static_assert(etl::is_one_of<type, TTypes...>::value, "T is not in parameter pack");
107
109 static constexpr size_t value = index_of_type_helper<type, TTypes...>::value - 1;
110 };
111
112 //***************************************************************************
114 //***************************************************************************
115 template <size_t I>
116 class type_from_index
117 {
118 private:
119
120 //***********************************
121 template <size_t II, size_t N, typename T1, typename... TRest>
122 struct type_from_index_helper
123 {
124 using type = typename etl::conditional<II == N, T1, typename type_from_index_helper<II, N + 1, TRest...>::type>::type;
125 };
126
127 //***********************************
128 template <size_t II, size_t N, typename T1>
129 struct type_from_index_helper<II, N, T1>
130 {
131 using type = T1;
132 };
133
134 public:
135
137 using type = typename type_from_index_helper<I, 0, TTypes...>::type;
138 };
139
140 //***********************************
141 template <size_t I>
142 using type_from_index_t = typename type_from_index<I>::type;
143 };
144
145 //*******************************************
146 // The traits an object may have.
147 //*******************************************
148 static constexpr bool Copyable = true;
149 static constexpr bool Non_Copyable = false;
150 static constexpr bool Moveable = true;
151 static constexpr bool Non_Moveable = false;
152
153 //*******************************************
154 // The types of operations we can perform.
155 //*******************************************
156 static constexpr int Copy = 0;
157 static constexpr int Move = 1;
158 static constexpr int Destroy = 2;
159
160 //*******************************************
161 // operation_type
162 //*******************************************
163 template <typename T, bool IsCopyable, bool IsMoveable>
164 struct operation_type;
165
166 //*******************************************
167 // Specialisation for null operation.
168 template <>
169 struct operation_type<void, Non_Copyable, Non_Moveable>
170 {
171 static void do_operation(int , char* , const char* )
172 {
173 // This should never occur.
174#if defined(ETL_IN_UNIT_TEST)
175 assert(false);
176#endif
177 }
178 };
179
180 //*******************************************
181 // Specialisation for no-copyable & non-moveable types.
182 template <typename T>
183 struct operation_type<T, Non_Copyable, Non_Moveable>
184 {
185 static void do_operation(int operation, char* pstorage, const char* /*pvalue*/)
186 {
187 switch (operation)
188 {
189 case Destroy:
190 {
191 reinterpret_cast<const T*>(pstorage)->~T();
192 break;
193 }
194
195 default:
196 {
197 // This should never occur.
198 #if defined(ETL_IN_UNIT_TEST)
199 assert(false);
200 #endif
201 break;
202 }
203 }
204 }
205 };
206
207 //*******************************************
208 // Specialisation for no-copyable & moveable types.
209 template <typename T>
210 struct operation_type<T, Non_Copyable, Moveable>
211 {
212 static void do_operation(int operation, char* pstorage, const char* pvalue)
213 {
214 switch (operation)
215 {
216 case Move:
217 {
218 ::new (pstorage) T(etl::move(*reinterpret_cast<T*>(const_cast<char*>(pvalue))));
219 break;
220 }
221
222 case Destroy:
223 {
224 reinterpret_cast<const T*>(pstorage)->~T();
225 break;
226 }
227
228 default:
229 {
230 // This should never occur.
231 #if defined(ETL_IN_UNIT_TEST)
232 assert(false);
233 #endif
234 break;
235 }
236 }
237 }
238 };
239
240 //*******************************************
241 // Specialisation for copyable & non-moveable types.
242 template <typename T>
243 struct operation_type<T, Copyable, Non_Moveable>
244 {
245 static void do_operation(int operation, char* pstorage, const char* pvalue)
246 {
247 switch (operation)
248 {
249 case Copy:
250 {
251 ::new (pstorage) T(*reinterpret_cast<const T*>(pvalue));
252 break;
253 }
254
255 case Destroy:
256 {
257 reinterpret_cast<const T*>(pstorage)->~T();
258 break;
259 }
260
261 default:
262 {
263 // This should never occur.
264 #if defined(ETL_IN_UNIT_TEST)
265 assert(false);
266 #endif
267 break;
268 }
269 }
270 }
271 };
272
273 //*******************************************
274 // Specialisation for copyable & moveable types.
275 template <typename T>
276 struct operation_type<T, Copyable, Moveable>
277 {
278 static void do_operation(int operation, char* pstorage, const char* pvalue)
279 {
280 switch (operation)
281 {
282 case Copy:
283 {
284 ::new (pstorage) T(*reinterpret_cast<const T*>(pvalue));
285 break;
286 }
287
288 case Move:
289 {
290 ::new (pstorage) T(etl::move(*reinterpret_cast<T*>(const_cast<char*>(pvalue))));
291 break;
292 }
293
294 case Destroy:
295 {
296 reinterpret_cast<const T*>(pstorage)->~T();
297 break;
298 }
299
300 default:
301 {
302 // This should never occur.
303#if defined(ETL_IN_UNIT_TEST)
304 assert(false);
305#endif
306 break;
307 }
308 }
309 }
310 };
311 }
312
314 constexpr size_t variant_npos = etl::integral_limits<size_t>::max;
315
316 //***********************************
317 // variant. Forward declaration
318 template <typename... TTypes>
319 class variant;
320
321 //***************************************************************************
323 //***************************************************************************
324 template <size_t Index, typename T>
325 struct variant_alternative;
326
327 template <size_t Index, typename... TTypes>
328 struct variant_alternative<Index, etl::variant<TTypes...>>
329 {
330 using type = typename etl::private_variant::parameter_pack<TTypes...>::template type_from_index<Index>::type;
331 };
332
333 template <size_t Index, typename T>
334 struct variant_alternative<Index, const T>
335 {
336 using type = typename variant_alternative<Index, T>::type;
337 };
338
339 template <size_t Index, typename T>
340 using variant_alternative_t = typename variant_alternative<Index, T>::type;
341
342 //***********************************
343 // holds_alternative. Forward declaration
344 template <typename T, typename... TTypes>
345 ETL_CONSTEXPR14 bool holds_alternative(const etl::variant<TTypes...>& v) noexcept;
346
347 //***********************************
348 // get. Forward declarations
349 template <size_t Index, typename... VTypes>
350 ETL_CONSTEXPR14 etl::variant_alternative_t<Index, etl::variant<VTypes...>>&
352
353 template <size_t Index, typename... VTypes>
354 ETL_CONSTEXPR14 etl::variant_alternative_t<Index, etl::variant<VTypes...>>&&
356
357 template <size_t Index, typename... VTypes>
358 ETL_CONSTEXPR14 const etl::variant_alternative_t<Index, const etl::variant<VTypes...>>&
360
361 template <size_t Index, typename... VTypes>
362 ETL_CONSTEXPR14 const etl::variant_alternative_t<Index, const etl::variant<VTypes...>>&&
363 get(const etl::variant<VTypes...>&& v);
364
365 template <typename T, typename... VTypes>
366 ETL_CONSTEXPR14 T& get(etl::variant<VTypes...>& v);
367
368 template <typename T, typename... VTypes>
369 ETL_CONSTEXPR14 T&& get(etl::variant<VTypes...>&& v);
370
371 template <typename T, typename... VTypes>
372 ETL_CONSTEXPR14 const T& get(const etl::variant<VTypes...>& v);
373
374 template <typename T, typename... VTypes>
375 ETL_CONSTEXPR14 const T&& get(const etl::variant<VTypes...>&& v);
376
377 //***************************************************************************
380 //***************************************************************************
381 struct monostate
382 {
383 };
384
385 constexpr bool operator >(etl::monostate, etl::monostate) noexcept { return false; }
386 constexpr bool operator <(etl::monostate, etl::monostate) noexcept { return false; }
387 constexpr bool operator !=(etl::monostate, etl::monostate) noexcept { return false; }
388 constexpr bool operator <=(etl::monostate, etl::monostate) noexcept { return true; }
389 constexpr bool operator >=(etl::monostate, etl::monostate) noexcept { return true; }
390 constexpr bool operator ==(etl::monostate, etl::monostate) noexcept { return true; }
391#if ETL_USING_CPP20 && ETL_USING_STL && !(defined(ETL_DEVELOPMENT_OS_APPLE) && defined(ETL_COMPILER_CLANG))
392 constexpr std::strong_ordering operator<=>(monostate, monostate) noexcept
393 {
394 return std::strong_ordering::equal;
395 }
396#endif
397
398#if ETL_NOT_USING_STL && !defined(ETL_USE_TYPE_TRAITS_BUILTINS)
399 template <>
400 struct is_copy_constructible<etl::monostate> : public etl::true_type
401 {
402 };
403
404 template <>
405 struct is_move_constructible<etl::monostate> : public etl::true_type
406 {
407 };
408#endif
409
410 //***************************************************************************
413 //***************************************************************************
414 class variant_exception : public exception
415 {
416 public:
417 variant_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
418 : exception(reason_, file_name_, line_number_)
419 {
420 }
421 };
422
423 //***************************************************************************
426 //***************************************************************************
427 class variant_incorrect_type_exception : public variant_exception
428 {
429 public:
430 variant_incorrect_type_exception(string_type file_name_, numeric_type line_number_)
431 : variant_exception(ETL_ERROR_TEXT("variant:unsupported type", ETL_VARIANT_FILE_ID"A"), file_name_, line_number_)
432 {
433 }
434 };
435
436 //***************************************************************************
439 //***************************************************************************
440 class bad_variant_access : public variant_exception
441 {
442 public:
443 bad_variant_access(string_type file_name_, numeric_type line_number_)
444 : variant_exception(ETL_ERROR_TEXT("variant:bad variant access", ETL_VARIANT_FILE_ID"B"), file_name_, line_number_)
445 {}
446 };
447
448 //***************************************************************************
452 //***************************************************************************
453 template <typename... TTypes>
454 class variant
455 {
456 public:
457
458 //***************************************************************************
460 //***************************************************************************
461 using type_id_t = uint_least8_t ;
462
463 //***************************************************************************
465 //***************************************************************************
466 template <size_t Index, typename... VTypes>
467 friend ETL_CONSTEXPR14 etl::variant_alternative_t<Index, etl::variant<VTypes...>>&
469
470 template <size_t Index, typename... VTypes>
471 friend ETL_CONSTEXPR14 etl::variant_alternative_t<Index, etl::variant<VTypes...>>&&
473
474 template <size_t Index, typename... VTypes>
475 friend ETL_CONSTEXPR14 const etl::variant_alternative_t<Index, const etl::variant<VTypes...>>&
477
478 template <size_t Index, typename... VTypes>
479 friend ETL_CONSTEXPR14 const etl::variant_alternative_t<Index, const etl::variant<VTypes...>>&&
480 get(const etl::variant<VTypes...>&& v);
481
482 template <typename T, typename... VTypes>
483 friend ETL_CONSTEXPR14 T& get(etl::variant<VTypes...>& v);
484
485 template <typename T, typename... VTypes>
486 friend ETL_CONSTEXPR14 T&& get(etl::variant<VTypes...>&& v);
487
488 template <typename T, typename... VTypes>
489 friend ETL_CONSTEXPR14 const T& get(const etl::variant<VTypes...>& v);
490
491 template <typename T, typename... VTypes>
492 friend ETL_CONSTEXPR14 const T&& get(const etl::variant<VTypes...>&& v);
493
494 private:
495
496 // All types of variant are friends.
497 template <typename... UTypes>
498 friend class variant;
499
500 //***************************************************************************
502 //***************************************************************************
503 using largest_t = typename largest_type<TTypes...>::type;
504
505 //***************************************************************************
507 //***************************************************************************
508 static const size_t Size = sizeof(largest_t);
509
510 //***************************************************************************
512 //***************************************************************************
513 static const size_t Alignment = etl::largest_alignment<TTypes...>::value;
514
515 //***************************************************************************
517 //***************************************************************************
518 template <typename T, bool IsCopyable, bool IsMoveable>
519 using operation_type = private_variant::operation_type<T, IsCopyable, IsMoveable>;
520
521 //*******************************************
522 // The types of operations we can perform.
523 //*******************************************
524 static constexpr int Copy = private_variant::Copy;
525 static constexpr int Move = private_variant::Move;
526 static constexpr int Destroy = private_variant::Destroy;
527
528 //*******************************************
529 // Get the index of a type.
530 //*******************************************
531 template <typename T>
532 using index_of_type = typename etl::private_variant::parameter_pack<TTypes...>::template index_of_type<etl::remove_cvref_t<T>>;
533
534 //*******************************************
535 // Get the type from the index.
536 //*******************************************
537 template <size_t Index>
538 using type_from_index = typename etl::private_variant::parameter_pack<TTypes...>::template type_from_index<Index>::type;
539
540 public:
541
542 //***************************************************************************
545 //***************************************************************************
547 ETL_CONSTEXPR14 variant()
548 {
549 using type = typename etl::private_variant::parameter_pack<TTypes...>::template type_from_index<0U>::type;
550
551 default_construct_in_place<type>(data);
552 operation = operation_type<type, etl::is_copy_constructible<type>::value, etl::is_move_constructible<type>::value>::do_operation;
553 type_id = 0U;
554 }
555#include "diagnostic_pop.h"
556
557 //***************************************************************************
559 //***************************************************************************
561 template <typename T, etl::enable_if_t<!etl::is_same<etl::remove_cvref_t<T>, variant>::value, int> = 0>
562 ETL_CONSTEXPR14 variant(T&& value)
563 : operation(operation_type<etl::remove_cvref_t<T>, etl::is_copy_constructible<etl::remove_cvref_t<T>>::value, etl::is_move_constructible<etl::remove_cvref_t<T>>::value>::do_operation)
564 , type_id(index_of_type<T>::value)
565 {
566 static_assert(etl::is_one_of<etl::remove_cvref_t<T>, TTypes...>::value, "Unsupported type");
567
568 construct_in_place<etl::remove_cvref_t<T>>(data, etl::forward<T>(value));
569 }
570#include "diagnostic_pop.h"
571
572 //***************************************************************************
574 //***************************************************************************
576 template <typename T, typename... TArgs>
577 ETL_CONSTEXPR14 explicit variant(etl::in_place_type_t<T>, TArgs&&... args)
578 : operation(operation_type<etl::remove_cvref_t<T>, etl::is_copy_constructible<etl::remove_cvref_t<T>>::value, etl::is_move_constructible<etl::remove_cvref_t<T>>::value>::do_operation)
579 , type_id(index_of_type<T>::value)
580 {
581 static_assert(etl::is_one_of<etl::remove_cvref_t<T>, TTypes...>::value, "Unsupported type");
582
583 construct_in_place_args<etl::remove_cvref_t<T>>(data, etl::forward<TArgs>(args)...);
584 }
585#include "diagnostic_pop.h"
586
587 //***************************************************************************
589 //***************************************************************************
591 template <size_t Index, typename... TArgs>
592 ETL_CONSTEXPR14 explicit variant(etl::in_place_index_t<Index>, TArgs&&... args)
593 : type_id(Index)
594 {
595 using type = typename private_variant::parameter_pack<TTypes...>:: template type_from_index_t<Index>;
596 static_assert(etl::is_one_of<type, TTypes...> ::value, "Unsupported type");
597
598 construct_in_place_args<type>(data, etl::forward<TArgs>(args)...);
599
600 operation = operation_type<type, etl::is_copy_constructible<type>::value, etl::is_move_constructible<type>::value>::do_operation;
601 }
602#include "diagnostic_pop.h"
603
604#if ETL_HAS_INITIALIZER_LIST
605 //***************************************************************************
607 //***************************************************************************
609 template <typename T, typename U, typename... TArgs >
610 ETL_CONSTEXPR14 explicit variant(etl::in_place_type_t<T>, std::initializer_list<U> init, TArgs&&... args)
611 : operation(operation_type<etl::remove_cvref_t<T>, etl::is_copy_constructible<etl::remove_cvref_t<T>>::value, etl::is_move_constructible<etl::remove_cvref_t<T>>::value>::do_operation)
612 , type_id(index_of_type<T>::value)
613 {
614 static_assert(etl::is_one_of<etl::remove_cvref_t<T>, TTypes...> ::value, "Unsupported type");
615
616 construct_in_place_args<etl::remove_cvref_t<T>>(data, init, etl::forward<TArgs>(args)...);
617 }
618#include "diagnostic_pop.h"
619
620 //***************************************************************************
622 //***************************************************************************
624 template <size_t Index, typename U, typename... TArgs >
625 ETL_CONSTEXPR14 explicit variant(etl::in_place_index_t<Index>, std::initializer_list<U> init, TArgs&&... args)
626 : type_id(Index)
627 {
628 using type = typename private_variant::parameter_pack<TTypes...>:: template type_from_index_t<Index>;
629 static_assert(etl::is_one_of<type, TTypes...> ::value, "Unsupported type");
630
631 construct_in_place_args<type>(data, init, etl::forward<TArgs>(args)...);
632
633 operation = operation_type<type, etl::is_copy_constructible<type>::value, etl::is_move_constructible<type>::value>::do_operation;
634 }
635#include "diagnostic_pop.h"
636#endif
637
638 //***************************************************************************
641 //***************************************************************************
643 ETL_CONSTEXPR14 variant(const variant& other)
644 : operation(other.operation)
645 , type_id(other.type_id)
646 {
647 if (this != &other)
648 {
649 if (other.index() == variant_npos)
650 {
651 type_id = variant_npos;
652 }
653 else
654 {
655 operation(private_variant::Copy, data, other.data);
656 }
657 }
658 }
659#include "diagnostic_pop.h"
660
661 //***************************************************************************
664 //***************************************************************************
666 ETL_CONSTEXPR14 variant(variant&& other)
667 : operation(other.operation)
668 , type_id(other.type_id)
669 {
670 if (this != &other)
671 {
672 if (other.index() == variant_npos)
673 {
674 type_id = variant_npos;
675 }
676 else
677 {
678 operation(private_variant::Move, data, other.data);
679 }
680 }
681 else
682 {
683 type_id = variant_npos;
684 }
685 }
686#include "diagnostic_pop.h"
687
688 //***************************************************************************
690 //***************************************************************************
691 ~variant()
692 {
693 if (index() != variant_npos)
694 {
695 operation(private_variant::Destroy, data, nullptr);
696 }
697
698 operation = operation_type<void, false, false>::do_operation; // Null operation.
699 type_id = variant_npos;
700 }
701
702 //***************************************************************************
704 //***************************************************************************
705 template <typename T, typename... TArgs>
706 T& emplace(TArgs&&... args)
707 {
708 static_assert(etl::is_one_of<T, TTypes...>::value, "Unsupported type");
709
710 using type = etl::remove_cvref_t<T>;
711
712 operation(private_variant::Destroy, data, nullptr);
713
714 construct_in_place_args<type>(data, etl::forward<TArgs>(args)...);
715
716 operation = operation_type<type, etl::is_copy_constructible<type>::value, etl::is_move_constructible<type>::value>::do_operation;
717
718 type_id = etl::private_variant::parameter_pack<TTypes...>::template index_of_type<T>::value;
719
720 return *static_cast<T*>(data);
721 }
722
723#if ETL_HAS_INITIALIZER_LIST
724 //***************************************************************************
726 //***************************************************************************
727 template <typename T, typename U, typename... TArgs>
728 T& emplace(std::initializer_list<U> il, TArgs&&... args)
729 {
730 static_assert(etl::is_one_of<T, TTypes...>::value, "Unsupported type");
731
732 using type = etl::remove_cvref_t<T>;
733
734 operation(private_variant::Destroy, data, nullptr);
735
736 construct_in_place_args<type>(data, il, etl::forward<TArgs>(args)...);
737
738 operation = operation_type<type, etl::is_copy_constructible<type>::value, etl::is_move_constructible<type>::value>::do_operation;
739
740 type_id = etl::private_variant::parameter_pack<TTypes...>::template index_of_type<T>::value;
741
742 return *static_cast<T*>(data);
743 }
744#endif
745
746 //***************************************************************************
748 //***************************************************************************
749 template <size_t Index, typename... TArgs>
750 typename etl::variant_alternative<Index, variant<TArgs...>>::type& emplace(TArgs&&... args)
751 {
752 static_assert(Index < etl::private_variant::parameter_pack<TTypes...>::size, "Index out of range");
753
754 using type = type_from_index<Index>;
755
756 operation(private_variant::Destroy, data, nullptr);
757
758 construct_in_place_args<type>(data, etl::forward<TArgs>(args)...);
759
760 operation = operation_type<type, etl::is_copy_constructible<type>::value, etl::is_move_constructible<type>::value>::do_operation;
761
762 type_id = Index;
763
764 return *static_cast<type*>(data);
765 }
766
767#if ETL_HAS_INITIALIZER_LIST
768 //***************************************************************************
770 //***************************************************************************
771 template <size_t Index, typename U, typename... TArgs>
772 typename etl::variant_alternative<Index, variant<TArgs...>>::type& emplace(std::initializer_list<U> il, TArgs&&... args)
773 {
774 static_assert(Index < etl::private_variant::parameter_pack<TTypes...>::size, "Index out of range");
775
776 using type = type_from_index<Index>;
777
778 operation(private_variant::Destroy, data, nullptr);
779
780 construct_in_place_args<type>(data, il, etl::forward<TArgs>(args)...);
781
782 operation = operation_type<type, etl::is_copy_constructible<type>::value, etl::is_move_constructible<type>::value>::do_operation;
783
784 type_id = Index;
785
786 return *static_cast<type*>(data);
787 }
788#endif
789
790 //***************************************************************************
793 //***************************************************************************
794 template <typename T, etl::enable_if_t<!etl::is_same<etl::remove_cvref_t<T>, variant>::value, int> = 0>
795 variant& operator =(T&& value)
796 {
797 using type = etl::remove_cvref_t<T>;
798
799 static_assert(etl::is_one_of<type, TTypes...>::value, "Unsupported type");
800
801 operation(private_variant::Destroy, data, nullptr);
802
803 construct_in_place<type>(data, etl::forward<T>(value));
804
805 operation = operation_type<type, etl::is_copy_constructible<type>::value, etl::is_move_constructible<type>::value>::do_operation;
806 type_id = etl::private_variant::parameter_pack<TTypes...>::template index_of_type<type>::value;
807
808 return *this;
809 }
810
811 //***************************************************************************
814 //***************************************************************************
815 variant& operator =(const variant& other)
816 {
817 if (this != &other)
818 {
819 if (other.index() == variant_npos)
820 {
821 type_id = variant_npos;
822 }
823 else
824 {
825 operation(Destroy, data, nullptr);
826
827 operation = other.operation;
828 operation(Copy, data, other.data);
829
830 type_id = other.type_id;
831 }
832 }
833
834 return *this;
835 }
836
837 //***************************************************************************
840 //***************************************************************************
841 variant& operator =(variant&& other)
842 {
843 if (this != &other)
844 {
845 if (other.index() == variant_npos)
846 {
847 type_id = variant_npos;
848 }
849 else
850 {
851 operation(Destroy, data, nullptr);
852
853 operation = other.operation;
854 operation(Move, data, other.data);
855
856 type_id = other.type_id;
857 }
858 }
859
860 return *this;
861 }
862
863 //***************************************************************************
866 //***************************************************************************
867 constexpr bool valueless_by_exception() const noexcept
868 {
869 return type_id == variant_npos;
870 }
871
872 //***************************************************************************
874 //***************************************************************************
875 constexpr size_t index() const noexcept
876 {
877 return type_id;
878 }
879
880 //***************************************************************************
884 //***************************************************************************
885 template <typename T>
886 static constexpr bool is_supported_type()
887 {
888 return etl::is_one_of<etl::remove_cvref_t<T>, TTypes...>::value;
889 }
890
891 //***************************************************************************
895 //***************************************************************************
896 template <typename T, etl::enable_if_t<is_supported_type<T>(), int> = 0>
897 constexpr bool is_type() const noexcept
898 {
899 return (type_id == etl::private_variant::parameter_pack<TTypes...>::template index_of_type<T>::value);
900 }
901
902 //***************************************************************************
903 template <typename T, etl::enable_if_t<!is_supported_type<T>(), int> = 0>
904 constexpr bool is_type() const noexcept
905 {
906 return false;
907 }
908
909 //***************************************************************************
914 //***************************************************************************
915 constexpr bool is_same_type(const variant& other) const
916 {
917 return type_id == other.type_id;
918 }
919
920 //***************************************************************************
922 //***************************************************************************
923 void swap(variant& rhs) noexcept
924 {
925 variant temp(etl::move(*this));
926 *this = etl::move(rhs);
927 rhs = etl::move(temp);
928 }
929
930 //***************************************************************************
932 //***************************************************************************
933 template <typename TVisitor>
935 accept(TVisitor& v)
936 {
937#if ETL_USING_CPP17 && !defined(ETL_VARIANT_FORCE_CPP11)
938 do_visitor(v, etl::make_index_sequence<sizeof...(TTypes)>{});
939#else
940 do_visitor(v);
941#endif
942 }
943
944 //***************************************************************************
946 //***************************************************************************
947 template <typename TVisitor>
949 accept(TVisitor& v) const
950 {
951#if ETL_USING_CPP17 && !defined(ETL_VARIANT_FORCE_CPP11)
952 do_visitor(v, etl::make_index_sequence<sizeof...(TTypes)>{});
953#else
954 do_visitor(v);
955#endif
956 }
957
958 //***************************************************************************
960 //***************************************************************************
961 template <typename TVisitor>
963 accept(TVisitor& v)
964 {
965#if ETL_USING_CPP17 && !defined(ETL_VARIANT_FORCE_CPP11)
966 do_operator(v, etl::make_index_sequence<sizeof...(TTypes)>{});
967#else
968 do_operator(v);
969#endif
970 }
971
972 //***************************************************************************
974 //***************************************************************************
975 template <typename TVisitor>
977 accept(TVisitor& v) const
978 {
979#if ETL_USING_CPP17 && !defined(ETL_VARIANT_FORCE_CPP11)
980 do_operator(v, etl::make_index_sequence<sizeof...(TTypes)>{});
981#else
982 do_operator(v);
983#endif
984 }
985
986 //***************************************************************************
989 //***************************************************************************
990 template <typename TVisitor>
991#if !defined(ETL_IN_UNIT_TEST)
992 ETL_DEPRECATED_REASON("Replace with accept()")
993#endif
994 void accept_visitor(TVisitor& v)
995 {
996#if ETL_USING_CPP17 && !defined(ETL_VARIANT_FORCE_CPP11)
997 do_visitor(v, etl::make_index_sequence<sizeof...(TTypes)>{});
998#else
999 do_visitor(v);
1000#endif
1001 }
1002
1003 //***************************************************************************
1006 //***************************************************************************
1007 template <typename TVisitor>
1008#if !defined(ETL_IN_UNIT_TEST)
1009 ETL_DEPRECATED_REASON("Replace with accept()")
1010#endif
1011 void accept_visitor(TVisitor& v) const
1012 {
1013#if ETL_USING_CPP17 && !defined(ETL_VARIANT_FORCE_CPP11)
1014 do_visitor(v, etl::make_index_sequence<sizeof...(TTypes)>{});
1015#else
1016 do_visitor(v);
1017#endif
1018 }
1019
1020 //***************************************************************************
1023 //***************************************************************************
1024 template <typename TVisitor>
1025#if !defined(ETL_IN_UNIT_TEST)
1026 ETL_DEPRECATED_REASON("Replace with accept()")
1027#endif
1028 void accept_functor(TVisitor& v)
1029 {
1030#if ETL_USING_CPP17 && !defined(ETL_VARIANT_FORCE_CPP11)
1031 do_operator(v, etl::make_index_sequence<sizeof...(TTypes)>{});
1032#else
1033 do_operator(v);
1034#endif
1035 }
1036
1037 //***************************************************************************
1040 //***************************************************************************
1041 template <typename TVisitor>
1042#if !defined(ETL_IN_UNIT_TEST)
1043 ETL_DEPRECATED_REASON("Replace with accept()")
1044#endif
1045 void accept_functor(TVisitor& v) const
1046 {
1047#if ETL_USING_CPP17 && !defined(ETL_VARIANT_FORCE_CPP11)
1048 do_operator(v, etl::make_index_sequence<sizeof...(TTypes)>{});
1049#else
1050 do_operator(v);
1051#endif
1052 }
1053
1054 private:
1055
1057 using operation_function = void(*)(int, char*, const char*);
1058
1059 //***************************************************************************
1061 //***************************************************************************
1062 template <typename T>
1063 static void construct_in_place(char* pstorage, const T& value)
1064 {
1065 using type = etl::remove_cvref_t<T>;
1066
1067 ::new (pstorage) type(value);
1068 }
1069
1070 //***************************************************************************
1072 //***************************************************************************
1073 template <typename T>
1074 static void construct_in_place(char* pstorage, T&& value)
1075 {
1076 using type = etl::remove_cvref_t<T>;
1077
1078 ::new (pstorage) type(etl::move(value));
1079 }
1080
1081 //***************************************************************************
1083 //***************************************************************************
1084 template <typename T, typename... TArgs>
1085 static void construct_in_place_args(char* pstorage, TArgs&&... args)
1086 {
1087 using type = etl::remove_cvref_t<T>;
1088
1089 ::new (pstorage) type(etl::forward<TArgs>(args)...);
1090 }
1091
1092 //***************************************************************************
1094 //***************************************************************************
1095 template <typename T>
1096 static void default_construct_in_place(char* pstorage)
1097 {
1098 using type = etl::remove_cvref_t<T>;
1099
1100 ::new (pstorage) type();
1101 }
1102
1103#if ETL_USING_CPP17 && !defined(ETL_VARIANT_FORCE_CPP11)
1104 //***************************************************************************
1106 //***************************************************************************
1107 template <typename TVisitor, size_t... I>
1108 void do_visitor(TVisitor& visitor, etl::index_sequence<I...>)
1109 {
1110 (attempt_visitor<I>(visitor) || ...);
1111 }
1112
1113 //***************************************************************************
1115 //***************************************************************************
1116 template <typename TVisitor, size_t... I>
1117 void do_visitor(TVisitor& visitor, etl::index_sequence<I...>) const
1118 {
1119 (attempt_visitor<I>(visitor) || ...);
1120 }
1121#else
1122 //***************************************************************************
1124 //***************************************************************************
1125 template <typename TVisitor>
1126 void do_visitor(TVisitor& visitor)
1127 {
1128 switch (index())
1129 {
1130 case 0: { visitor.visit(etl::get<0>(*this)); break; }
1131 case 1: { visitor.visit(etl::get<1>(*this)); break; }
1132 case 2: { visitor.visit(etl::get<2>(*this)); break; }
1133 case 3: { visitor.visit(etl::get<3>(*this)); break; }
1134 case 4: { visitor.visit(etl::get<4>(*this)); break; }
1135 case 5: { visitor.visit(etl::get<5>(*this)); break; }
1136 case 6: { visitor.visit(etl::get<6>(*this)); break; }
1137 case 7: { visitor.visit(etl::get<7>(*this)); break; }
1138#if !defined(ETL_VARIANT_CPP11_MAX_8_TYPES)
1139 case 8: { visitor.visit(etl::get<8>(*this)); break; }
1140 case 9: { visitor.visit(etl::get<9>(*this)); break; }
1141 case 10: { visitor.visit(etl::get<10>(*this)); break; }
1142 case 11: { visitor.visit(etl::get<11>(*this)); break; }
1143 case 12: { visitor.visit(etl::get<12>(*this)); break; }
1144 case 13: { visitor.visit(etl::get<13>(*this)); break; }
1145 case 14: { visitor.visit(etl::get<14>(*this)); break; }
1146 case 15: { visitor.visit(etl::get<15>(*this)); break; }
1147#if !defined(ETL_VARIANT_CPP11_MAX_16_TYPES)
1148 case 16: { visitor.visit(etl::get<16>(*this)); break; }
1149 case 17: { visitor.visit(etl::get<17>(*this)); break; }
1150 case 18: { visitor.visit(etl::get<18>(*this)); break; }
1151 case 19: { visitor.visit(etl::get<19>(*this)); break; }
1152 case 20: { visitor.visit(etl::get<20>(*this)); break; }
1153 case 21: { visitor.visit(etl::get<21>(*this)); break; }
1154 case 22: { visitor.visit(etl::get<22>(*this)); break; }
1155 case 23: { visitor.visit(etl::get<23>(*this)); break; }
1156#if !defined(ETL_VARIANT_CPP11_MAX_24_TYPES)
1157 case 24: { visitor.visit(etl::get<24>(*this)); break; }
1158 case 25: { visitor.visit(etl::get<25>(*this)); break; }
1159 case 26: { visitor.visit(etl::get<26>(*this)); break; }
1160 case 27: { visitor.visit(etl::get<27>(*this)); break; }
1161 case 28: { visitor.visit(etl::get<28>(*this)); break; }
1162 case 29: { visitor.visit(etl::get<29>(*this)); break; }
1163 case 30: { visitor.visit(etl::get<30>(*this)); break; }
1164 case 31: { visitor.visit(etl::get<31>(*this)); break; }
1165#endif
1166#endif
1167#endif
1168 default: break;
1169 }
1170 }
1171
1172 //***************************************************************************
1174 //***************************************************************************
1175 template <typename TVisitor>
1176 void do_visitor(TVisitor& visitor) const
1177 {
1178 switch (index())
1179 {
1180 case 0: { visitor.visit(etl::get<0>(*this)); break; }
1181 case 1: { visitor.visit(etl::get<1>(*this)); break; }
1182 case 2: { visitor.visit(etl::get<2>(*this)); break; }
1183 case 3: { visitor.visit(etl::get<3>(*this)); break; }
1184 case 4: { visitor.visit(etl::get<4>(*this)); break; }
1185 case 5: { visitor.visit(etl::get<5>(*this)); break; }
1186 case 6: { visitor.visit(etl::get<6>(*this)); break; }
1187 case 7: { visitor.visit(etl::get<7>(*this)); break; }
1188#if !defined(ETL_VARIANT_CPP11_MAX_8_TYPES)
1189 case 8: { visitor.visit(etl::get<8>(*this)); break; }
1190 case 9: { visitor.visit(etl::get<9>(*this)); break; }
1191 case 10: { visitor.visit(etl::get<10>(*this)); break; }
1192 case 11: { visitor.visit(etl::get<11>(*this)); break; }
1193 case 12: { visitor.visit(etl::get<12>(*this)); break; }
1194 case 13: { visitor.visit(etl::get<13>(*this)); break; }
1195 case 14: { visitor.visit(etl::get<14>(*this)); break; }
1196 case 15: { visitor.visit(etl::get<15>(*this)); break; }
1197#if !defined(ETL_VARIANT_CPP11_MAX_16_TYPES)
1198 case 16: { visitor.visit(etl::get<16>(*this)); break; }
1199 case 17: { visitor.visit(etl::get<17>(*this)); break; }
1200 case 18: { visitor.visit(etl::get<18>(*this)); break; }
1201 case 19: { visitor.visit(etl::get<19>(*this)); break; }
1202 case 20: { visitor.visit(etl::get<20>(*this)); break; }
1203 case 21: { visitor.visit(etl::get<21>(*this)); break; }
1204 case 22: { visitor.visit(etl::get<22>(*this)); break; }
1205 case 23: { visitor.visit(etl::get<23>(*this)); break; }
1206#if !defined(ETL_VARIANT_CPP11_MAX_24_TYPES)
1207 case 24: { visitor.visit(etl::get<24>(*this)); break; }
1208 case 25: { visitor.visit(etl::get<25>(*this)); break; }
1209 case 26: { visitor.visit(etl::get<26>(*this)); break; }
1210 case 27: { visitor.visit(etl::get<27>(*this)); break; }
1211 case 28: { visitor.visit(etl::get<28>(*this)); break; }
1212 case 29: { visitor.visit(etl::get<29>(*this)); break; }
1213 case 30: { visitor.visit(etl::get<30>(*this)); break; }
1214 case 31: { visitor.visit(etl::get<31>(*this)); break; }
1215#endif
1216#endif
1217#endif
1218 default: break;
1219 }
1220 }
1221#endif
1222
1223 //***************************************************************************
1225 //***************************************************************************
1226 template <size_t Index, typename TVisitor>
1227 bool attempt_visitor(TVisitor& visitor)
1228 {
1229 if (Index == index())
1230 {
1231 // Workaround for MSVC (2023/05/13)
1232 // It doesn't compile 'visitor.visit(etl::get<Index>(*this))' correctly for C++17 & C++20.
1233 // Changed all of the instances for consistency.
1234 auto& v = etl::get<Index>(*this);
1235 visitor.visit(v);
1236 return true;
1237 }
1238 else
1239 {
1240 return false;
1241 }
1242 }
1243
1244 //***************************************************************************
1246 //***************************************************************************
1247 template <size_t Index, typename TVisitor>
1248 bool attempt_visitor(TVisitor& visitor) const
1249 {
1250 if (Index == index())
1251 {
1252 // Workaround for MSVC (2023/05/13)
1253 // It doesn't compile 'visitor.visit(etl::get<Index>(*this))' correctly for C++17 & C++20.
1254 // Changed all of the instances for consistency.
1255 auto& v = etl::get<Index>(*this);
1256 visitor.visit(v);
1257 return true;
1258 }
1259 else
1260 {
1261 return false;
1262 }
1263 }
1264
1265#if ETL_USING_CPP17 && !defined(ETL_VARIANT_FORCE_CPP11)
1266 //***************************************************************************
1268 //***************************************************************************
1269 template <typename TVisitor, size_t... I>
1270 void do_operator(TVisitor& visitor, etl::index_sequence<I...>)
1271 {
1272 (attempt_operator<I>(visitor) || ...);
1273 }
1274
1275 //***************************************************************************
1277 //***************************************************************************
1278 template <typename TVisitor, size_t... I>
1279 void do_operator(TVisitor& visitor, etl::index_sequence<I...>) const
1280 {
1281 (attempt_operator<I>(visitor) || ...);
1282 }
1283#else
1284 //***************************************************************************
1286 //***************************************************************************
1287 template <typename TVisitor>
1288 void do_operator(TVisitor& visitor)
1289 {
1290#if defined(ETL_VARIANT_CPP11_MAX_8_TYPES)
1291 ETL_STATIC_ASSERT(sizeof...(TTypes) <= 8U, "ETL_VARIANT_CPP11_MAX_8_TYPES - Only a maximum of 8 types are allowed in this variant");
1292#endif
1293
1294#if defined(ETL_VARIANT_CPP11_MAX_16_TYPES)
1295 ETL_STATIC_ASSERT(sizeof...(TTypes) <= 16U, "ETL_VARIANT_CPP11_MAX_16_TYPES - Only a maximum of 16 types are allowed in this variant");
1296#endif
1297
1298#if defined(ETL_VARIANT_CPP11_MAX_24_TYPES)
1299 ETL_STATIC_ASSERT(sizeof...(TTypes) <= 24U, "ETL_VARIANT_CPP11_MAX_24_TYPES - Only a maximum of 24 types are allowed in this variant");
1300#endif
1301
1302 ETL_STATIC_ASSERT(sizeof...(TTypes) <= 32U, "A maximum of 32 types are allowed in this variant");
1303
1304 switch (index())
1305 {
1306 case 0: visitor(etl::get<0>(*this)); break;
1307 case 1: visitor(etl::get<1>(*this)); break;
1308 case 2: visitor(etl::get<2>(*this)); break;
1309 case 3: visitor(etl::get<3>(*this)); break;
1310 case 4: visitor(etl::get<4>(*this)); break;
1311 case 5: visitor(etl::get<5>(*this)); break;
1312 case 6: visitor(etl::get<6>(*this)); break;
1313 case 7: visitor(etl::get<7>(*this)); break;
1314#if !defined(ETL_VARIANT_CPP11_MAX_8_TYPES)
1315 case 8: visitor(etl::get<8>(*this)); break;
1316 case 9: visitor(etl::get<9>(*this)); break;
1317 case 10: visitor(etl::get<10>(*this)); break;
1318 case 11: visitor(etl::get<11>(*this)); break;
1319 case 12: visitor(etl::get<12>(*this)); break;
1320 case 13: visitor(etl::get<13>(*this)); break;
1321 case 14: visitor(etl::get<14>(*this)); break;
1322 case 15: visitor(etl::get<15>(*this)); break;
1323#if !defined(ETL_VARIANT_CPP11_MAX_16_TYPES)
1324 case 16: visitor(etl::get<16>(*this)); break;
1325 case 17: visitor(etl::get<17>(*this)); break;
1326 case 18: visitor(etl::get<18>(*this)); break;
1327 case 19: visitor(etl::get<19>(*this)); break;
1328 case 20: visitor(etl::get<20>(*this)); break;
1329 case 21: visitor(etl::get<21>(*this)); break;
1330 case 22: visitor(etl::get<22>(*this)); break;
1331 case 23: visitor(etl::get<23>(*this)); break;
1332#if !defined(ETL_VARIANT_CPP11_MAX_24_TYPES)
1333 case 24: visitor(etl::get<24>(*this)); break;
1334 case 25: visitor(etl::get<25>(*this)); break;
1335 case 26: visitor(etl::get<26>(*this)); break;
1336 case 27: visitor(etl::get<27>(*this)); break;
1337 case 28: visitor(etl::get<28>(*this)); break;
1338 case 29: visitor(etl::get<29>(*this)); break;
1339 case 30: visitor(etl::get<30>(*this)); break;
1340 case 31: visitor(etl::get<31>(*this)); break;
1341#endif
1342#endif
1343#endif
1344 default: break;
1345 }
1346 }
1347
1348 //***************************************************************************
1350 //***************************************************************************
1351 template <typename TVisitor>
1352 void do_operator(TVisitor& visitor) const
1353 {
1354#if defined(ETL_VARIANT_CPP11_MAX_8_TYPES)
1355 ETL_STATIC_ASSERT(sizeof...(TTypes) <= 8U, "ETL_VARIANT_CPP11_MAX_8_TYPES - Only a maximum of 8 types are allowed in this variant");
1356#endif
1357
1358#if defined(ETL_VARIANT_CPP11_MAX_16_TYPES)
1359 ETL_STATIC_ASSERT(sizeof...(TTypes) <= 16U, "ETL_VARIANT_CPP11_MAX_16_TYPES - Only a maximum of 16 types are allowed in this variant");
1360#endif
1361
1362#if defined(ETL_VARIANT_CPP11_MAX_24_TYPES)
1363 ETL_STATIC_ASSERT(sizeof...(TTypes) <= 24U, "ETL_VARIANT_CPP11_MAX_24_TYPES - Only a maximum of 24 types are allowed in this variant");
1364#endif
1365
1366 ETL_STATIC_ASSERT(sizeof...(TTypes) <= 32U, "A maximum of 32 types are allowed in this variant");
1367
1368 switch (index())
1369 {
1370 case 0: visitor(etl::get<0>(*this)); break;
1371 case 1: visitor(etl::get<1>(*this)); break;
1372 case 2: visitor(etl::get<2>(*this)); break;
1373 case 3: visitor(etl::get<3>(*this)); break;
1374 case 4: visitor(etl::get<4>(*this)); break;
1375 case 5: visitor(etl::get<5>(*this)); break;
1376 case 6: visitor(etl::get<6>(*this)); break;
1377 case 7: visitor(etl::get<7>(*this)); break;
1378#if !defined(ETL_VARIANT_CPP11_MAX_8_TYPES)
1379 case 8: visitor(etl::get<8>(*this)); break;
1380 case 9: visitor(etl::get<9>(*this)); break;
1381 case 10: visitor(etl::get<10>(*this)); break;
1382 case 11: visitor(etl::get<11>(*this)); break;
1383 case 12: visitor(etl::get<12>(*this)); break;
1384 case 13: visitor(etl::get<13>(*this)); break;
1385 case 14: visitor(etl::get<14>(*this)); break;
1386 case 15: visitor(etl::get<15>(*this)); break;
1387#if !defined(ETL_VARIANT_CPP11_MAX_16_TYPES)
1388 case 16: visitor(etl::get<16>(*this)); break;
1389 case 17: visitor(etl::get<17>(*this)); break;
1390 case 18: visitor(etl::get<18>(*this)); break;
1391 case 19: visitor(etl::get<19>(*this)); break;
1392 case 20: visitor(etl::get<20>(*this)); break;
1393 case 21: visitor(etl::get<21>(*this)); break;
1394 case 22: visitor(etl::get<22>(*this)); break;
1395 case 23: visitor(etl::get<23>(*this)); break;
1396#if !defined(ETL_VARIANT_CPP11_MAX_24_TYPES)
1397 case 24: visitor(etl::get<24>(*this)); break;
1398 case 25: visitor(etl::get<25>(*this)); break;
1399 case 26: visitor(etl::get<26>(*this)); break;
1400 case 27: visitor(etl::get<27>(*this)); break;
1401 case 28: visitor(etl::get<28>(*this)); break;
1402 case 29: visitor(etl::get<29>(*this)); break;
1403 case 30: visitor(etl::get<30>(*this)); break;
1404 case 31: visitor(etl::get<31>(*this)); break;
1405#endif
1406#endif
1407#endif
1408 default: break;
1409 }
1410 }
1411#endif
1412
1413 //***************************************************************************
1415 //***************************************************************************
1416 template <size_t Index, typename TVisitor>
1417 bool attempt_operator(TVisitor& visitor)
1418 {
1419 if (Index == index())
1420 {
1421 auto& v = etl::get<Index>(*this);
1422 visitor(v);
1423 return true;
1424 }
1425 else
1426 {
1427 return false;
1428 }
1429 }
1430
1431 //***************************************************************************
1433 //***************************************************************************
1434 template <size_t Index, typename TVisitor>
1435 bool attempt_operator(TVisitor& visitor) const
1436 {
1437 if (Index == index())
1438 {
1439 auto& v = etl::get<Index>(*this);
1440 visitor(v);
1441 return true;
1442 }
1443 else
1444 {
1445 return false;
1446 }
1447 }
1448
1449 //***************************************************************************
1452 //***************************************************************************
1454
1455 //***************************************************************************
1457 //***************************************************************************
1458 operation_function operation;
1459
1460 //***************************************************************************
1462 //***************************************************************************
1463 size_t type_id;
1464 };
1465
1466 //***************************************************************************
1468 //***************************************************************************
1469 template <typename T, typename... TTypes>
1470 ETL_CONSTEXPR14 bool holds_alternative(const etl::variant<TTypes...>& v) noexcept
1471 {
1472 constexpr size_t Index = etl::private_variant::parameter_pack<TTypes...>::template index_of_type<T>::value;
1473
1474 return (Index == variant_npos) ? false : (v.index() == Index);
1475 }
1476
1477 //***************************************************************************
1479 //***************************************************************************
1480 template <size_t Index, typename... TTypes>
1481 ETL_CONSTEXPR14 bool holds_alternative(const etl::variant<TTypes...>& v) noexcept
1482 {
1483 return (Index == v.index());
1484 }
1485
1486 //***************************************************************************
1488 //***************************************************************************
1489 template <typename... TTypes>
1490 ETL_CONSTEXPR14 bool holds_alternative(size_t index, const etl::variant<TTypes...>& v) noexcept
1491 {
1492 return (index == v.index());
1493 }
1494
1495 //***************************************************************************
1497 //***************************************************************************
1498 template <size_t Index, typename... TTypes>
1499 ETL_CONSTEXPR14 etl::variant_alternative_t<Index, etl::variant<TTypes...>>&
1501 {
1502#if ETL_USING_CPP17 && !defined(ETL_VARIANT_FORCE_CPP11)
1503 static_assert(Index < sizeof...(TTypes), "Index out of range");
1504#endif
1505
1506 ETL_ASSERT(Index == v.index(), ETL_ERROR(etl::variant_incorrect_type_exception));
1507
1508 using type = etl::variant_alternative_t<Index, etl::variant<TTypes...>>;
1509
1510 return *static_cast<type*>(v.data);
1511 }
1512
1513 //***********************************
1514 template <size_t Index, typename... TTypes>
1515 ETL_CONSTEXPR14 etl::variant_alternative_t<Index, etl::variant<TTypes...>>&&
1517 {
1518#if ETL_USING_CPP17 && !defined(ETL_VARIANT_FORCE_CPP11)
1519 static_assert(Index < sizeof...(TTypes), "Index out of range");
1520#endif
1521
1522 using type = etl::variant_alternative_t<Index, etl::variant<TTypes...>>;
1523
1524 return etl::move(*static_cast<type*>(v.data));
1525 }
1526
1527 //***********************************
1528 template <size_t Index, typename... TTypes>
1529 ETL_CONSTEXPR14 const etl::variant_alternative_t<Index, const etl::variant<TTypes...>>&
1531 {
1532#if ETL_USING_CPP17 && !defined(ETL_VARIANT_FORCE_CPP11)
1533 static_assert(Index < sizeof...(TTypes), "Index out of range");
1534#endif
1535
1536 ETL_ASSERT(Index == v.index(), ETL_ERROR(etl::variant_incorrect_type_exception));
1537
1538 using type = etl::variant_alternative_t<Index, etl::variant<TTypes...>>;
1539
1540 return *static_cast<const type*>(v.data);
1541 }
1542
1543 //***********************************
1544 template <size_t Index, typename... TTypes>
1545 ETL_CONSTEXPR14 const etl::variant_alternative_t<Index, const etl::variant<TTypes...>>&&
1546 get(const etl::variant<TTypes...>&& v)
1547 {
1548#if ETL_USING_CPP17 & !defined(ETL_VARIANT_FORCE_CPP11)
1549 static_assert(Index < sizeof...(TTypes), "Index out of range");
1550#endif
1551
1552 ETL_ASSERT(Index == v.index(), ETL_ERROR(etl::variant_incorrect_type_exception));
1553
1554 using type = etl::variant_alternative_t<Index, etl::variant<TTypes...>>;
1555
1556 return etl::move(*static_cast<const type*>(v.data));
1557 }
1558
1559 //***********************************
1560 template <typename T, typename... TTypes>
1561 ETL_CONSTEXPR14 T& get(etl::variant<TTypes...>& v)
1562 {
1563 constexpr size_t Index = etl::private_variant::parameter_pack<TTypes...>::template index_of_type<T>::value;
1564
1565 return get<Index>(v);
1566 }
1567
1568 //***********************************
1569 template <typename T, typename... TTypes>
1570 ETL_CONSTEXPR14 T&& get(etl::variant<TTypes...>&& v)
1571 {
1572 constexpr size_t Index = etl::private_variant::parameter_pack<TTypes...>::template index_of_type<T>::value;
1573
1574 return get<Index>(etl::move(v));
1575 }
1576
1577 //***********************************
1578 template <typename T, typename... TTypes>
1579 ETL_CONSTEXPR14 const T& get(const etl::variant<TTypes...>& v)
1580 {
1581 constexpr size_t Index = etl::private_variant::parameter_pack<TTypes...>::template index_of_type<T>::value;
1582
1583 return get<Index>(v);
1584 }
1585
1586 //***********************************
1587 template <typename T, typename... TTypes>
1588 ETL_CONSTEXPR14 const T&& get(const etl::variant<TTypes...>&& v)
1589 {
1590 constexpr size_t Index = etl::private_variant::parameter_pack<TTypes...>::template index_of_type<T>::value;
1591
1592 return get<Index>(etl::move(v));
1593 }
1594
1595 //***************************************************************************
1597 //***************************************************************************
1598 template< size_t Index, typename... TTypes >
1599 ETL_CONSTEXPR14 etl::add_pointer_t<etl::variant_alternative_t<Index, etl::variant<TTypes...>>>
1600 get_if(etl::variant<TTypes...>* pv) noexcept
1601 {
1602 if ((pv != nullptr) && (pv->index() == Index))
1603 {
1604 return &etl::get<Index>(*pv);
1605 }
1606 else
1607 {
1608 return nullptr;
1609 }
1610 }
1611
1612 //***********************************
1613 template< size_t Index, typename... TTypes >
1614 ETL_CONSTEXPR14 etl::add_pointer_t<const etl::variant_alternative_t<Index, etl::variant<TTypes...>>>
1615 get_if(const etl::variant<TTypes...>* pv) noexcept
1616 {
1617 if ((pv != nullptr) && (pv->index() == Index))
1618 {
1619 return &etl::get<Index>(*pv);
1620 }
1621 else
1622 {
1623 return nullptr;
1624 }
1625 }
1626
1627 //***********************************
1628 template< class T, typename... TTypes >
1629 ETL_CONSTEXPR14 etl::add_pointer_t<T> get_if(etl::variant<TTypes...>* pv) noexcept
1630 {
1631 constexpr size_t Index = etl::private_variant::parameter_pack<TTypes...>::template index_of_type<T>::value;
1632
1633 if ((pv != nullptr) && (pv->index() == Index))
1634 {
1635 return &etl::get<Index>(*pv);
1636 }
1637 else
1638 {
1639 return nullptr;
1640 }
1641 }
1642
1643 //***********************************
1644 template< typename T, typename... TTypes >
1645 ETL_CONSTEXPR14 etl::add_pointer_t<const T> get_if(const etl::variant<TTypes...>* pv) noexcept
1646 {
1647 constexpr size_t Index = etl::private_variant::parameter_pack<TTypes...>::template index_of_type<T>::value;
1648
1649 if ((pv != nullptr) && (pv->index() == Index))
1650 {
1651 return &etl::get<Index>(*pv);
1652 }
1653 else
1654 {
1655 return nullptr;
1656 }
1657 }
1658
1659 //***************************************************************************
1661 //***************************************************************************
1662 template <typename... TTypes>
1664 {
1665 lhs.swap(rhs);
1666 }
1667
1668 //***************************************************************************
1670 //***************************************************************************
1671 template <typename T>
1672 struct variant_size;
1673
1674 template <typename... TTypes>
1675 struct variant_size<etl::variant<TTypes...>>
1676 : etl::integral_constant<size_t, sizeof...(TTypes)>
1677 {
1678 };
1679
1680 template <typename T>
1681 struct variant_size<const T>
1682 : etl::integral_constant<size_t, variant_size<T>::value>
1683 {
1684 };
1685
1686#if ETL_USING_CPP17
1687 template <typename... TTypes>
1688 inline constexpr size_t variant_size_v = variant_size<TTypes...>::value;
1689#endif
1690
1691 //***************************************************************************
1693 //***************************************************************************
1694 namespace private_variant
1695 {
1696 template <typename TRet, typename TCallable, typename TVariant, size_t tIndex, typename TNext, typename... TVariants>
1697 static ETL_CONSTEXPR14 TRet do_visit_single(TCallable&& f, TVariant&& v, TNext&&, TVariants&&... vs);
1698
1699 //***************************************************************************
1703 //***************************************************************************
1704 struct visit_auto_return
1705 {
1706 };
1707
1708 //***************************************************************************
1711 //***************************************************************************
1712 template <typename TCallable, typename... Ts>
1713 struct single_visit_result_type
1714 {
1715 using type = decltype(declval<TCallable>()(declval<Ts>()...));
1716 };
1717
1718 template <typename TCallable, typename... Ts>
1719 using single_visit_result_type_t = typename single_visit_result_type<TCallable, Ts...>::type;
1720
1721 //***************************************************************************
1724 //***************************************************************************
1725 template <typename TVar, typename T>
1726 using rlref_copy = conditional_t<is_reference<TVar>::value, T&, T&&>;
1727
1728 //***************************************************************************
1735 //***************************************************************************
1736 template <template <typename...> class, typename...>
1737 struct visit_result_helper;
1738
1739 template <template <typename...> class TToInject, size_t... tAltIndices, typename TCur>
1740 struct visit_result_helper<TToInject, index_sequence<tAltIndices...>, TCur>
1741 {
1742 template <size_t tIndex>
1743 using var_type = rlref_copy<TCur,
1744 variant_alternative_t<tIndex, remove_reference_t<TCur> > >;
1745
1746 using type = common_type_t<TToInject<var_type<tAltIndices> >...>;
1747 };
1748
1749 template <template <typename...> class TToInject, size_t... tAltIndices, typename TCur, typename TNext, typename... TVs>
1750 struct visit_result_helper<TToInject, index_sequence<tAltIndices...>, TCur, TNext, TVs...>
1751 {
1752 template <size_t tIndex>
1753 using var_type = rlref_copy<TCur, variant_alternative_t<tIndex, remove_reference_t<TCur> > >;
1754
1755 template <size_t tIndex>
1756 struct next_inject_wrap
1757 {
1758 template <typename... TNextInj>
1759 using next_inject = TToInject<var_type<tIndex>, TNextInj...>;
1760 using recursive_result = typename visit_result_helper<next_inject, make_index_sequence<variant_size<remove_reference_t<TNext> >::value>, TNext, TVs...>::type;
1761 };
1762
1763 using type = common_type_t<typename next_inject_wrap<tAltIndices>::recursive_result...>;
1764 };
1765
1766 //***************************************************************************
1770 //***************************************************************************
1771 template <typename TRet, typename...>
1772 struct visit_result
1773 {
1774 using type = TRet;
1775 };
1776
1777 template <typename TCallable, typename T1, typename... Ts>
1778 struct visit_result<visit_auto_return, TCallable, T1, Ts...>
1779 {
1780 // bind TCallable to the first argument in this variadic alias.
1781 template <typename... Ts2>
1782 using single_res = single_visit_result_type_t<TCallable, Ts2...>;
1783 using type = typename visit_result_helper<single_res, make_index_sequence<variant_size<remove_reference_t<T1> >::value>, T1, Ts...>::type;
1784 };
1785
1786 template <typename... Ts>
1787 using visit_result_t = typename visit_result<Ts...>::type;
1788
1789 //***************************************************************************
1792 //***************************************************************************
1793 template <typename TRet, typename TCallable, typename TVariant, size_t tIndex>
1794 constexpr TRet do_visit_single(TCallable&& f, TVariant&& v)
1795 {
1796 return static_cast<TCallable&&>(f)(etl::get<tIndex>(static_cast<TVariant&&>(v)));
1797 }
1798
1799 //***************************************************************************
1803 //***************************************************************************
1804 template <typename TRet, typename TCallable, typename TCurVariant, typename... TVarRest>
1805 struct do_visit_helper
1806 {
1807 using function_pointer = add_pointer_t<TRet(TCallable&&, TCurVariant&&, TVarRest&&...)>;
1808
1809 template <size_t tIndex>
1810 static constexpr function_pointer fptr() noexcept
1811 {
1812 return &do_visit_single<TRet, TCallable, TCurVariant, tIndex, TVarRest...>;
1813 }
1814 };
1815
1816 //***************************************************************************
1818 //***************************************************************************
1819 template <typename TRet, typename TCallable, typename TVariant, size_t... tIndices, typename... TVarRest>
1820 static ETL_CONSTEXPR14 TRet do_visit(TCallable&& f, TVariant&& v, index_sequence<tIndices...>, TVarRest&&... variants)
1821 {
1822 ETL_ASSERT(!v.valueless_by_exception(), ETL_ERROR(bad_variant_access));
1823
1824 using helper_t = do_visit_helper<TRet, TCallable, TVariant, TVarRest...>;
1825 using func_ptr = typename helper_t::function_pointer;
1826
1827 constexpr func_ptr jmp_table[]
1828 {
1829 helper_t::template fptr<tIndices>()...
1830 };
1831
1832 return jmp_table[v.index()](static_cast<TCallable&&>(f), static_cast<TVariant&&>(v), static_cast<TVarRest&&>(variants)...);
1833 }
1834
1835 template <typename TRet, typename TCallable, typename TVariant, typename... TVs>
1836 static ETL_CONSTEXPR14 TRet visit(TCallable&& f, TVariant&& v, TVs&&... vs)
1837 {
1838 constexpr size_t variants = etl::variant_size<typename remove_reference<TVariant>::type>::value;
1839 return private_variant::do_visit<TRet>(static_cast<TCallable&&>(f),
1840 static_cast<TVariant&&>(v),
1841 make_index_sequence<variants>{},
1842 static_cast<TVs&&>(vs)...);
1843 }
1844
1845 //***************************************************************************
1848 //***************************************************************************
1849 template <typename TRet, typename TCallable, typename TVariant, size_t tIndex>
1850 class constexpr_visit_closure
1851 {
1852 add_pointer_t<TCallable> callable_;
1853 add_pointer_t<TVariant> variant_;
1854
1855 public:
1856 constexpr constexpr_visit_closure(TCallable&& c, TVariant&& v)
1857 : callable_(&c), variant_(&v)
1858 {
1859 }
1860
1861 template <typename... Ts>
1862 ETL_CONSTEXPR14 TRet operator()(Ts&&... args) const
1863 {
1864 return static_cast<TCallable&&>(*callable_)(get<tIndex>(static_cast<TVariant&&>(*variant_)), static_cast<Ts&&>(args)...);
1865 }
1866 };
1867
1868 template <typename TRet, typename TCallable, typename TVariant, size_t tIndex, typename TNext, typename... TVariants>
1869 static ETL_CONSTEXPR14 TRet do_visit_single(TCallable&& f, TVariant&& v, TNext&& next, TVariants&&... vs)
1870 {
1871 return private_variant::visit<TRet>(constexpr_visit_closure<TRet, TCallable, TVariant, tIndex>(static_cast<TCallable&&>(f), static_cast<TVariant&&>(v)),
1872 static_cast<TNext&&>(next), static_cast<TVariants&&>(vs)...);
1873 }
1874
1875 } // namespace private_variant
1876
1877 //***************************************************************************
1880 //***************************************************************************
1881 template <typename TRet = private_variant::visit_auto_return, typename... TVariants, typename TCallable, typename TDeducedReturn = private_variant::visit_result_t<TRet, TCallable, TVariants...> >
1882 static ETL_CONSTEXPR14 TDeducedReturn visit(TCallable&& f, TVariants&&... vs)
1883 {
1884 return private_variant::visit<TDeducedReturn>(static_cast<TCallable&&>(f), static_cast<TVariants&&>(vs)...);
1885 }
1886
1887 namespace private_variant
1888 {
1889 //***************************************************************************
1892 //***************************************************************************
1893 template <typename TVariant>
1894 struct equality_visitor
1895 {
1896 equality_visitor(const TVariant& rhs_)
1897 : rhs(rhs_)
1898 {
1899 }
1900
1901 template <typename TValue>
1902 bool operator()(const TValue& lhs_downcasted)
1903 {
1904 return lhs_downcasted == etl::get<TValue>(rhs);
1905 }
1906
1907 const TVariant& rhs;
1908 };
1909
1910 //***************************************************************************
1913 //***************************************************************************
1914 template <typename TVariant>
1915 struct less_than_visitor
1916 {
1917 less_than_visitor(const TVariant& rhs_)
1918 : rhs(rhs_)
1919 {
1920 }
1921
1922 template <typename TValue>
1923 bool operator()(const TValue& lhs_downcasted)
1924 {
1925 return lhs_downcasted < etl::get<TValue>(rhs);
1926 }
1927
1928 const TVariant& rhs;
1929 };
1930 }
1931
1932 //***************************************************************************
1935 //***************************************************************************
1936 template <typename... TTypes>
1937 ETL_CONSTEXPR14 bool operator ==(const etl::variant<TTypes...>& lhs, const etl::variant<TTypes...>& rhs)
1938 {
1939 // If both variants are valueless, they are considered equal
1940 if (lhs.valueless_by_exception() && rhs.valueless_by_exception())
1941 {
1942 return true;
1943 }
1944
1945 // If one variant is valueless and the other is not, they are not equal
1946 if (lhs.valueless_by_exception() || rhs.valueless_by_exception())
1947 {
1948 return false;
1949 }
1950
1951 // If variants have different types, they are not equal
1952 if (lhs.index() != rhs.index())
1953 {
1954 return false;
1955 }
1956
1957 // Variants have the same type, apply the equality operator for the contained values
1958 private_variant::equality_visitor<etl::variant<TTypes...>> visitor(rhs);
1959
1960 return etl::visit(visitor, lhs);
1961 }
1962
1963 //***************************************************************************
1966 //***************************************************************************
1967 template <typename... TTypes>
1968 ETL_CONSTEXPR14 bool operator !=(const etl::variant<TTypes...>& lhs, const etl::variant<TTypes...>& rhs)
1969 {
1970 return !(lhs == rhs);
1971 }
1972
1973 //***************************************************************************
1976 //***************************************************************************
1977 template <typename... TTypes>
1978 ETL_CONSTEXPR14 bool operator <(const etl::variant<TTypes...>& lhs, const etl::variant<TTypes...>& rhs)
1979 {
1980 // If both variants are valueless, they are considered equal, so not less than
1981 if (lhs.valueless_by_exception() && rhs.valueless_by_exception())
1982 {
1983 return false;
1984 }
1985
1986 // A valueless variant is always less than a variant with a value
1987 if (lhs.valueless_by_exception())
1988 {
1989 return true;
1990 }
1991
1992 // A variant with a value is never less than a valueless variant
1993 if (rhs.valueless_by_exception())
1994 {
1995 return false;
1996 }
1997
1998 // If variants have different types, compare the type index
1999 if (lhs.index() != rhs.index())
2000 {
2001 return lhs.index() < rhs.index();
2002 }
2003
2004 // Variants have the same type, apply the less than operator for the contained values
2005 private_variant::less_than_visitor<etl::variant<TTypes...>> visitor(rhs);
2006
2007 return etl::visit(visitor, lhs);
2008 }
2009
2010 //***************************************************************************
2013 //***************************************************************************
2014 template <typename... TTypes>
2015 ETL_CONSTEXPR14 bool operator >(const etl::variant<TTypes...>& lhs, const etl::variant<TTypes...>& rhs)
2016 {
2017 return (rhs < lhs);
2018 }
2019
2020 //***************************************************************************
2023 //***************************************************************************
2024 template <typename... TTypes>
2025 ETL_CONSTEXPR14 bool operator <=(const etl::variant<TTypes...>& lhs, const etl::variant<TTypes...>& rhs)
2026 {
2027 return !(lhs > rhs);
2028 }
2029
2030 //***************************************************************************
2033 //***************************************************************************
2034 template <typename... TTypes>
2035 ETL_CONSTEXPR14 bool operator >=(const etl::variant<TTypes...>& lhs, const etl::variant<TTypes...>& rhs)
2036 {
2037 return !(lhs < rhs);
2038 }
2039
2040 namespace private_variant
2041 {
2042#if ETL_USING_CPP20 && ETL_USING_STL && !(defined(ETL_DEVELOPMENT_OS_APPLE) && defined(ETL_COMPILER_CLANG))
2043 //***************************************************************************
2046 //***************************************************************************
2047 template <typename TVariant>
2048 struct compare_visitor
2049 {
2050 compare_visitor(const TVariant& rhs_)
2051 : rhs(rhs_)
2052 {
2053 }
2054
2055 template <typename TValue>
2056 std::strong_ordering operator()(const TValue& lhs_downcasted)
2057 {
2058 return lhs_downcasted <=> etl::get<TValue>(rhs);
2059 }
2060
2061 const TVariant& rhs;
2062 };
2063#endif
2064 }
2065
2066 //***************************************************************************
2070 //***************************************************************************
2071#if ETL_USING_CPP20 && ETL_USING_STL && !(defined(ETL_DEVELOPMENT_OS_APPLE) && defined(ETL_COMPILER_CLANG))
2072 template <typename... TTypes>
2073 ETL_CONSTEXPR14
2074 std::common_comparison_category_t<std::compare_three_way_result_t<TTypes>...>
2075 operator <=>(const etl::variant<TTypes...>& lhs, const etl::variant<TTypes...>& rhs)
2076 {
2077 if (lhs.valueless_by_exception() && rhs.valueless_by_exception())
2078 {
2079 return std::strong_ordering::equal;
2080 }
2081 else if (lhs.valueless_by_exception())
2082 {
2083 return std::strong_ordering::less;
2084 }
2085 else if (rhs.valueless_by_exception())
2086 {
2087 return std::strong_ordering::greater;
2088 }
2089 else if (lhs.index() != rhs.index())
2090 {
2091 return lhs.index() <=> rhs.index();
2092 }
2093 else
2094 {
2095 // Variants have the same type, apply the equality operator for the contained values
2096 private_variant::compare_visitor<etl::variant<TTypes...>> visitor(rhs);
2097
2098 return etl::visit(visitor, lhs);
2099 }
2100 }
2101#endif
2102}
2103#endif
#define ETL_ASSERT(b, e)
Definition error_handler.h:356
ETL_CONSTEXPR exception(string_type reason_, string_type, numeric_type line_)
Constructor.
Definition exception.h:69
Definition integral_limits.h:516
Definition largest.h:227
conditional
Definition type_traits_generator.h:1155
integral_constant
Definition type_traits_generator.h:827
is_same
Definition type_traits_generator.h:1036
static bool is_supported_type()
Definition variant_legacy.h:879
~variant()
Destructor.
Definition variant_legacy.h:230
bool is_same_type(const variant &other) const
Definition variant_legacy.h:662
T & get()
Definition variant_legacy.h:754
uint_least8_t type_id_t
The type used for ids.
Definition variant_legacy.h:153
variant & operator=(const T &value)
Definition variant_legacy.h:617
bool is_type() const
Definition variant_legacy.h:727
T & emplace()
Emplace with one constructor parameter.
Definition variant_legacy.h:540
size_t index() const
Gets the index of the type currently stored or UNSUPPORTED_TYPE_ID.
Definition variant_legacy.h:735
Definition variant_legacy.h:147
Definition variant_legacy.h:100
Definition variant_legacy.h:79
bitset_ext
Definition absolute.h:38
bool operator>(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:693
T & get(array< T, MAXN > &a)
Definition array.h:719
bool operator>=(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:705
bool operator!=(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:654
void swap(etl::array< T, SIZE > &lhs, etl::array< T, SIZE > &rhs)
Template deduction guides.
Definition array.h:630
ETL_CONSTEXPR TContainer::size_type size(const TContainer &container)
Definition iterator.h:1187
bool operator==(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:642
bool operator<(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:666
bool operator<=(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:681
Definition type_traits_generator.h:2074
pair holds two objects of arbitrary type
Definition utility.h:164
Definition variant_legacy.h:950