diff --git a/include/etl/functional.h b/include/etl/functional.h index 0c3f0f2c..5f274af1 100644 --- a/include/etl/functional.h +++ b/include/etl/functional.h @@ -232,7 +232,6 @@ namespace etl } //*************************************************************************** - template class binder2nd : public etl::unary_function { diff --git a/include/etl/generators/type_traits_generator.h b/include/etl/generators/type_traits_generator.h index b2d405fe..3fad300b 100644 --- a/include/etl/generators/type_traits_generator.h +++ b/include/etl/generators/type_traits_generator.h @@ -781,6 +781,7 @@ namespace etl /// Specialisation of 'alignment_of' for 'void'. ///\ingroup type_traits template <> struct alignment_of : integral_constant {}; + template <> struct alignment_of : integral_constant {}; #if ETL_CPP17_SUPPORTED template diff --git a/include/etl/overload.h b/include/etl/overload.h index fb9dd080..52a41fcd 100644 --- a/include/etl/overload.h +++ b/include/etl/overload.h @@ -32,46 +32,23 @@ SOFTWARE. #define ETL_OVERLOAD_INCLUDED #include "platform.h" +#include "utility.h" +#include "type_traits.h" namespace etl { -#if ETL_CPP11_SUPPORTED - #if ETL_CPP17_SUPPORTED && !defined(ETL_OVERLOAD_FORCE_CPP11) +#if ETL_CPP14_SUPPORTED +#if ETL_CPP17_SUPPORTED && !defined(ETL_OVERLOAD_FORCE_CPP14) + //************************************************************************* - /// Variadic template definition of overload. + /// Variadic template definition of overload for C++17 and above. //************************************************************************* - template + template struct overload : TOverloads... { using TOverloads::operator()...; }; - //************************************************************************* - /// Template deduction guide. - //************************************************************************* - template overload(TOverloads...)->overload; - -#else - //************************************************************************* - /// Variadic template definition of overload. - //************************************************************************* - template - struct overload : TOverload, overload - { - using TOverload::operator(); - using overload::operator(); - }; - - //************************************************************************* - /// Template specialisation of overload for one type. - //************************************************************************* - template - struct overload : TOverload - { - using TOverload::operator(); - }; -#endif - //************************************************************************* /// Make an overload. //************************************************************************* @@ -80,7 +57,75 @@ namespace etl { return overload{ etl::forward(overloads)... }; } -} + + //************************************************************************* + /// Template deduction guide. + //************************************************************************* + template overload(TOverloads...)->overload; + +#else + + //************************************************************************* + /// Variadic template definition of overload for C++14. + //************************************************************************* + //namespace private_overload + //{ + // //*********************************** + // // Overload helper templates. + // //*********************************** + // template + // struct overload_helper; + + // template <> + // struct overload_helper<> + // { + // }; + + // template + // struct overload_helper : TFirst, overload_helper + // { + // using TFirst::operator(); + + // template + // overload_helper(UFirst&& u, UOthers&&... others) + // : TFirst{ etl::forward(u) }, overload_helper{ etl::forward(others)... } + // { + // } + // }; + //} + + ////*********************************** + ///// Make an overload. + ////*********************************** + //template + //constexpr auto make_overload(TOverloads&&... overloads) + //{ + // return private_overload::overload_helper{ etl::forward(overloads)... }; + //} + + template + struct overload : TFirst, overload + { + using TFirst::operator(); + using overload::operator(); + }; + + template struct overload : TFirst + { + using TFirst::operator(); + }; + + //************************************************************************* + /// Make an overload. + //************************************************************************* + template + constexpr auto make_overload(TOthers&&... overloads) + { + return overload{ etl::forward(overloads)... }; + } #endif #endif +} + +#endif diff --git a/include/etl/private/variant_new.h b/include/etl/private/variant_new.h index e11a6e32..41c2570b 100644 --- a/include/etl/private/variant_new.h +++ b/include/etl/private/variant_new.h @@ -43,57 +43,19 @@ SOFTWARE. #include "../parameter_pack.h" #include "../placement_new.h" #include "../visitor.h" - -#include +#include "../memory.h" #if defined(ETL_COMPILER_KEIL) #pragma diag_suppress 940 #pragma diag_suppress 111 #endif -namespace etl -{ - //template - //class integer_sequence - //{ - //public: - // - // ETL_STATIC_ASSERT(etl::is_integral::value, "Integral types only"); - - // typedef T value_type; - // - // static ETL_CONSTEXPR size_t size() ETL_NOEXCEPT - // { - // return sizeof...(Integers); - // } - //}; - - //namespace private_integer_sequence - //{ - // template - // struct make_index_sequence; - - // template - // struct make_index_sequence> - // { - // typedef typename make_index_sequence>::type type; - // }; - - // template - // struct make_index_sequence<0, integer_sequence> - // { - // typedef integer_sequence type; - // }; - //} - - //template - //using make_index_sequence = typename private_integer_sequence::make_index_sequence>::type; - - //template - //using index_sequence = integer_sequence; -} - +#if ETL_CPP11_NOT_SUPPORTED + #if !defined(ETL_IN_UNIT_TEST) + #error NOT SUPPORTED FOR C++03 OR BELOW + #endif +#else //***************************************************************************** ///\defgroup variant variant /// A class that can contain one a several specified types in a type safe manner. @@ -102,10 +64,95 @@ namespace etl namespace etl { - static_assert(ETL_CPP11_SUPPORTED, "Only supported for C++11 or above"); + namespace private_variant + { + //*************************************************************************** + // This is a copy of the normal etl::parameter_pack, but without the static_assert + // so that the C++11 versions of do_accept() & do_operator() do not throw a compile time error. + //*************************************************************************** + template + class parameter_pack + { + public: + static constexpr size_t size = sizeof...(TTypes); + + //*************************************************************************** + /// index_of_type + //*************************************************************************** + template + class index_of_type + { + private: + + using type = etl::remove_reference_t; + + //*********************************** + template + struct index_of_type_helper + { + static constexpr size_t value = etl::is_same::value ? 1 : 1 + index_of_type_helper::value; + }; + + //*********************************** + template + struct index_of_type_helper + { + static constexpr size_t value = 1; + }; + + public: + + static_assert(etl::is_one_of_v, "T is not in parameter pack"); + + /// The index value. + static constexpr size_t value = index_of_type_helper::value - 1; + }; + + //*************************************************************************** + /// type_from_index + //*************************************************************************** + template + class type_from_index + { + private: + + //*********************************** + template + struct type_from_index_helper + { + using type = typename etl::conditional::type>::type; + }; + + //*********************************** + template + struct type_from_index_helper + { + using type = T1; + }; + + public: + + /// Template alias + using type = typename type_from_index_helper::type; + }; + + //*********************************** + template + using type_from_index_t = typename type_from_index::type; + }; + } + + /// Definition of variant_npos. constexpr size_t variant_npos = etl::integral_limits::max; + // Forward declarations. + template + class variant; + + template + ETL_CONSTEXPR14 bool holds_alternative(const etl::variant& v) noexcept; + //*************************************************************************** /// Monostate for variants. ///\ingroup variant @@ -142,7 +189,7 @@ namespace etl { public: variant_incorrect_type_exception(string_type file_name_, numeric_type line_number_) - : variant_exception(ETL_ERROR_TEXT("variant: unsupported type", ETL_VARIANT_FILE_ID"A"), file_name_, line_number_) + : variant_exception(ETL_ERROR_TEXT("variant:unsupported type", ETL_VARIANT_FILE_ID"A"), file_name_, line_number_) { } }; @@ -167,9 +214,8 @@ namespace etl // The type of actions we can perform. enum class action_type : char { - Construct, - Destruct, - Move + Create, + Destroy }; // All types of variant are friends. @@ -197,48 +243,113 @@ namespace etl /// The internal storage. /// Aligned on a suitable boundary, which should be good for all types. //*************************************************************************** - typename etl::aligned_storage::type data; + etl::uninitialized_buffer data; //*************************************************************************** /// Default constructor. /// Sets the state of the instance to containing no valid data. //*************************************************************************** - constexpr variant() + ETL_CONSTEXPR14 variant() : data() { - using type = typename etl::parameter_pack::template type_from_index<0>::type; + using type = typename etl::private_variant::parameter_pack::template type_from_index<0>::type; - type temp; - - operation = do_operation; - operation(action_type::Construct, data, &temp); + operation = do_operation_default_construct; + operation(action_type::Create, data, nullptr); type_id = 0; } //*************************************************************************** - /// Constructor for lvalues + /// Constructor from a value. //*************************************************************************** - template - constexpr variant(const T& value) + template , variant>::value, int> = 0> + ETL_CONSTEXPR14 variant(T&& value) : data() - , operation(do_operation) - , type_id(etl::parameter_pack::template index_of_type::value) + , operation(operation_type::value>::do_operation) + , type_id(etl::private_variant::parameter_pack::template index_of_type>::value) { - static_assert(etl::is_one_of::value, "Unsupported type"); + static_assert(etl::is_one_of, TTypes...>::value, "Unsupported type"); - operation(action_type::Construct, data, &const_cast(value)); + operation(action_type::Create, data, &value); + } + + //*************************************************************************** + /// Construct from arguments. + //*************************************************************************** + template + ETL_CONSTEXPR14 explicit variant(etl::in_place_type_t, TArgs&&... args) + : data() + , type_id(etl::private_variant::parameter_pack::template index_of_type>::value) + { + T temp(std::forward(args)...); + + operation = operation_type::value>::do_operation; + operation(action_type::Create, data, &temp); + } + + //*************************************************************************** + /// Construct from arguments. + //*************************************************************************** + template + ETL_CONSTEXPR14 explicit variant(etl::in_place_index_t, TArgs&&... args) + : data() + { + using type = private_variant::parameter_pack::type_from_index_t; + + type temp(std::forward(args)...); + + operation = operation_type::value>::do_operation; + operation(action_type::Create, data, &temp); + + type_id = Index; } //*************************************************************************** /// Copy constructor. ///\param other The other variant object to copy. //*************************************************************************** - constexpr variant(const variant& other) + ETL_CONSTEXPR14 variant(const variant& other) : data() , operation(other.operation) , type_id(other.type_id) { - operation(action_type::Construct, data, other.data); + if (this != &other) + { + if (other.index() == variant_npos) + { + type_id = variant_npos; + } + else + { + operation(action_type::Create, data, other.data); + } + } + } + + //*************************************************************************** + /// Move constructor. + ///\param other The other variant object to copy. + //*************************************************************************** + ETL_CONSTEXPR14 variant(variant&& other) + : data() + , operation(other.operation) + , type_id(other.type_id) + { + if (this != &other) + { + if (other.index() == variant_npos) + { + type_id = variant_npos; + } + else + { + operation(action_type::Create, data, other.data); + } + } + else + { + type_id = variant_npos; + } } //*************************************************************************** @@ -246,9 +357,12 @@ namespace etl //*************************************************************************** ~variant() { - operation(action_type::Destruct, data, nullptr); - operation = null_operation; + if (index() != variant_npos) + { + operation(action_type::Destroy, data, nullptr); + } + operation = null_operation; type_id = variant_npos; } @@ -260,33 +374,32 @@ namespace etl { static_assert(etl::is_one_of::value, "Unsupported type"); - operation(action_type::Destruct, data, nullptr); - - operation = do_operation; - + operation(action_type::Destroy, data, nullptr); + T temp(etl::forward(args)...); - operation(action_type::Construct, data, &temp); + operation = operation_type::value>::do_operation; + operation(action_type::Create, data, &temp); - type_id = etl::parameter_pack::template index_of_type::value; + type_id = etl::private_variant::parameter_pack::template index_of_type::value; return *static_cast(data); } //*************************************************************************** - /// Assignment operator for type. + /// Move assignment operator for type. ///\param value The value to assign. //*************************************************************************** - template - variant& operator =(const T& value) + template , variant>, int> = 0> + variant& operator =(T&& value) { - static_assert(etl::is_one_of::value, "Unsupported type"); + static_assert(etl::is_one_of, TTypes...>::value, "Unsupported type"); - operation(action_type::Destruct, data, nullptr); + operation(action_type::Destroy, data, nullptr); - operation = do_operation; - operation(action_type::Construct, data, &value); + operation = operation_type::value>::do_operation; + operation(action_type::Create, data, &value); - type_id = etl::parameter_pack::template index_of_type::value; + type_id = etl::private_variant::parameter_pack::template index_of_type::value; return *this; } @@ -299,12 +412,45 @@ namespace etl { if (this != &other) { - operation(action_type::Destruct, data, nullptr); + if (other.index() == variant_npos) + { + type_id = variant_npos; + } + else + { + operation(action_type::Destroy, data, nullptr); - operation = other.operation; - operation(action_type::Construct, data, other.data); + operation = other.operation; + operation(action_type::Create, data, other.data); - type_id = other.type_id; + type_id = other.type_id; + } + } + + return *this; + } + + //*************************************************************************** + /// Assignment operator for variant type. + ///\param other The variant to assign. + //*************************************************************************** + variant& operator =(variant&& other) + { + if (this != &other) + { + if (other.index() == variant_npos) + { + type_id = variant_npos; + } + else + { + operation(action_type::Destroy, data, nullptr); + + operation = other.operation; + operation(action_type::Create, data, other.data); + + type_id = other.type_id; + } } return *this; @@ -316,7 +462,7 @@ namespace etl //*************************************************************************** constexpr bool valueless_by_exception() const noexcept { - return type_id != variant_npos; + return type_id == variant_npos; } //*************************************************************************** @@ -337,41 +483,17 @@ namespace etl rhs = temp; } - //*************************************************************************** - /// 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 - T& get() - { - static_assert(etl::is_one_of::value, "Unsupported type"); - ETL_ASSERT(etl::holds_alternative(*this), ETL_ERROR(variant_incorrect_type_exception)); - - return static_cast(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 - const T& get() const - { - static_assert(etl::is_one_of::value, "Unsupported type"); - ETL_ASSERT(is_type(), ETL_ERROR(variant_incorrect_type_exception)); - - return static_cast(data); - } - //*************************************************************************** /// Accept an etl::visitor. //*************************************************************************** template void accept(etl::visitor& v) { - do_accept(v, std::make_index_sequence{}); +#if ETL_CPP17_SUPPORTED && !defined(ETL_VARIANT_FORCE_CPP11) + do_accept(v, etl::make_index_sequence{}); +#else + do_accept(v); +#endif } //*************************************************************************** @@ -380,48 +502,168 @@ namespace etl template void operator()(TVisitor& v) { - do_operator(v, std::make_index_sequence{}); +#if ETL_CPP17_SUPPORTED && !defined(ETL_VARIANT_FORCE_CPP11) + do_operator(v, etl::make_index_sequence{}); +#else + do_operator(v); +#endif } private: - using operation_type = void(*)(action_type, void*, const void*); + using operation_function = void(*)(action_type, void*, const void*); //*************************************************************************** /// Do an operation determined by type. //*************************************************************************** - template - static void do_operation(action_type action, void* pstorage, const void* pvalue) + template + static void do_operation_default_construct(action_type action, void* pstorage, const void* pvalue) { switch (action) { - case action_type::Construct: - { - ::new (pstorage) T(*reinterpret_cast(pvalue)); - break; - } + case action_type::Create: + { + ::new (pstorage) T(); + break; + } - case action_type::Destruct: - { - reinterpret_cast(pstorage)->~T(); - break; - } + case action_type::Destroy: + { + reinterpret_cast(pstorage)->~T(); + break; + } - default: - { - break; - } + default: + { + break; + } } } + // Declaration. + template + struct operation_type; + + // Specialisation for lvalue rreferences + template + struct operation_type + { + static void do_operation(variant::action_type action, void* pstorage, const void* pvalue) + { + using type = etl::remove_reference_t; + + switch (action) + { + case variant::action_type::Create: + { + ::new (pstorage) type(*reinterpret_cast(pvalue)); + break; + } + + case variant::action_type::Destroy: + { + reinterpret_cast(pstorage)->~type(); + break; + } + + default: + { + break; + } + } + } + }; + + // Specialisation for rvalue rreferences + template + struct operation_type + { + static void do_operation(variant::action_type action, void* pstorage, const void* pvalue) + { + using type = etl::remove_reference_t; + + switch (action) + { + case variant::action_type::Create: + { + ::new (pstorage) type(etl::move(*reinterpret_cast(const_cast(pvalue)))); + break; + } + + case variant::action_type::Destroy: + { + reinterpret_cast(pstorage)->~type(); + break; + } + + default: + { + break; + } + } + } + }; + +#if ETL_CPP17_SUPPORTED && !defined(ETL_VARIANT_FORCE_CPP11) //*************************************************************************** - /// Loop through the types until a match is found. + /// Call the relevent visitor by attemptng each one. //*************************************************************************** template - void do_accept(TVisitor& visitor, std::index_sequence) + void do_accept(TVisitor& visitor, etl::index_sequence) { (attempt_visitor(visitor) || ...); } +#else + //*************************************************************************** + /// /// Call the relevent visitor. + //*************************************************************************** + template + void do_accept(TVisitor& visitor) + { + switch (index()) + { + case 0: visitor.visit(etl::get<0>(*this)); break; + case 1: visitor.visit(etl::get<1>(*this)); break; + case 2: visitor.visit(etl::get<2>(*this)); break; + case 3: visitor.visit(etl::get<3>(*this)); break; + case 4: visitor.visit(etl::get<4>(*this)); break; + case 5: visitor.visit(etl::get<5>(*this)); break; + case 6: visitor.visit(etl::get<6>(*this)); break; + case 7: visitor.visit(etl::get<7>(*this)); break; +#if !defined(ETL_VARIANT_CPP11_MAX_8_TYPES) + case 8: visitor.visit(etl::get<8>(*this)); break; + case 9: visitor.visit(etl::get<9>(*this)); break; + case 10: visitor.visit(etl::get<10>(*this)); break; + case 11: visitor.visit(etl::get<11>(*this)); break; + case 12: visitor.visit(etl::get<12>(*this)); break; + case 13: visitor.visit(etl::get<13>(*this)); break; + case 14: visitor.visit(etl::get<14>(*this)); break; + case 15: visitor.visit(etl::get<15>(*this)); break; +#if !defined(ETL_VARIANT_CPP11_MAX_16_TYPES) + case 16: visitor.visit(etl::get<16>(*this)); break; + case 17: visitor.visit(etl::get<17>(*this)); break; + case 18: visitor.visit(etl::get<18>(*this)); break; + case 19: visitor.visit(etl::get<19>(*this)); break; + case 20: visitor.visit(etl::get<20>(*this)); break; + case 21: visitor.visit(etl::get<21>(*this)); break; + case 22: visitor.visit(etl::get<22>(*this)); break; + case 23: visitor.visit(etl::get<23>(*this)); break; +#if !defined(ETL_VARIANT_CPP11_MAX_24_TYPES) + case 24: visitor.visit(etl::get<24>(*this)); break; + case 25: visitor.visit(etl::get<25>(*this)); break; + case 26: visitor.visit(etl::get<26>(*this)); break; + case 27: visitor.visit(etl::get<27>(*this)); break; + case 28: visitor.visit(etl::get<28>(*this)); break; + case 29: visitor.visit(etl::get<29>(*this)); break; + case 30: visitor.visit(etl::get<30>(*this)); break; + case 31: visitor.visit(etl::get<31>(*this)); break; +#endif +#endif +#endif + default: break; + } + } +#endif //*************************************************************************** /// Attempt to call a visitor. @@ -440,14 +682,78 @@ namespace etl } } +#if ETL_CPP17_SUPPORTED && !defined(ETL_VARIANT_FORCE_CPP11) //*************************************************************************** - /// Loop through the types until a match is found. + /// Call the relevent visitor by attemptng each one. //*************************************************************************** template - void do_operator(TVisitor& visitor, std::index_sequence) + void do_operator(TVisitor& visitor, etl::index_sequence) { (attempt_operator(visitor) || ...); } +#else + //*************************************************************************** + /// Call the relevent visitor. + //*************************************************************************** + template + void do_operator(TVisitor& visitor) + { +#if defined(ETL_VARIANT_CPP11_MAX_8_TYPES) + ETL_STATIC_ASSERT(sizeof...(TTypes) <= 8U, "???"); +#endif + +#if defined(ETL_VARIANT_CPP11_MAX_16_TYPES) + ETL_STATIC_ASSERT(sizeof...(TTypes) <= 16U, "???"); +#endif + +#if defined(ETL_VARIANT_CPP11_MAX_24_TYPES) + ETL_STATIC_ASSERT(sizeof...(TTypes) <= 24U, "???"); +#endif + + switch (index()) + { + case 0: visitor(etl::get<0>(*this)); break; + case 1: visitor(etl::get<1>(*this)); break; + case 2: visitor(etl::get<2>(*this)); break; + case 3: visitor(etl::get<3>(*this)); break; + case 4: visitor(etl::get<4>(*this)); break; + case 5: visitor(etl::get<5>(*this)); break; + case 6: visitor(etl::get<6>(*this)); break; + case 7: visitor(etl::get<7>(*this)); break; +#if !defined(ETL_VARIANT_CPP11_MAX_8_TYPES) + case 8: visitor(etl::get<8>(*this)); break; + case 9: visitor(etl::get<9>(*this)); break; + case 10: visitor(etl::get<10>(*this)); break; + case 11: visitor(etl::get<11>(*this)); break; + case 12: visitor(etl::get<12>(*this)); break; + case 13: visitor(etl::get<13>(*this)); break; + case 14: visitor(etl::get<14>(*this)); break; + case 15: visitor(etl::get<15>(*this)); break; +#if !defined(ETL_VARIANT_CPP11_MAX_16_TYPES) + case 16: visitor(etl::get<16>(*this)); break; + case 17: visitor(etl::get<17>(*this)); break; + case 18: visitor(etl::get<18>(*this)); break; + case 19: visitor(etl::get<19>(*this)); break; + case 20: visitor(etl::get<20>(*this)); break; + case 21: visitor(etl::get<21>(*this)); break; + case 22: visitor(etl::get<22>(*this)); break; + case 23: visitor(etl::get<23>(*this)); break; +#if !defined(ETL_VARIANT_CPP11_MAX_24_TYPES) + case 24: visitor(etl::get<24>(*this)); break; + case 25: visitor(etl::get<25>(*this)); break; + case 26: visitor(etl::get<26>(*this)); break; + case 27: visitor(etl::get<27>(*this)); break; + case 28: visitor(etl::get<28>(*this)); break; + case 29: visitor(etl::get<29>(*this)); break; + case 30: visitor(etl::get<30>(*this)); break; + case 31: visitor(etl::get<31>(*this)); break; +#endif +#endif +#endif + default: break; + } + } +#endif //*************************************************************************** /// Attempt to call a visitor. @@ -477,7 +783,7 @@ namespace etl //*************************************************************************** /// The operation function. //*************************************************************************** - operation_type operation; + operation_function operation; //*************************************************************************** /// The id of the current stored type. @@ -489,9 +795,9 @@ namespace etl /// Checks if the variant v holds the alternative T. //*************************************************************************** template - constexpr bool holds_alternative(const etl::variant& v) noexcept + ETL_CONSTEXPR14 bool holds_alternative(const etl::variant& v) noexcept { - constexpr size_t Index = etl::parameter_pack::template index_of_type::value; + constexpr size_t Index = etl::private_variant::parameter_pack::template index_of_type::value; return (Index == variant_npos) ? false : (v.index() == Index); } @@ -505,7 +811,7 @@ namespace etl template struct variant_alternative> { - using type = typename etl::parameter_pack::template type_from_index::type; + using type = typename etl::private_variant::parameter_pack::template type_from_index::type; }; template @@ -521,10 +827,13 @@ namespace etl /// get //*************************************************************************** template - constexpr etl::variant_alternative_t>& + ETL_CONSTEXPR14 etl::variant_alternative_t>& get(etl::variant& v) { - //static_assert(Index < sizeof...(TTypes), "Index out of range"); +#if ETL_CPP17_SUPPORTED && !defined(ETL_VARIANT_FORCE_CPP11) + static_assert(Index < sizeof...(TTypes), "Index out of range"); +#endif + ETL_ASSERT(Index == v.index(), ETL_ERROR(etl::variant_incorrect_type_exception)); using type = etl::variant_alternative_t>; @@ -534,10 +843,12 @@ namespace etl //*********************************** template - constexpr etl::variant_alternative_t>&& + ETL_CONSTEXPR14 etl::variant_alternative_t>&& get(etl::variant&& v) { +#if ETL_CPP17_SUPPORTED && !defined(ETL_VARIANT_FORCE_CPP11) static_assert(Index < sizeof...(TTypes), "Index out of range"); +#endif using type = etl::variant_alternative_t>; @@ -546,10 +857,13 @@ namespace etl //*********************************** template - constexpr const etl::variant_alternative_t>& + ETL_CONSTEXPR14 const etl::variant_alternative_t>& get(const etl::variant& v) { +#if ETL_CPP17_SUPPORTED && !defined(ETL_VARIANT_FORCE_CPP11) static_assert(Index < sizeof...(TTypes), "Index out of range"); +#endif + ETL_ASSERT(Index == v.index(), ETL_ERROR(etl::variant_incorrect_type_exception)); using type = etl::variant_alternative_t>; @@ -559,10 +873,13 @@ namespace etl //*********************************** template - constexpr const etl::variant_alternative_t>&& + ETL_CONSTEXPR14 const etl::variant_alternative_t>&& get(const etl::variant&& v) { +#if ETL_CPP17_SUPPORTED & !defined(ETL_VARIANT_FORCE_CPP11) static_assert(Index < sizeof...(TTypes), "Index out of range"); +#endif + ETL_ASSERT(Index == v.index(), ETL_ERROR(etl::variant_incorrect_type_exception)); using type = etl::variant_alternative_t>; @@ -572,45 +889,45 @@ namespace etl //*********************************** template - constexpr T& get(etl::variant& v) + ETL_CONSTEXPR14 T& get(etl::variant& v) { - constexpr size_t Index = etl::parameter_pack::template index_of_type::value; + constexpr size_t Index = etl::private_variant::parameter_pack::template index_of_type::value; return get(v); } //*********************************** template - constexpr T&& get(etl::variant&& v) + ETL_CONSTEXPR14 T&& get(etl::variant&& v) { - constexpr size_t Index = etl::parameter_pack::template index_of_type::value; + constexpr size_t Index = etl::private_variant::parameter_pack::template index_of_type::value; return get(v); } //*********************************** template - constexpr const T& get(const etl::variant& v) + ETL_CONSTEXPR14 const T& get(const etl::variant& v) { - constexpr size_t Index = etl::parameter_pack::template index_of_type::value; + constexpr size_t Index = etl::private_variant::parameter_pack::template index_of_type::value; return get(v); } //*********************************** template - constexpr const T&& get(const etl::variant&& v) + ETL_CONSTEXPR14 const T&& get(const etl::variant&& v) { - constexpr size_t Index = etl::parameter_pack::template index_of_type::value; + constexpr size_t Index = etl::private_variant::parameter_pack::template index_of_type::value; return get(v); } //*************************************************************************** - /// get_if + /// get_if (pointer parameter) //*************************************************************************** template < size_t Index, typename... TTypes > - constexpr etl::add_pointer_t>> + ETL_CONSTEXPR14 etl::add_pointer_t>> get_if(etl::variant* pv) noexcept { if ((pv != nullptr) && (pv->index() == Index)) @@ -625,7 +942,7 @@ namespace etl //*********************************** template< size_t Index, typename... TTypes > - constexpr etl::add_pointer_t>> + ETL_CONSTEXPR14 etl::add_pointer_t>> get_if(const etl::variant* pv) noexcept { if ((pv != nullptr) && (pv->index() == Index)) @@ -640,22 +957,96 @@ namespace etl //*********************************** template< class T, typename... TTypes > - constexpr etl::add_pointer_t get_if(etl::variant* pv) noexcept + ETL_CONSTEXPR14 etl::add_pointer_t get_if(etl::variant* pv) noexcept { - constexpr size_t Index = etl::parameter_pack::template index_of_type::value; + constexpr size_t Index = etl::private_variant::parameter_pack::template index_of_type::value; return etl::get_if(pv); } //*********************************** template< class T, typename... TTypes > - constexpr etl::add_pointer_t get_if(const etl::variant* pv) noexcept + ETL_CONSTEXPR14 etl::add_pointer_t get_if(const etl::variant* pv) noexcept { - constexpr size_t Index = etl::parameter_pack::template index_of_type::value; + constexpr size_t Index = etl::private_variant::parameter_pack::template index_of_type::value; return etl::get_if(pv); } + //*************************************************************************** + /// get_if (reference parameter) + //*************************************************************************** + template < size_t Index, typename... TTypes > + ETL_CONSTEXPR14 etl::add_pointer_t>> + get_if(etl::variant& v) noexcept + { + if (v.index() == Index) + { + return &etl::get(v); + } + else + { + return nullptr; + } + } + + //*********************************** + template< size_t Index, typename... TTypes > + ETL_CONSTEXPR14 etl::add_pointer_t>> + get_if(const etl::variant& v) noexcept + { + if (v.index() == Index) + { + return &etl::get(v); + } + else + { + return nullptr; + } + } + + //*********************************** + template< size_t Index, typename... TTypes > + ETL_CONSTEXPR14 etl::add_pointer_t>> + get_if(etl::variant&& v) noexcept + { + if (v.index() == Index) + { + return &etl::get(v); + } + else + { + return nullptr; + } + } + + //*********************************** + template< class T, typename... TTypes > + ETL_CONSTEXPR14 etl::add_pointer_t get_if(etl::variant& v) noexcept + { + constexpr size_t Index = etl::private_variant::parameter_pack::template index_of_type::value; + + return etl::get_if(v); + } + + //*********************************** + template< class T, typename... TTypes > + ETL_CONSTEXPR14 etl::add_pointer_t get_if(const etl::variant& v) noexcept + { + constexpr size_t Index = etl::private_variant::parameter_pack::template index_of_type::value; + + return etl::get_if(v); + } + + //*********************************** + template< class T, typename... TTypes > + ETL_CONSTEXPR14 etl::add_pointer_t get_if(etl::variant&& v) noexcept + { + constexpr size_t Index = etl::private_variant::parameter_pack::template index_of_type::value; + + return etl::get_if(v); + } + //*************************************************************************** /// swap //*************************************************************************** @@ -682,4 +1073,10 @@ namespace etl : etl::integral_constant::value> { }; + +#if ETL_CPP17_SUPPORTED + template + inline constexpr size_t variant_size_v = variant_size::value; +#endif } +#endif diff --git a/include/etl/type_traits.h b/include/etl/type_traits.h index 281b94bf..b12d08e2 100644 --- a/include/etl/type_traits.h +++ b/include/etl/type_traits.h @@ -769,6 +769,7 @@ namespace etl /// Specialisation of 'alignment_of' for 'void'. ///\ingroup type_traits template <> struct alignment_of : integral_constant {}; + template <> struct alignment_of : integral_constant {}; #if ETL_CPP17_SUPPORTED template diff --git a/include/etl/utility.h b/include/etl/utility.h index 62d4237d..a8af74f9 100644 --- a/include/etl/utility.h +++ b/include/etl/utility.h @@ -332,8 +332,55 @@ namespace etl return t; } - //****************************************************************************** + //*************************************************************************** + /// integer_sequence + //*************************************************************************** +#if ETL_CPP11_SUPPORTED + template + class integer_sequence + { + public: + + ETL_STATIC_ASSERT(etl::is_integral::value, "Integral types only"); + + typedef T value_type; + + static ETL_CONSTEXPR size_t size() ETL_NOEXCEPT + { + return sizeof...(Integers); + } + }; + + namespace private_integer_sequence + { + template + struct make_index_sequence; + + template + struct make_index_sequence> + { + typedef typename make_index_sequence>::type type; + }; + + template + struct make_index_sequence<0, etl::integer_sequence> + { + typedef etl::integer_sequence type; + }; + } + + //*********************************** + template + using make_index_sequence = typename private_integer_sequence::make_index_sequence>::type; + + //*********************************** + template + using index_sequence = etl::integer_sequence; +#endif + + //*************************************************************************** /// 2D coordinate type. + //*************************************************************************** template struct coordinate_2d { @@ -362,6 +409,36 @@ namespace etl T x; T y; }; + + //*************************************************************************** + /// in_place disambiguation tags. + //*************************************************************************** + + //************************* + struct in_place_t + { + explicit ETL_CONSTEXPR in_place_t() {} + }; + + inline ETL_CONSTEXPR in_place_t in_place{}; + + //************************* + template struct in_place_type_t + { + explicit ETL_CONSTEXPR in_place_type_t(){}; + }; + + template + inline ETL_CONSTEXPR in_place_type_t in_place_type{}; + + //************************* + template struct in_place_index_t + { + explicit ETL_CONSTEXPR in_place_index_t() {} + }; + + template + inline ETL_CONSTEXPR in_place_index_t in_place_index{}; } #endif diff --git a/include/etl/variant.h b/include/etl/variant.h index 8702eeed..7e4a20e6 100644 --- a/include/etl/variant.h +++ b/include/etl/variant.h @@ -31,7 +31,7 @@ SOFTWARE. #ifndef ETL_VARIANT_INCLUDED #define ETL_VARIANT_INCLUDED -#if 1 //ETL_USE_LEGACY_VARIANT +#if ETL_USE_LEGACY_VARIANT #include "private/variant_legacy.h" #else #include "private/variant_new.h" diff --git a/test/etl_profile.h b/test/etl_profile.h index 3212f83b..b3b01bf7 100644 --- a/test/etl_profile.h +++ b/test/etl_profile.h @@ -98,7 +98,9 @@ SOFTWARE. #define ETL_MEM_CAST_FORCE_CPP03 #endif -//#define ETL_OVERLOAD_FORCE_CPP11 +#define ETL_OVERLOAD_FORCE_CPP14 +#define ETL_VARIANT_FORCE_CPP11 +#define ETL_VARIANT_CPP11_MAX_16_TYPES #if defined(ETL_NO_STL) #define ETL_TIMER_SEMAPHORE_TYPE uint32_t diff --git a/test/sanity-check/c++03/CMakeLists.txt b/test/sanity-check/c++03/CMakeLists.txt index dea14a49..9361a7c5 100644 --- a/test/sanity-check/c++03/CMakeLists.txt +++ b/test/sanity-check/c++03/CMakeLists.txt @@ -173,6 +173,7 @@ target_sources(t98 PRIVATE etl_profile.h ../numeric.h.t.cpp ../observer.h.t.cpp ../optional.h.t.cpp + ../overload.h.t.cpp ../packet.h.t.cpp ../parameter_pack.h.t.cpp ../parameter_type.h.t.cpp @@ -242,7 +243,8 @@ target_sources(t98 PRIVATE etl_profile.h ../user_type.h.t.cpp ../utility.h.t.cpp ../variance.h.t.cpp - ../variant.h.t.cpp + ../variant_legacy.h.t.cpp + ../variant_new.h.t.cpp ../variant_pool.h.t.cpp ../vector.h.t.cpp ../version.h.t.cpp diff --git a/test/sanity-check/c++11/CMakeLists.txt b/test/sanity-check/c++11/CMakeLists.txt index 09193372..89342ec0 100644 --- a/test/sanity-check/c++11/CMakeLists.txt +++ b/test/sanity-check/c++11/CMakeLists.txt @@ -173,6 +173,7 @@ target_sources(t11 PRIVATE etl_profile.h ../numeric.h.t.cpp ../observer.h.t.cpp ../optional.h.t.cpp + ../overload.h.t.cpp ../packet.h.t.cpp ../parameter_pack.h.t.cpp ../parameter_type.h.t.cpp @@ -242,7 +243,8 @@ target_sources(t11 PRIVATE etl_profile.h ../user_type.h.t.cpp ../utility.h.t.cpp ../variance.h.t.cpp - ../variant.h.t.cpp + ../variant_legacy.h.t.cpp + ../variant_new.h.t.cpp ../variant_pool.h.t.cpp ../vector.h.t.cpp ../version.h.t.cpp diff --git a/test/sanity-check/c++14/CMakeLists.txt b/test/sanity-check/c++14/CMakeLists.txt index e514d386..65dcab43 100644 --- a/test/sanity-check/c++14/CMakeLists.txt +++ b/test/sanity-check/c++14/CMakeLists.txt @@ -173,6 +173,7 @@ target_sources(t14 PRIVATE etl_profile.h ../numeric.h.t.cpp ../observer.h.t.cpp ../optional.h.t.cpp + ../overload.h.t.cpp ../packet.h.t.cpp ../parameter_pack.h.t.cpp ../parameter_type.h.t.cpp @@ -242,7 +243,8 @@ target_sources(t14 PRIVATE etl_profile.h ../user_type.h.t.cpp ../utility.h.t.cpp ../variance.h.t.cpp - ../variant.h.t.cpp + ../variant_legacy.h.t.cpp + ../variant_new.h.t.cpp ../variant_pool.h.t.cpp ../vector.h.t.cpp ../version.h.t.cpp diff --git a/test/sanity-check/c++17/CMakeLists.txt b/test/sanity-check/c++17/CMakeLists.txt index dd6b754a..4e691395 100644 --- a/test/sanity-check/c++17/CMakeLists.txt +++ b/test/sanity-check/c++17/CMakeLists.txt @@ -173,6 +173,7 @@ target_sources(t17 PRIVATE etl_profile.h ../numeric.h.t.cpp ../observer.h.t.cpp ../optional.h.t.cpp + ../overload.h.t.cpp ../packet.h.t.cpp ../parameter_pack.h.t.cpp ../parameter_type.h.t.cpp @@ -242,7 +243,8 @@ target_sources(t17 PRIVATE etl_profile.h ../user_type.h.t.cpp ../utility.h.t.cpp ../variance.h.t.cpp - ../variant.h.t.cpp + ../variant_legacy.h.t.cpp + ../variant_new.h.t.cpp ../variant_pool.h.t.cpp ../vector.h.t.cpp ../version.h.t.cpp diff --git a/test/sanity-check/overload.h.t.cpp b/test/sanity-check/overload.h.t.cpp new file mode 100644 index 00000000..500f4bcb --- /dev/null +++ b/test/sanity-check/overload.h.t.cpp @@ -0,0 +1,29 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2021 John Wellbelove + +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. +******************************************************************************/ + +#include diff --git a/test/sanity-check/variant_legacy.h.t.cpp b/test/sanity-check/variant_legacy.h.t.cpp new file mode 100644 index 00000000..d95072de --- /dev/null +++ b/test/sanity-check/variant_legacy.h.t.cpp @@ -0,0 +1,29 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2021 John Wellbelove + +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. +******************************************************************************/ + +#include diff --git a/test/sanity-check/variant_new.h.t.cpp b/test/sanity-check/variant_new.h.t.cpp new file mode 100644 index 00000000..62b5bea7 --- /dev/null +++ b/test/sanity-check/variant_new.h.t.cpp @@ -0,0 +1,29 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2021 John Wellbelove + +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. +******************************************************************************/ + +#include diff --git a/test/sanity-check/variant_old.h.t.cpp b/test/sanity-check/variant_old.h.t.cpp new file mode 100644 index 00000000..c306bbfb --- /dev/null +++ b/test/sanity-check/variant_old.h.t.cpp @@ -0,0 +1,29 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2021 John Wellbelove + +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. +******************************************************************************/ + +#include diff --git a/test/test_overload.cpp b/test/test_overload.cpp new file mode 100644 index 00000000..31d8389f --- /dev/null +++ b/test/test_overload.cpp @@ -0,0 +1,164 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2015 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. +******************************************************************************/ + +#include "unit_test_framework.h" + +#include "etl/overload.h" + +#include + +namespace +{ + struct Result + { + Result() + : bi(false) + , bd(false) + , bs(false) + { + } + + void clear() + { + bi = false; + bd = false; + bs = false; + } + + bool bi; + bool bd; + bool bs; + }; + + Result result; + + struct Visitor + { + void operator ()(int i) { result.bi = true; } + void operator ()(double d) { result.bd = true; } + void operator ()(const std::string& s) { result.bs = true; } + }; + + template + void Function(T value, TOverload& ol) + { + ol(value); + } + + SUITE(test_overload) + { + //************************************************************************* + TEST(test_overload_lambdas) + { + auto overload = etl::make_overload([](int i) { result.bi = true; }, + [](double d) { result.bd = true; }, + [](const std::string& s) { result.bs = true; }); + + result.clear(); + Function(int(1), overload); + CHECK(result.bi == true); + CHECK(result.bd == false); + CHECK(result.bs == false); + + result.clear(); + Function(double(2.0), overload); + CHECK(result.bi == false); + CHECK(result.bd == true); + CHECK(result.bs == false); + + result.clear(); + Function(std::string("3"), overload); + CHECK(result.bi == false); + CHECK(result.bd == false); + CHECK(result.bs == true); + } + + //************************************************************************* + TEST(test_overload_lambdas_cpp17) + { +#if !defined(ETL_OVERLOAD_FORCE_CPP14) + result.clear(); + Function(int(1), etl::overload + { + [](int i) { result.bi = true; }, + [](double d) { result.bd = true; }, + [](const std::string& s) { result.bs = true; } + }); + CHECK(result.bi == true); + CHECK(result.bd == false); + CHECK(result.bs == false); + + result.clear(); + Function(double(2.0), etl::overload + { + [](int i) { result.bi = true; }, + [](double d) { result.bd = true; }, + [](const std::string& s) { result.bs = true; } + }); + CHECK(result.bi == false); + CHECK(result.bd == true); + CHECK(result.bs == false); + + result.clear(); + Function(std::string("3"), etl::overload + { + [](int i) { result.bi = true; }, + [](double d) { result.bd = true; }, + [](const std::string& s) { result.bs = true; } + }); + CHECK(result.bi == false); + CHECK(result.bd == false); + CHECK(result.bs == true); +#endif + } + + //************************************************************************* + TEST(test_visitor_overload) + { + auto overload = etl::make_overload(Visitor()); + + result.clear(); + Function(int(1), overload); + CHECK(result.bi == true); + CHECK(result.bd == false); + CHECK(result.bs == false); + + result.clear(); + Function(double(2.0), overload); + CHECK(result.bi == false); + CHECK(result.bd == true); + CHECK(result.bs == false); + + result.clear(); + Function(std::string("3"), overload); + CHECK(result.bi == false); + CHECK(result.bd == false); + CHECK(result.bs == true); + } + }; +} diff --git a/test/test_variant_new.cpp b/test/test_variant_new.cpp index e19a74bc..db279ece 100644 --- a/test/test_variant_new.cpp +++ b/test/test_variant_new.cpp @@ -36,11 +36,13 @@ SOFTWARE. #include #include #include +#include namespace { - // Test variant types. - typedef etl::variant test_variant_3; + // Test variant_etl types. + using test_variant_etl_3 = etl::variant; + using test_variant_std_3 = std::variant; struct D1 { @@ -162,6 +164,67 @@ namespace typedef etl::variant test_variant_emplace; + //********************************************* + struct Copyable + { + Copyable() + : copied_from(false) + , copied_to(false) + { + } + + Copyable(const Copyable& other) noexcept + { + copied_to = true; + copied_from = false; + } + + Copyable& operator =(const Copyable& rhs) noexcept + { + copied_to = true; + copied_from = false; + + return *this; + } + + bool copied_from; + bool copied_to; + }; + + //********************************************* + struct Moveable + { + Moveable() + : moved_from(false) + , moved_to(false) + { + } + + Moveable(Moveable&& other) noexcept + { + moved_to = true; + moved_from = false; + other.moved_to = false; + other.moved_from = true; + } + + Moveable& operator =(Moveable&& rhs) noexcept + { + moved_to = true; + moved_from = false; + rhs.moved_to = false; + rhs.moved_from = true; + + return *this; + } + + Moveable(const Moveable& other) = delete; + Moveable& operator =(const Moveable& rhs) = delete; + + bool moved_from; + bool moved_to; + }; + SUITE(test_variant) { TEST(test_alignment) @@ -176,20 +239,20 @@ namespace static test_variant_c c(3); static test_variant_d d(4.5); - CHECK((uintptr_t(&a.get()) % uintptr_t(etl::alignment_of::value)) == 0); - CHECK((uintptr_t(&b.get()) % uintptr_t(etl::alignment_of::value)) == 0); - CHECK((uintptr_t(&c.get()) % uintptr_t(etl::alignment_of::value)) == 0); - CHECK((uintptr_t(&d.get()) % uintptr_t(etl::alignment_of::value)) == 0); + CHECK((uintptr_t(&etl::get(a)) % uintptr_t(etl::alignment_of::value)) == 0); + CHECK((uintptr_t(&etl::get(b)) % uintptr_t(etl::alignment_of::value)) == 0); + CHECK((uintptr_t(&etl::get(c)) % uintptr_t(etl::alignment_of::value)) == 0); + CHECK((uintptr_t(&etl::get(d)) % uintptr_t(etl::alignment_of::value)) == 0); } //************************************************************************* TEST(test_constructor_default) { - CHECK_NO_THROW(test_variant_3 variant); + CHECK_NO_THROW(test_variant_etl_3 variant_etl); - test_variant_3 variant; + test_variant_etl_3 variant_etl; - CHECK(etl::holds_alternative(variant)); + CHECK(etl::holds_alternative(variant_etl)); } //************************************************************************* @@ -197,24 +260,24 @@ namespace { // Char. char c = 'a'; - test_variant_3 variant_char(c); - - CHECK(etl::holds_alternative(variant_char)); - CHECK_EQUAL(c, etl::get(variant_char)); + test_variant_etl_3 variant_char_etl(c); + CHECK(c == 'a'); + CHECK(etl::holds_alternative(variant_char_etl)); + CHECK_EQUAL(c, etl::get(variant_char_etl)); // Int. int i = 1; - test_variant_3 variant_int(i); - - CHECK(etl::holds_alternative(variant_int)); - CHECK_EQUAL(i, etl::get(variant_int)); + test_variant_etl_3 variant_int_etl(i); + CHECK(i == 1); + CHECK(etl::holds_alternative(variant_int_etl)); + CHECK_EQUAL(i, etl::get(variant_int_etl)); // String. std::string text("Some Text"); - test_variant_3 variant_text(text); - - CHECK(etl::holds_alternative(variant_text)); - CHECK_EQUAL(text, etl::get(variant_text)); + test_variant_etl_3 variant_text_etl(text); + CHECK(text == "Some Text"); + CHECK(etl::holds_alternative(variant_text_etl)); + CHECK_EQUAL(text, etl::get(variant_text_etl)); } //************************************************************************* @@ -222,72 +285,122 @@ namespace { // Char. char c = 'a'; - test_variant_3 variant_char(etl::move(c)); - - CHECK(etl::holds_alternative(variant_char)); - CHECK_EQUAL(c, etl::get(variant_char)); + test_variant_etl_3 variant_char_etl(etl::move(c)); + CHECK(etl::holds_alternative(variant_char_etl)); + CHECK_EQUAL(c, etl::get(variant_char_etl)); // Int. int i = 1; - test_variant_3 variant_int(etl::move(i)); - - CHECK(etl::holds_alternative(variant_int)); - CHECK_EQUAL(i, etl::get(variant_int)); + test_variant_etl_3 variant_int_etl(etl::move(i)); + CHECK(etl::holds_alternative(variant_int_etl)); + CHECK_EQUAL(i, etl::get(variant_int_etl)); // String. std::string text("Some Text"); - test_variant_3 variant_text(etl::move(text)); + test_variant_etl_3 variant_text_etl(etl::move(text)); + CHECK(etl::holds_alternative(variant_text_etl)); + CHECK_EQUAL(std::string("Some Text"), etl::get(variant_text_etl)); + } - CHECK(etl::holds_alternative(variant_text)); - CHECK_EQUAL(text, etl::get(variant_text)); + //************************************************************************* + TEST(test_emplace_value) + { + // Char. + char c = 'a'; + test_variant_etl_3 variant_char_etl; + + variant_char_etl.emplace(c); + CHECK(c == 'a'); + CHECK(etl::holds_alternative(variant_char_etl)); + CHECK_EQUAL(c, etl::get(variant_char_etl)); + + // Int. + int i = 1; + test_variant_etl_3 variant_int_etl; + + variant_int_etl.emplace(i); + CHECK(i == 1); + CHECK(etl::holds_alternative(variant_int_etl)); + CHECK_EQUAL(i, etl::get(variant_int_etl)); + + // String. + std::string text("Some Text"); + test_variant_etl_3 variant_text_etl; + + variant_text_etl.emplace(text); + CHECK(text == "Some Text"); + CHECK(etl::holds_alternative(variant_text_etl)); + CHECK_EQUAL(text, etl::get(variant_text_etl)); } //************************************************************************* TEST(test_copy_constructor) { std::string text("Some Text"); - test_variant_3 variant_1(text); + test_variant_etl_3 variant_1_etl(text); - test_variant_3 variant_2(variant_1); + test_variant_etl_3 variant_2_etl(variant_1_etl); - CHECK_EQUAL(variant_1.index(), variant_2.index()); - CHECK_EQUAL(variant_1.get(), variant_2.get()); + CHECK_EQUAL(variant_1_etl.index(), variant_2_etl.index()); + CHECK_EQUAL(etl::get(variant_1_etl), etl::get(variant_2_etl)); + } + + //************************************************************************* + TEST(test_copy_constructor_from_empty) + { + std::string text("Some Text"); + test_variant_etl_3 variant_1_etl; + + test_variant_etl_3 variant_2_etl(variant_1_etl); + + CHECK_EQUAL(variant_1_etl.index(), variant_2_etl.index()); } //************************************************************************* TEST(test_move_constructor) { std::string text("Some Text"); - test_variant_3 variant_1(text); + test_variant_etl_3 variant_1_etl(text); - test_variant_3 variant_2(etl::move(variant_1)); + test_variant_etl_3 variant_2_etl(etl::move(variant_1_etl)); - CHECK_EQUAL(variant_1.index(), variant_2.index()); - CHECK_EQUAL(variant_1.get(), variant_2.get()); + CHECK_EQUAL(variant_1_etl.index(), variant_2_etl.index()); + CHECK_EQUAL(etl::get(variant_1_etl), etl::get(variant_2_etl)); + } + + //************************************************************************* + TEST(test_move_constructor_from_empty) + { + std::string text("Some Text"); + test_variant_etl_3 variant_1_etl; + + test_variant_etl_3 variant_2_etl(etl::move(variant_1_etl)); + + CHECK_EQUAL(variant_1_etl.index(), variant_2_etl.index()); } //************************************************************************* TEST(test_assign_from_value) { std::string text("Some Text"); - test_variant_3 variant; + test_variant_etl_3 variant_etl; - variant = text; + variant_etl = text; - CHECK_EQUAL(text, variant.get()); + CHECK_EQUAL(text, etl::get(variant_etl)); } //************************************************************************* TEST(test_assign_from_variant) { std::string text("Some Text"); - test_variant_3 variant_1; - test_variant_3 variant_2; + test_variant_etl_3 variant_1_etl; + test_variant_etl_3 variant_2_etl; - variant_1 = text; - variant_2 = variant_1; + variant_1_etl = text; + variant_2_etl = variant_1_etl; - CHECK_EQUAL(text, variant_2.get()); + CHECK_EQUAL(text, etl::get(variant_2_etl)); } //************************************************************************* @@ -295,36 +408,36 @@ namespace { std::string text("Some Text"); int integer(99); - test_variant_3 variant_1; - test_variant_3 variant_2; + test_variant_etl_3 variant_1_etl; + test_variant_etl_3 variant_2_etl; - variant_1 = text; - variant_2 = integer; - variant_2 = variant_1; + variant_1_etl = text; + variant_2_etl = integer; + variant_2_etl = variant_1_etl; - CHECK_EQUAL(text, variant_2.get()); + CHECK_EQUAL(text, etl::get(variant_2_etl)); } //************************************************************************* TEST(test_assignment_incorrect_type_exception) { std::string text("Some Text"); - test_variant_3 variant(text); + test_variant_etl_3 variant_etl(text); int i; - CHECK_THROW(etl::get(variant), etl::variant_incorrect_type_exception); + CHECK_THROW(etl::get(variant_etl), etl::variant_incorrect_type_exception); (void)i; } //************************************************************************* TEST(test_self_assignment) { - test_variant_3 variant; + test_variant_etl_3 variant_etl; - variant = 1; - variant = variant; + variant_etl = 1; + variant_etl = variant_etl; - CHECK_EQUAL(1, etl::get(variant)); + CHECK_EQUAL(1, etl::get(variant_etl)); } //************************************************************************* @@ -332,16 +445,16 @@ namespace { std::string text("Some Text"); int integer(99); - test_variant_3 variant_1(text); - test_variant_3 variant_2(integer); + test_variant_etl_3 variant_1_etl(text); + test_variant_etl_3 variant_2_etl(integer); - variant_1.swap(variant_2); + variant_1_etl.swap(variant_2_etl); - CHECK(etl::holds_alternative(variant_1)); - CHECK_EQUAL(integer, etl::get(variant_1)); + CHECK(etl::holds_alternative(variant_1_etl)); + CHECK_EQUAL(integer, etl::get(variant_1_etl)); - CHECK(etl::holds_alternative(variant_2)); - CHECK_EQUAL(text, etl::get(variant_2)); + CHECK(etl::holds_alternative(variant_2_etl)); + CHECK_EQUAL(text, etl::get(variant_2_etl)); } //************************************************************************* @@ -349,38 +462,38 @@ namespace { std::string text("Some Text"); int integer(99); - test_variant_3 variant_1(text); - test_variant_3 variant_2(integer); + test_variant_etl_3 variant_1_etl(text); + test_variant_etl_3 variant_2_etl(integer); - etl::swap(variant_1, variant_2); + etl::swap(variant_1_etl, variant_2_etl); - CHECK(etl::holds_alternative(variant_1)); - CHECK_EQUAL(integer, etl::get(variant_1)); + CHECK(etl::holds_alternative(variant_1_etl)); + CHECK_EQUAL(integer, etl::get(variant_1_etl)); - CHECK(etl::holds_alternative(variant_2)); - CHECK_EQUAL(text, etl::get(variant_2)); + CHECK(etl::holds_alternative(variant_2_etl)); + CHECK_EQUAL(text, etl::get(variant_2_etl)); } //************************************************************************* TEST(test_emplace) { - test_variant_emplace variant; + test_variant_emplace variant_etl; - variant.emplace("1"); - CHECK(etl::holds_alternative(variant)); - CHECK_EQUAL(D1("1"), etl::get(variant)); + variant_etl.emplace("1"); + CHECK(etl::holds_alternative(variant_etl)); + CHECK_EQUAL(D1("1"), etl::get(variant_etl)); - variant.emplace("1", "2"); - CHECK(etl::holds_alternative(variant)); - CHECK_EQUAL(D2("1", "2"), etl::get(variant)); + variant_etl.emplace("1", "2"); + CHECK(etl::holds_alternative(variant_etl)); + CHECK_EQUAL(D2("1", "2"), etl::get(variant_etl)); - variant.emplace("1", "2", "3"); - CHECK(etl::holds_alternative(variant)); - CHECK_EQUAL(D3("1", "2", "3"), etl::get(variant)); + variant_etl.emplace("1", "2", "3"); + CHECK(etl::holds_alternative(variant_etl)); + CHECK_EQUAL(D3("1", "2", "3"), etl::get(variant_etl)); - variant.emplace("1", "2", "3", "4"); - CHECK(etl::holds_alternative(variant)); - CHECK_EQUAL(D4("1", "2", "3", "4"), etl::get(variant)); + variant_etl.emplace("1", "2", "3", "4"); + CHECK(etl::holds_alternative(variant_etl)); + CHECK_EQUAL(D4("1", "2", "3", "4"), etl::get(variant_etl)); } //************************************************************************* @@ -393,9 +506,9 @@ namespace { D1 da("1"); - test_variant_emplace variant(etl::move(getD1())); + test_variant_emplace variant_etl(etl::move(getD1())); - D1 db = etl::move(etl::get(variant)); + D1 db = etl::move(etl::get(variant_etl)); } //************************************************************************* @@ -432,18 +545,18 @@ namespace Visitor visitor; - test_variant_3 variant; + test_variant_etl_3 variant_etl; - variant = char(1); - variant.accept(visitor); + variant_etl = char(1); + variant_etl.accept(visitor); CHECK_EQUAL(1, visitor.result_c); - variant = int(2); - variant.accept(visitor); + variant_etl = int(2); + variant_etl.accept(visitor); CHECK_EQUAL(2, visitor.result_i); - variant = std::string("3"); - variant.accept(visitor); + variant_etl = std::string("3"); + variant_etl.accept(visitor); CHECK_EQUAL("3", visitor.result_s); } @@ -481,19 +594,137 @@ namespace Visitor visitor; - test_variant_3 variant; + test_variant_etl_3 variant_etl; - variant = char(1); - variant(visitor); + variant_etl = char(1); + variant_etl(visitor); CHECK_EQUAL(1, visitor.result_c); - variant = int(2); - variant(visitor); + variant_etl = int(2); + variant_etl(visitor); CHECK_EQUAL(2, visitor.result_i); - variant = std::string("3"); - variant(visitor); + variant_etl = std::string("3"); + variant_etl(visitor); CHECK_EQUAL("3", visitor.result_s); } + + //************************************************************************* + TEST(test_get_if_index) + { + test_variant_etl_3 variant_etl; + + variant_etl = char(1); + CHECK(etl::get_if<0>(&variant_etl) != nullptr); + CHECK(etl::get_if<0>(variant_etl) != nullptr); + CHECK(etl::get_if<1>(&variant_etl) == nullptr); + CHECK(etl::get_if<1>(variant_etl) == nullptr); + CHECK(etl::get_if<2>(&variant_etl) == nullptr); + CHECK(etl::get_if<2>(variant_etl) == nullptr); + + variant_etl = int(2); + CHECK(etl::get_if<0>(&variant_etl) == nullptr); + CHECK(etl::get_if<0>(variant_etl) == nullptr); + CHECK(etl::get_if<1>(&variant_etl) != nullptr); + CHECK(etl::get_if<1>(variant_etl) != nullptr); + CHECK(etl::get_if<2>(&variant_etl) == nullptr); + CHECK(etl::get_if<2>(variant_etl) == nullptr); + + variant_etl = std::string("3"); + CHECK(etl::get_if<0>(&variant_etl) == nullptr); + CHECK(etl::get_if<0>(variant_etl) == nullptr); + CHECK(etl::get_if<1>(&variant_etl) == nullptr); + CHECK(etl::get_if<1>(variant_etl) == nullptr); + CHECK(etl::get_if<2>(&variant_etl) != nullptr); + CHECK(etl::get_if<2>(variant_etl) != nullptr); + } + + //************************************************************************* + TEST(test_get_if_type) + { + test_variant_etl_3 variant_etl; + + variant_etl = char(1); + CHECK(etl::get_if(&variant_etl) != nullptr); + CHECK(etl::get_if(variant_etl) != nullptr); + CHECK(etl::get_if(&variant_etl) == nullptr); + CHECK(etl::get_if(variant_etl) == nullptr); + CHECK(etl::get_if(&variant_etl) == nullptr); + CHECK(etl::get_if(variant_etl) == nullptr); + + variant_etl = int(2); + CHECK(etl::get_if(&variant_etl) == nullptr); + CHECK(etl::get_if(variant_etl) == nullptr); + CHECK(etl::get_if(&variant_etl) != nullptr); + CHECK(etl::get_if(variant_etl) != nullptr); + CHECK(etl::get_if(&variant_etl) == nullptr); + CHECK(etl::get_if(variant_etl) == nullptr); + + variant_etl = std::string("3"); + CHECK(etl::get_if(&variant_etl) == nullptr); + CHECK(etl::get_if(variant_etl) == nullptr); + CHECK(etl::get_if(&variant_etl) == nullptr); + CHECK(etl::get_if(variant_etl) == nullptr); + CHECK(etl::get_if(&variant_etl) != nullptr); + CHECK(etl::get_if(variant_etl) != nullptr); + } + + //************************************************************************* + TEST(test_variant_size) + { + test_variant_etl_3 variant_etl; + + CHECK_EQUAL(3U, etl::variant_size_v); + } + + //************************************************************************* + TEST(test_compare_etl_and_stl_variant_with_moveable_type) + { + Moveable from_etl; + Moveable to_etl; + + Moveable from_std; + Moveable to_std; + + etl::variant variant_etl; + std::variant variant_std; + + variant_etl = etl::move(from_etl); + variant_std = etl::move(from_std); + + CHECK_EQUAL(from_std.moved_from, from_etl.moved_from); + CHECK_EQUAL(from_std.moved_to, from_etl.moved_to); + + to_etl = etl::move(etl::get<0>(variant_etl)); + to_std = etl::move(std::get<0>(variant_std)); + + CHECK_EQUAL(to_std.moved_from, to_etl.moved_from); + CHECK_EQUAL(to_std.moved_to, to_etl.moved_to); + } + + //************************************************************************* + TEST(test_compare_etl_and_stl_variant_with_copyable_type) + { + Copyable from_etl; + Copyable to_etl; + + Copyable from_std; + Copyable to_std; + + etl::variant variant_etl; + std::variant variant_std; + + variant_etl = from_etl; + variant_std = from_std; + + CHECK_EQUAL(from_std.copied_from, from_etl.copied_from); + CHECK_EQUAL(from_std.copied_to, from_etl.copied_to); + + to_etl = etl::get<0>(variant_etl); + to_std = std::get<0>(variant_std); + + CHECK_EQUAL(to_std.copied_from, to_etl.copied_from); + CHECK_EQUAL(to_std.copied_to, to_etl.copied_to); + } }; } diff --git a/test/vs2019/etl.vcxproj b/test/vs2019/etl.vcxproj index 809344d5..dd638032 100644 --- a/test/vs2019/etl.vcxproj +++ b/test/vs2019/etl.vcxproj @@ -3477,6 +3477,23 @@ true true + + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true true @@ -4353,6 +4370,40 @@ true true + + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true true @@ -4887,6 +4938,7 @@ false + diff --git a/test/vs2019/etl.vcxproj.filters b/test/vs2019/etl.vcxproj.filters index 7355962b..d5ee5e95 100644 --- a/test/vs2019/etl.vcxproj.filters +++ b/test/vs2019/etl.vcxproj.filters @@ -1137,6 +1137,9 @@ ETL\Patterns + + Header Files + @@ -2576,6 +2579,18 @@ Source Files\Sanity Checks + + Source Files\Sanity Checks + + + Source Files\Sanity Checks + + + Source Files\Sanity Checks + + + Source Files +