Containers (STL-compatible) StateMachines MessageBus and more for Embedded Systems. See www.etlcpp.com
Diff: variant.h
- Revision:
- 0:b47c2a7920c2
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/variant.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,941 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef __ETL_VARIANT__ +#define __ETL_VARIANT__ + +#include <stdint.h> + +#include "platform.h" +#include "array.h" +#include "largest.h" +#include "exception.h" +#include "type_traits.h" +#include "integral_limits.h" +#include "static_assert.h" +#include "alignment.h" +#include "error_handler.h" + +#if defined(ETL_COMPILER_KEIL) + #pragma diag_suppress 940 + #pragma diag_suppress 111 +#endif + +#undef ETL_FILE +#define ETL_FILE "24" + +//***************************************************************************** +///\defgroup variant variant +/// A class that can contain one a several specified types in a type safe manner. +///\ingroup containers +//***************************************************************************** + +namespace etl +{ + namespace __private_variant__ + { + //************************************************************************* + /// Placeholder for unused template parameters. + /// This class is never instantiated. + //************************************************************************* + template <const size_t ID> + struct no_type + { + }; + } + + //*************************************************************************** + /// Base exception for the variant class. + ///\ingroup variant + //*************************************************************************** + class variant_exception : public exception + { + public: + variant_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// 'Unsupported type' exception for the variant class. + ///\ingroup variant + //*************************************************************************** + class variant_incorrect_type_exception : public variant_exception + { + public: + variant_incorrect_type_exception(string_type file_name_, numeric_type line_number_) + : variant_exception(ETL_ERROR_TEXT("variant: unsupported type", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// A template class that can store any of the types defined in the template parameter list. + /// Supports up to 8 types. + ///\ingroup variant + //*************************************************************************** + template <typename T1, + typename T2 = __private_variant__::no_type<2>, + typename T3 = __private_variant__::no_type<3>, + typename T4 = __private_variant__::no_type<4>, + typename T5 = __private_variant__::no_type<5>, + typename T6 = __private_variant__::no_type<6>, + typename T7 = __private_variant__::no_type<7>, + typename T8 = __private_variant__::no_type<8> > + class variant + { + private: + + // All types of variant are friends. + template <typename U1, typename U2, typename U3, typename U4, typename U5, typename U6, typename U7, typename U8> + friend class variant; + + //*************************************************************************** + /// The largest type. + //*************************************************************************** + typedef typename largest_type<T1, T2, T3, T4, T5, T6, T7, T8>::type largest_t; + + //*************************************************************************** + /// The largest size. + //*************************************************************************** + static const size_t SIZE = sizeof(largest_t); + + //*************************************************************************** + /// The largest alignment. + //*************************************************************************** + static const size_t ALIGNMENT = etl::largest_alignment<T1, T2, T3, T4, T5, T6, T7, T8>::value; + + //*************************************************************************** + /// The type used for ids. + //*************************************************************************** + typedef uint_least8_t type_id_t; + + //*************************************************************************** + /// The id a unsupported types. + //*************************************************************************** + static const type_id_t UNSUPPORTED_TYPE_ID = integral_limits<type_id_t>::max; + + //*************************************************************************** + /// Short form of no_type placeholders. + //*************************************************************************** + typedef __private_variant__::no_type<2> no_type2; + typedef __private_variant__::no_type<3> no_type3; + typedef __private_variant__::no_type<4> no_type4; + typedef __private_variant__::no_type<5> no_type5; + typedef __private_variant__::no_type<6> no_type6; + typedef __private_variant__::no_type<7> no_type7; + typedef __private_variant__::no_type<8> no_type8; + + //*************************************************************************** + /// Lookup the id of type. + //*************************************************************************** + template <typename T> + struct Type_Id_Lookup + { + static const uint_least8_t type_id = etl::is_same<T, T1>::value ? 0 : + etl::is_same<T, T2>::value ? 1 : + etl::is_same<T, T3>::value ? 2 : + etl::is_same<T, T4>::value ? 3 : + etl::is_same<T, T5>::value ? 4 : + etl::is_same<T, T6>::value ? 5 : + etl::is_same<T, T7>::value ? 6 : + etl::is_same<T, T8>::value ? 7 : + UNSUPPORTED_TYPE_ID; + }; + + //*************************************************************************** + /// Lookup for the id of type. + //*************************************************************************** + template <typename T> + struct Type_Is_Supported : public integral_constant<bool, + is_same<T, T1>::value || + is_same<T, T2>::value || + is_same<T, T3>::value || + is_same<T, T4>::value || + is_same<T, T5>::value || + is_same<T, T6>::value || + is_same<T, T7>::value || + is_same<T, T8>::value> + { + }; + + public: + + //*************************************************************************** + /// Destructor. + //*************************************************************************** + ~variant() + { + destruct_current(); + } + + //************************************************************************* + //**** Reader types ******************************************************* + //************************************************************************* + + //************************************************************************* + /// Base reader type functor class. + /// Allows for typesafe access to the stored value types. + /// Define the reader type for 8 types. + //************************************************************************* + template <typename R1, typename R2 = no_type2, typename R3 = no_type3, typename R4 = no_type4, typename R5 = no_type5, typename R6 = no_type6, typename R7 = no_type7, typename R8 = no_type8> + class reader_type + { + public: + + friend class variant; + + virtual void read(typename etl::parameter_type<R1>::type value) = 0; + virtual void read(typename etl::parameter_type<R2>::type value) = 0; + virtual void read(typename etl::parameter_type<R3>::type value) = 0; + virtual void read(typename etl::parameter_type<R4>::type value) = 0; + virtual void read(typename etl::parameter_type<R5>::type value) = 0; + virtual void read(typename etl::parameter_type<R6>::type value) = 0; + virtual void read(typename etl::parameter_type<R7>::type value) = 0; + virtual void read(typename etl::parameter_type<R8>::type value) = 0; + }; + + //************************************************************************* + /// Define the reader type for 7 types. + //************************************************************************* + template <typename R1, typename R2, typename R3, typename R4, typename R5, typename R6, typename R7> + class reader_type<R1, R2, R3, R4, R5, R6, R7, no_type8> + { + public: + + friend class variant; + + virtual void read(typename etl::parameter_type<R1>::type value) = 0; + virtual void read(typename etl::parameter_type<R2>::type value) = 0; + virtual void read(typename etl::parameter_type<R3>::type value) = 0; + virtual void read(typename etl::parameter_type<R4>::type value) = 0; + virtual void read(typename etl::parameter_type<R5>::type value) = 0; + virtual void read(typename etl::parameter_type<R6>::type value) = 0; + virtual void read(typename etl::parameter_type<R7>::type value) = 0; + + private: + + void read(no_type8&) {}; + }; + + //************************************************************************* + /// Define the reader type for 6 types. + //************************************************************************* + template <typename R1, typename R2, typename R3, typename R4, typename R5, typename R6> + class reader_type<R1, R2, R3, R4, R5, R6, no_type7, no_type8> + { + public: + + friend class variant; + + virtual void read(typename etl::parameter_type<R1>::type value) = 0; + virtual void read(typename etl::parameter_type<R2>::type value) = 0; + virtual void read(typename etl::parameter_type<R3>::type value) = 0; + virtual void read(typename etl::parameter_type<R4>::type value) = 0; + virtual void read(typename etl::parameter_type<R5>::type value) = 0; + virtual void read(typename etl::parameter_type<R6>::type value) = 0; + + private: + + void read(no_type7&) {}; + void read(no_type8&) {}; + }; + + //************************************************************************* + /// Define the reader type for 5 types. + //************************************************************************* + template <typename R1, typename R2, typename R3, typename R4, typename R5> + class reader_type<R1, R2, R3, R4, R5, no_type6, no_type7, no_type8> + { + public: + + friend class variant; + + virtual void read(typename etl::parameter_type<R1>::type value) = 0; + virtual void read(typename etl::parameter_type<R2>::type value) = 0; + virtual void read(typename etl::parameter_type<R3>::type value) = 0; + virtual void read(typename etl::parameter_type<R4>::type value) = 0; + virtual void read(typename etl::parameter_type<R5>::type value) = 0; + + private: + + void read(no_type6&) {}; + void read(no_type7&) {}; + void read(no_type8&) {}; + }; + + //************************************************************************* + /// Define the reader type for 4 types. + //************************************************************************* + template <typename R1, typename R2, typename R3, typename R4> + class reader_type<R1, R2, R3, R4, no_type5, no_type6, no_type7, no_type8> + { + public: + + friend class variant; + + virtual void read(typename etl::parameter_type<R1>::type value) = 0; + virtual void read(typename etl::parameter_type<R2>::type value) = 0; + virtual void read(typename etl::parameter_type<R3>::type value) = 0; + virtual void read(typename etl::parameter_type<R4>::type value) = 0; + + private: + + void read(no_type5&) {}; + void read(no_type6&) {}; + void read(no_type7&) {}; + void read(no_type8&) {}; + }; + + //************************************************************************* + /// Define the reader type for 3 types. + //************************************************************************* + template <typename R1, typename R2, typename R3> + class reader_type<R1, R2, R3, no_type4, no_type5, no_type6, no_type7, no_type8> + { + public: + + friend class variant; + + virtual void read(typename etl::parameter_type<R1>::type value) = 0; + virtual void read(typename etl::parameter_type<R2>::type value) = 0; + virtual void read(typename etl::parameter_type<R3>::type value) = 0; + + private: + + void read(no_type4&) {}; + void read(no_type5&) {}; + void read(no_type6&) {}; + void read(no_type7&) {}; + void read(no_type8&) {}; + }; + + //************************************************************************* + /// Define the reader type for 2 types. + //************************************************************************* + template <typename R1, typename R2> + class reader_type<R1, R2, no_type3, no_type4, no_type5, no_type6, no_type7, no_type8> + { + public: + + friend class variant; + + virtual void read(typename etl::parameter_type<R1>::type value) = 0; + virtual void read(typename etl::parameter_type<R2>::type value) = 0; + + private: + + void read(no_type3&) {}; + void read(no_type4&) {}; + void read(no_type5&) {}; + void read(no_type6&) {}; + void read(no_type7&) {}; + void read(no_type8&) {}; + }; + + //************************************************************************* + /// Define the reader type for 1 type. + //************************************************************************* + template <typename R1> + class reader_type<R1, no_type2, no_type3, no_type4, no_type5, no_type6, no_type7, no_type8> + { + public: + + friend class variant; + + virtual void read(typename etl::parameter_type<R1>::type value) = 0; + + private: + + void read(no_type2&) {}; + void read(no_type3&) {}; + void read(no_type4&) {}; + void read(no_type5&) {}; + void read(no_type6&) {}; + void read(no_type7&) {}; + void read(no_type8&) {}; + }; + + //************************************************************************* + //**** Up-cast functors *************************************************** + //************************************************************************* + + //************************************************************************* + /// Base upcast_functor for eight types. + //************************************************************************* + template <typename TBase, typename U1, typename U2 = no_type2, typename U3 = no_type3, typename U4 = no_type4, typename U5 = no_type5, typename U6 = no_type6, typename U7 = no_type7, typename U8 = no_type8> + class upcast_functor + { + public: + + TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) + { + switch (typeId) + { + case 0: return reinterpret_cast<U1&>(*p_data); + case 1: return reinterpret_cast<U2&>(*p_data); + case 2: return reinterpret_cast<U3&>(*p_data); + case 3: return reinterpret_cast<U4&>(*p_data); + case 4: return reinterpret_cast<U5&>(*p_data); + case 5: return reinterpret_cast<U6&>(*p_data); + case 6: return reinterpret_cast<U7&>(*p_data); + case 7: return reinterpret_cast<U8&>(*p_data); + default: return reinterpret_cast<TBase&>(*reinterpret_cast<TBase*>(0)); + } + } + + const TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) const + { + switch (typeId) + { + case 0: return reinterpret_cast<const U1&>(*p_data); + case 1: return reinterpret_cast<const U2&>(*p_data); + case 2: return reinterpret_cast<const U3&>(*p_data); + case 3: return reinterpret_cast<const U4&>(*p_data); + case 4: return reinterpret_cast<const U5&>(*p_data); + case 5: return reinterpret_cast<const U6&>(*p_data); + case 6: return reinterpret_cast<const U7&>(*p_data); + case 7: return reinterpret_cast<const U8&>(*p_data); + default: return reinterpret_cast<const TBase&>(*reinterpret_cast<const TBase*>(0)); + } + } + }; + + //************************************************************************* + /// Upcast_functor for seven types. + //************************************************************************* + template <typename TBase, typename U1, typename U2, typename U3, typename U4, typename U5, typename U6, typename U7> + class upcast_functor<TBase, U1, U2, U3, U4, U5, U6, U7, no_type8> + { + public: + + TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) + { + switch (typeId) + { + case 0: return reinterpret_cast<U1&>(*p_data); + case 1: return reinterpret_cast<U2&>(*p_data); + case 2: return reinterpret_cast<U3&>(*p_data); + case 3: return reinterpret_cast<U4&>(*p_data); + case 4: return reinterpret_cast<U5&>(*p_data); + case 5: return reinterpret_cast<U6&>(*p_data); + case 6: return reinterpret_cast<U7&>(*p_data); + default: return reinterpret_cast<TBase&>(*reinterpret_cast<TBase*>(0)); + } + } + + const TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) const + { + switch (typeId) + { + case 0: return reinterpret_cast<const U1&>(*p_data); + case 1: return reinterpret_cast<const U2&>(*p_data); + case 2: return reinterpret_cast<const U3&>(*p_data); + case 3: return reinterpret_cast<const U4&>(*p_data); + case 4: return reinterpret_cast<const U5&>(*p_data); + case 5: return reinterpret_cast<const U6&>(*p_data); + case 6: return reinterpret_cast<const U7&>(*p_data); + default: return reinterpret_cast<const TBase&>(*reinterpret_cast<const TBase*>(0)); + } + } + }; + + //************************************************************************* + /// Upcast_functor for six types. + //************************************************************************* + template <typename TBase, typename U1, typename U2, typename U3, typename U4, typename U5, typename U6> + class upcast_functor<TBase, U1, U2, U3, U4, U5, U6, no_type7, no_type8> + { + public: + + TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) + { + switch (typeId) + { + case 0: return reinterpret_cast<U1&>(*p_data); + case 1: return reinterpret_cast<U2&>(*p_data); + case 2: return reinterpret_cast<U3&>(*p_data); + case 3: return reinterpret_cast<U4&>(*p_data); + case 4: return reinterpret_cast<U5&>(*p_data); + case 5: return reinterpret_cast<U6&>(*p_data); + default: return reinterpret_cast<TBase&>(*reinterpret_cast<TBase*>(0)); + } + } + + const TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) const + { + switch (typeId) + { + case 0: return reinterpret_cast<const U1&>(*p_data); + case 1: return reinterpret_cast<const U2&>(*p_data); + case 2: return reinterpret_cast<const U3&>(*p_data); + case 3: return reinterpret_cast<const U4&>(*p_data); + case 4: return reinterpret_cast<const U5&>(*p_data); + case 5: return reinterpret_cast<const U6&>(*p_data); + default: return reinterpret_cast<const TBase&>(*reinterpret_cast<const TBase*>(0)); + } + } + }; + + //************************************************************************* + /// Upcast_functor for five types. + //************************************************************************* + template <typename TBase, typename U1, typename U2, typename U3, typename U4, typename U5> + class upcast_functor<TBase, U1, U2, U3, U4, U5, no_type6, no_type7, no_type8> + { + public: + + TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) + { + switch (typeId) + { + case 0: return reinterpret_cast<U1&>(*p_data); + case 1: return reinterpret_cast<U2&>(*p_data); + case 2: return reinterpret_cast<U3&>(*p_data); + case 3: return reinterpret_cast<U4&>(*p_data); + case 4: return reinterpret_cast<U5&>(*p_data); + default: return reinterpret_cast<TBase&>(*reinterpret_cast<TBase*>(0)); + } + } + + const TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) const + { + switch (typeId) + { + case 0: return reinterpret_cast<const U1&>(*p_data); + case 1: return reinterpret_cast<const U2&>(*p_data); + case 2: return reinterpret_cast<const U3&>(*p_data); + case 3: return reinterpret_cast<const U4&>(*p_data); + case 4: return reinterpret_cast<const U5&>(*p_data); + default: return reinterpret_cast<const TBase&>(*reinterpret_cast<const TBase*>(0)); + } + } + }; + + //************************************************************************* + /// Upcast_functor for four types. + //************************************************************************* + template <typename TBase, typename U1, typename U2, typename U3, typename U4> + class upcast_functor<TBase, U1, U2, U3, U4, no_type5, no_type6, no_type7, no_type8> + { + public: + + TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) + { + switch (typeId) + { + case 0: return reinterpret_cast<U1&>(*p_data); + case 1: return reinterpret_cast<U2&>(*p_data); + case 2: return reinterpret_cast<U3&>(*p_data); + case 3: return reinterpret_cast<U4&>(*p_data); + default: return reinterpret_cast<TBase&>(*reinterpret_cast<TBase*>(0)); + } + } + + const TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) const + { + switch (typeId) + { + case 0: return reinterpret_cast<const U1&>(*p_data); + case 1: return reinterpret_cast<const U2&>(*p_data); + case 2: return reinterpret_cast<const U3&>(*p_data); + case 3: return reinterpret_cast<const U4&>(*p_data); + default: return reinterpret_cast<const TBase&>(*reinterpret_cast<const TBase*>(0)); + } + } + }; + + //************************************************************************* + /// Upcast_functor for three types. + //************************************************************************* + template <typename TBase, typename U1, typename U2, typename U3> + class upcast_functor<TBase, U1, U2, U3, no_type4, no_type5, no_type6, no_type7, no_type8> + { + public: + + TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) + { + switch (typeId) + { + case 0: return reinterpret_cast<U1&>(*p_data); + case 1: return reinterpret_cast<U2&>(*p_data); + case 2: return reinterpret_cast<U3&>(*p_data); + default: return reinterpret_cast<TBase&>(*reinterpret_cast<TBase*>(0)); + } + } + + const TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) const + { + switch (typeId) + { + case 0: return reinterpret_cast<const U1&>(*p_data); + case 1: return reinterpret_cast<const U2&>(*p_data); + case 2: return reinterpret_cast<const U3&>(*p_data); + default: return reinterpret_cast<const TBase&>(*reinterpret_cast<const TBase*>(0)); + } + } + }; + + //************************************************************************* + /// Upcast_functor for two types. + //************************************************************************* + template <typename TBase, typename U1, typename U2> + class upcast_functor<TBase, U1, U2, no_type3, no_type4, no_type5, no_type6, no_type7, no_type8> + { + public: + + TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) + { + switch (typeId) + { + case 0: return reinterpret_cast<U1&>(*p_data); + case 1: return reinterpret_cast<U2&>(*p_data); + default: return reinterpret_cast<TBase&>(*reinterpret_cast<TBase*>(0)); + } + } + + const TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) const + { + switch (typeId) + { + case 0: return reinterpret_cast<const U1&>(*p_data); + case 1: return reinterpret_cast<const U2&>(*p_data); + default: return reinterpret_cast<const TBase&>(*reinterpret_cast<const TBase*>(0)); + } + } + }; + + //************************************************************************* + /// Upcast_functor for one type. + //************************************************************************* + template <typename TBase, typename U1> + class upcast_functor<TBase, U1, no_type2, no_type3, no_type4, no_type5, no_type6, no_type7, no_type8> + { + public: + + TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) + { + return reinterpret_cast<U1&>(*p_data); + } + + const TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) const + { + return reinterpret_cast<const U1&>(*p_data); + } + }; + + //*************************************************************************** + /// The base type for derived readers. + //*************************************************************************** + typedef reader_type<T1, T2, T3, T4, T5, T6, T7, T8> reader; + + //*************************************************************************** + /// Default constructor. + /// Sets the state of the instance to containing no valid data. + //*************************************************************************** + variant() + : type_id(UNSUPPORTED_TYPE_ID) + { + } + + //*************************************************************************** + /// Constructor that catches any types that are not supported. + /// Forces a STATIC_ASSERT. + //*************************************************************************** + template <typename T> + variant(const T& value) + { + STATIC_ASSERT(Type_Is_Supported<T>::value, "Unsupported type"); + + ::new (static_cast<T*>(data)) T(value); + type_id = Type_Id_Lookup<T>::type_id; + } + + //*************************************************************************** + /// Copy constructor. + ///\param other The other variant object to copy. + //*************************************************************************** + variant(const variant& other) + { + switch (other.type_id) + { + case 0: ::new (static_cast<T1*>(data)) T1(other.get<T1>()); break; + case 1: ::new (static_cast<T2*>(data)) T2(other.get<T2>()); break; + case 2: ::new (static_cast<T3*>(data)) T3(other.get<T3>()); break; + case 3: ::new (static_cast<T4*>(data)) T4(other.get<T4>()); break; + case 4: ::new (static_cast<T5*>(data)) T5(other.get<T5>()); break; + case 5: ::new (static_cast<T6*>(data)) T6(other.get<T6>()); break; + case 6: ::new (static_cast<T7*>(data)) T7(other.get<T7>()); break; + case 7: ::new (static_cast<T8*>(data)) T8(other.get<T8>()); break; + default: break; + } + + type_id = other.type_id; + } + + //*************************************************************************** + /// Assignment operator for T1 type. + ///\param value The value to assign. + //*************************************************************************** + template <typename T> + variant& operator =(const T& value) + { + STATIC_ASSERT(Type_Is_Supported<T>::value, "Unsupported type"); + + destruct_current(); + ::new (static_cast<T*>(data)) T(value); + type_id = Type_Id_Lookup<T>::type_id; + + return *this; + } + + //*************************************************************************** + /// Assignment operator for variant type. + ///\param other The variant to assign. + //*************************************************************************** + variant& operator =(const variant& other) + { + if (this != &other) + { + destruct_current(); + + switch (other.type_id) + { + case 0: ::new (static_cast<T1*>(data)) T1(other.get<T1>()); break; + case 1: ::new (static_cast<T2*>(data)) T2(other.get<T2>()); break; + case 2: ::new (static_cast<T3*>(data)) T3(other.get<T3>()); break; + case 3: ::new (static_cast<T4*>(data)) T4(other.get<T4>()); break; + case 4: ::new (static_cast<T5*>(data)) T5(other.get<T5>()); break; + case 5: ::new (static_cast<T6*>(data)) T6(other.get<T6>()); break; + case 6: ::new (static_cast<T7*>(data)) T7(other.get<T7>()); break; + case 7: ::new (static_cast<T8*>(data)) T8(other.get<T8>()); break; + default: break; + } + + type_id = other.type_id; + } + + return *this; + } + + //*************************************************************************** + /// Checks if the type is the same as the current stored type. + /// For variants with the same type declarations. + ///\return <b>true</b> if the types are the same, otherwise <b>false</b>. + //*************************************************************************** + bool is_same_type(const variant& other) const + { + return type_id == other.type_id; + } + + //*************************************************************************** + /// Checks if the type is the same as the current stored type. + /// For variants with differing declarations. + ///\return <b>true</b> if the types are the same, otherwise <b>false</b>. + //*************************************************************************** + template <typename U1, typename U2, typename U3, typename U4, typename U5, typename U6, typename U7, typename U8> + bool is_same_type(const variant<U1, U2, U3, U4, U5, U6, U7, U8>& other) const + { + bool is_same = false; + + switch (other.type_id) + { + case 0: is_same = (type_id == Type_Id_Lookup<U1>::type_id); break; + case 1: is_same = (type_id == Type_Id_Lookup<U2>::type_id); break; + case 2: is_same = (type_id == Type_Id_Lookup<U3>::type_id); break; + case 3: is_same = (type_id == Type_Id_Lookup<U4>::type_id); break; + case 4: is_same = (type_id == Type_Id_Lookup<U5>::type_id); break; + case 5: is_same = (type_id == Type_Id_Lookup<U6>::type_id); break; + case 6: is_same = (type_id == Type_Id_Lookup<U7>::type_id); break; + case 7: is_same = (type_id == Type_Id_Lookup<U8>::type_id); break; + default: break; + } + + return is_same; + } + + //*************************************************************************** + /// Calls the supplied reader instance. + /// The 'read' function appropriate to the current type is called with the stored value. + //*************************************************************************** + void call(reader& reader) + { + switch (type_id) + { + case 0: reader.read(static_cast<T1&>(data)); break; + case 1: reader.read(static_cast<T2&>(data)); break; + case 2: reader.read(static_cast<T3&>(data)); break; + case 3: reader.read(static_cast<T4&>(data)); break; + case 4: reader.read(static_cast<T5&>(data)); break; + case 5: reader.read(static_cast<T6&>(data)); break; + case 6: reader.read(static_cast<T7&>(data)); break; + case 7: reader.read(static_cast<T8&>(data)); break; + default: break; + } + } + + //*************************************************************************** + /// Checks whether a valid value is currently stored. + ///\return <b>true</b> if the value is valid, otherwise <b>false</b>. + //*************************************************************************** + bool is_valid() const + { + return type_id != UNSUPPORTED_TYPE_ID; + } + + //*************************************************************************** + /// Checks to see if the type currently stored is the same as that specified in the template parameter. + ///\return <b>true</b> if it is the specified type, otherwise <b>false</b>. + //*************************************************************************** + template <typename T> + bool is_type() const + { + return type_id == Type_Id_Lookup<T>::type_id; + } + + //*************************************************************************** + /// Clears the value to 'no valid stored value'. + //*************************************************************************** + void clear() + { + destruct_current(); + } + + //*************************************************************************** + /// Gets the value stored as the specified template type. + /// Throws a variant_incorrect_type_exception if the actual type is not that specified. + ///\return A reference to the value. + //*************************************************************************** + template <typename T> + T& get() + { + STATIC_ASSERT(Type_Is_Supported<T>::value, "Unsupported type"); + ETL_ASSERT(is_type<T>(), ETL_ERROR(variant_incorrect_type_exception)); + + return static_cast<T&>(data); + } + + //*************************************************************************** + /// Gets the value stored as the specified template type. + /// Throws a variant_incorrect_type_exception if the actual type is not that specified. + ///\return A const reference to the value. + //*************************************************************************** + template <typename T> + const T& get() const + { + STATIC_ASSERT(Type_Is_Supported<T>::value, "Unsupported type"); + ETL_ASSERT(is_type<T>(), ETL_ERROR(variant_incorrect_type_exception)); + + return static_cast<const T&>(data); + } + + //*************************************************************************** + /// Gets the value stored as the specified template type. + ///\return A reference to the value. + //*************************************************************************** + template <typename TBase> + TBase& upcast() + { + return upcast_functor<TBase, T1, T2, T3, T4, T5, T6, T7, T8>()(data, type_id); + } + + //*************************************************************************** + /// Gets the value stored as the specified template type. + ///\return A const reference to the value. + //*************************************************************************** + template <typename TBase> + const TBase& upcast() const + { + return upcast_functor<TBase, T1, T2, T3, T4, T5, T6, T7, T8>()(data, type_id); + } + + //*************************************************************************** + /// Conversion operators for each type. + //*************************************************************************** + operator T1&() { return get<T1>(); } + operator T2&() { return get<T2>(); } + operator T3&() { return get<T3>(); } + operator T4&() { return get<T4>(); } + operator T5&() { return get<T5>(); } + operator T6&() { return get<T6>(); } + operator T7&() { return get<T7>(); } + operator T8&() { return get<T8>(); } + + //*************************************************************************** + /// Checks if the template type is supported by the implementation of variant.. + ///\return <b>true</b> if the type is supported, otherwise <b>false</b>. + //*************************************************************************** + template <typename T> + static bool is_supported_type() + { + return Type_Is_Supported<T>::value; + } + + private: + + //*************************************************************************** + /// Destruct the current occupant of the variant. + //*************************************************************************** + void destruct_current() + { + switch (type_id) + { + case 0: { static_cast<T1*>(data)->~T1(); break; } + case 1: { static_cast<T2*>(data)->~T2(); break; } + case 2: { static_cast<T3*>(data)->~T3(); break; } + case 3: { static_cast<T4*>(data)->~T4(); break; } + case 4: { static_cast<T5*>(data)->~T5(); break; } + case 5: { static_cast<T6*>(data)->~T6(); break; } + case 6: { static_cast<T7*>(data)->~T7(); break; } + case 7: { static_cast<T8*>(data)->~T8(); break; } + default: { break; } + } + + type_id = UNSUPPORTED_TYPE_ID; + } + + //*************************************************************************** + /// The internal storage. + /// Aligned on a suitable boundary, which should be good for all types. + //*************************************************************************** + typename etl::aligned_storage<SIZE, ALIGNMENT>::type data; + + //*************************************************************************** + /// The id of the current stored type. + //*************************************************************************** + type_id_t type_id; + }; +} + +#undef ETL_FILE + +#endif +