From 9c68847c5c1851e96f55d7696b3e830731c2b2af Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Thu, 15 Jul 2021 12:57:46 +0100 Subject: [PATCH] Compiler compatibility changes --- include/etl/private/variant_new.h | 613 ++++++++++++++++++++---------- include/etl/utility.h | 12 +- test/etl_profile.h | 2 +- test/test_variant_new.cpp | 64 ++++ 4 files changed, 487 insertions(+), 204 deletions(-) diff --git a/include/etl/private/variant_new.h b/include/etl/private/variant_new.h index 2e4d379f..2fe4865c 100644 --- a/include/etl/private/variant_new.h +++ b/include/etl/private/variant_new.h @@ -143,15 +143,206 @@ namespace etl template using type_from_index_t = typename type_from_index::type; }; + + //******************************************* + // The traits an object may have. + //******************************************* + static constexpr bool Copyable = true; + static constexpr bool Non_Copyable = false; + static constexpr bool Moveable = true; + static constexpr bool Non_Moveable = false; + + //******************************************* + // The types of operations we can perform. + //******************************************* + static constexpr int Copy = 0; + static constexpr int Move = 1; + static constexpr int Destroy = 2; + + //******************************************* + // operation_type + //******************************************* + template + struct operation_type; + + //******************************************* + // Specialisation for null operation. + template <> + struct operation_type + { + static void do_operation(int operation, char* pstorage, const char* pvalue) + { + // This should never occur. +#if defined(ETL_IN_UNIT_TEST) + assert(false); +#endif + } + }; + + //******************************************* + // Specialisation for no-copyable & non-moveable types. + template + struct operation_type + { + static void do_operation(int operation, char* pstorage, const char* pvalue) + { + switch (operation) + { + case Destroy: + { + reinterpret_cast(pstorage)->~T(); + break; + } + + default: + { + // This should never occur. + #if defined(ETL_IN_UNIT_TEST) + assert(false); + #endif + break; + } + } + } + }; + + //******************************************* + // Specialisation for no-copyable & moveable types. + template + struct operation_type + { + static void do_operation(int operation, char* pstorage, const char* pvalue) + { + switch (operation) + { + case Move: + { + ::new (pstorage) T(etl::move(*reinterpret_cast(const_cast(pvalue)))); + break; + } + + case Destroy: + { + reinterpret_cast(pstorage)->~T(); + break; + } + + default: + { + // This should never occur. + #if defined(ETL_IN_UNIT_TEST) + assert(false); + #endif + break; + } + } + } + }; + + //******************************************* + // Specialisation for copyable & non-moveable types. + template + struct operation_type + { + static void do_operation(int operation, char* pstorage, const char* pvalue) + { + switch (operation) + { + case Copy: + { + ::new (pstorage) T(*reinterpret_cast(pvalue)); + break; + } + + case Destroy: + { + reinterpret_cast(pstorage)->~T(); + break; + } + + default: + { + // This should never occur. + #if defined(ETL_IN_UNIT_TEST) + assert(false); + #endif + break; + } + } + } + }; + + //******************************************* + // Specialisation for copyable & moveable types. + template + struct operation_type + { + static void do_operation(int operation, char* pstorage, const char* pvalue) + { + switch (operation) + { + case Copy: + { + ::new (pstorage) T(*reinterpret_cast(pvalue)); + break; + } + + case Move: + { + ::new (pstorage) T(etl::move(*reinterpret_cast(const_cast(pvalue)))); + break; + } + + case Destroy: + { + reinterpret_cast(pstorage)->~T(); + break; + } + + default: + { + // This should never occur. +#if defined(ETL_IN_UNIT_TEST) + assert(false); +#endif + break; + } + } + } + }; } /// Definition of variant_npos. constexpr size_t variant_npos = etl::integral_limits::max; - // Forward declarations. + //*********************************** + // variant. Forward declaration template class variant; + //*************************************************************************** + /// variant_alternative + //*************************************************************************** + template + struct variant_alternative; + + template + struct variant_alternative> + { + using type = typename etl::private_variant::parameter_pack::template type_from_index::type; + }; + + template + struct variant_alternative + { + using type = typename variant_alternative::type; + }; + + template + using variant_alternative_t = typename variant_alternative::type; + + //*********************************** + // holds_alternative. Forward declaration template ETL_CONSTEXPR14 bool holds_alternative(const etl::variant& v) noexcept; @@ -213,14 +404,6 @@ namespace etl private: - // The type of operations we can perform. - enum class command - { - Copy, - Move, - Destroy - }; - // All types of variant are friends. template friend class variant; @@ -240,13 +423,20 @@ namespace etl //*************************************************************************** static const size_t Alignment = etl::largest_alignment::value; - public: + //*************************************************************************** + /// The operation templates. + //*************************************************************************** + template + using operation_type = private_variant::operation_type; - //*************************************************************************** - /// The internal storage. - /// Aligned on a suitable boundary, which should be good for all types. - //*************************************************************************** - etl::uninitialized_buffer data; + //******************************************* + // The types of operations we can perform. + //******************************************* + static constexpr int Copy = private_variant::Copy; + static constexpr int Move = private_variant::Move; + static constexpr int Destroy = private_variant::Destroy; + + public: //*************************************************************************** /// Default constructor. @@ -285,7 +475,7 @@ namespace etl , operation(operation_type, etl::is_copy_constructible>::value, etl::is_move_constructible>::value>::do_operation) , type_id(etl::private_variant::parameter_pack::template index_of_type>::value) { - static_assert(etl::is_one_of>, TTypes...>::value, "Unsupported type"); + static_assert(etl::is_one_of, TTypes...>::value, "Unsupported type"); construct_in_place_args>(data, std::forward(args)...); } @@ -299,7 +489,7 @@ namespace etl , type_id(Index) { using type = typename private_variant::parameter_pack:: template type_from_index_t; - static_assert(etl::is_one_of, TTypes... > ::value, "Unsupported type"); + static_assert(etl::is_one_of ::value, "Unsupported type"); construct_in_place_args(data, std::forward(args)...); @@ -313,12 +503,12 @@ namespace etl template ETL_CONSTEXPR14 explicit variant(etl::in_place_type_t, std::initializer_list init, TArgs&&... args) : data() - , operation(operation_type>, etl::is_copy_constructible>::value, etl::is_move_constructible::etl::remove_reference_t>::do_operation) + , operation(operation_type, etl::is_copy_constructible>::value, etl::is_move_constructible>::value>::do_operation) , type_id(private_variant::parameter_pack:: template index_of_type>::value) { - static_assert(etl::is_one_of>, TTypes... > ::value, "Unsupported type"); + static_assert(etl::is_one_of, TTypes...> ::value, "Unsupported type"); - construct_in_place_args>(data, std::forward(args)...); + construct_in_place_args>(data, init, std::forward(args)...); } //*************************************************************************** @@ -330,9 +520,9 @@ namespace etl , type_id(Index) { using type = typename private_variant::parameter_pack:: template type_from_index_t; - static_assert(etl::is_one_of, TTypes... > ::value, "Unsupported type"); + static_assert(etl::is_one_of ::value, "Unsupported type"); - construct_in_place_args(data, std::forward(args)...); + construct_in_place_args(data, init, std::forward(args)...); operation = operation_type::value, etl::is_move_constructible::value>::do_operation; } @@ -355,7 +545,7 @@ namespace etl } else { - operation(command::Copy, data, other.data); + operation(private_variant::Copy, data, other.data); } } } @@ -377,7 +567,7 @@ namespace etl } else { - operation(command::Move, data, other.data); + operation(private_variant::Move, data, other.data); } } else @@ -393,7 +583,7 @@ namespace etl { if (index() != variant_npos) { - operation(command::Destroy, data, nullptr); + operation(private_variant::Destroy, data, nullptr); } operation = operation_type::do_operation; // Null operation. @@ -410,7 +600,7 @@ namespace etl using type = etl::remove_reference_t; - operation(command::Destroy, data, nullptr); + operation(private_variant::Destroy, data, nullptr); construct_in_place_args(data, std::forward(args)...); @@ -432,7 +622,7 @@ namespace etl static_assert(etl::is_one_of::value, "Unsupported type"); - operation(command::Destroy, data, nullptr); + operation(private_variant::Destroy, data, nullptr); construct_in_place(data, etl::forward(value)); @@ -456,10 +646,10 @@ namespace etl } else { - operation(command::Destroy, data, nullptr); + operation(Destroy, data, nullptr); operation = other.operation; - operation(command::Copy, data, other.data); + operation(Copy, data, other.data); type_id = other.type_id; } @@ -482,10 +672,10 @@ namespace etl } else { - operation(command::Destroy, data, nullptr); + operation(Destroy, data, nullptr); operation = other.operation; - operation(command::Move, data, other.data); + operation(Move, data, other.data); type_id = other.type_id; } @@ -546,10 +736,41 @@ namespace etl #endif } + //*************************************************************************** + /// get() is a friend function. + //*************************************************************************** + template + friend ETL_CONSTEXPR14 etl::variant_alternative_t>& + get(etl::variant& v); + + template + friend ETL_CONSTEXPR14 etl::variant_alternative_t>&& + get(etl::variant&& v); + + template + friend ETL_CONSTEXPR14 const etl::variant_alternative_t>& + get(const etl::variant& v); + + template + friend ETL_CONSTEXPR14 const etl::variant_alternative_t>&& + get(const etl::variant&& v); + + template + friend ETL_CONSTEXPR14 T& get(etl::variant& v); + + template + friend ETL_CONSTEXPR14 T&& get(etl::variant&& v); + + template + friend ETL_CONSTEXPR14 const T& get(const etl::variant& v); + + template + friend ETL_CONSTEXPR14 const T&& get(const etl::variant&& v); + private: /// The operation function type. - using operation_function = void(*)(command, char*, const char*); + using operation_function = void(*)(int, char*, const char*); //*************************************************************************** /// Construct the type in-place. lvalue reference. @@ -595,153 +816,160 @@ namespace etl ::new (pstorage) type(); } - //******************************************* - // Declaration. - template - struct operation_type; - - //******************************************* - // Specialisation for null operation. - template <> - struct operation_type - { - static void do_operation(variant::command operation, char* pstorage, const char* pvalue) - { - // This should never occur. -#if defined(ETL_IN_UNIT_TEST) - assert(false); -#endif - } - }; - - //******************************************* - // Specialisation for no-copyable & non-moveable types. - template - struct operation_type - { - static void do_operation(variant::command operation, char* pstorage, const char* pvalue) - { - switch (operation) - { - case variant::command::Destroy: - { - reinterpret_cast(pstorage)->~T(); - break; - } - - default: - { - // This should never occur. -#if defined(ETL_IN_UNIT_TEST) - assert(false); -#endif - break; - } - } - } - }; - - //******************************************* - // Specialisation for no-copyable & moveable types. - template - struct operation_type - { - static void do_operation(variant::command operation, char* pstorage, const char* pvalue) - { - switch (operation) - { - case variant::command::Move: - { - ::new (pstorage) T(etl::move(*reinterpret_cast(const_cast(pvalue)))); - break; - } - - case variant::command::Destroy: - { - reinterpret_cast(pstorage)->~T(); - break; - } - - default: - { - // This should never occur. -#if defined(ETL_IN_UNIT_TEST) - assert(false); -#endif - break; - } - } - } - }; - - //******************************************* - // Specialisation for copyable & non-moveable types. - template - struct operation_type - { - static void do_operation(variant::command operation, char* pstorage, const char* pvalue) - { - switch (operation) - { - case variant::command::Copy: - { - ::new (pstorage) T(*reinterpret_cast(pvalue)); - break; - } - - case variant::command::Destroy: - { - reinterpret_cast(pstorage)->~T(); - break; - } - - default: - { - // This should never occur. -#if defined(ETL_IN_UNIT_TEST) - assert(false); -#endif - break; - } - } - } - }; - - //******************************************* - // Specialisation for copyable & moveable types. - template - struct operation_type - { - static void do_operation(variant::command command, char* pstorage, const char* pvalue) - { - switch (command) - { - case variant::command::Copy: - { - ::new (pstorage) T(*reinterpret_cast(pvalue)); - break; - } - - case variant::command::Move: - { - ::new (pstorage) T(etl::move(*reinterpret_cast(const_cast(pvalue)))); - break; - } - - case variant::command::Destroy: - { - reinterpret_cast(pstorage)->~T(); - break; - } - - default: - { - assert(false); - break; - } - } - } - }; +// //******************************************* +// // The traits an object may have. +// static constexpr bool Copyable = true; +// static constexpr bool Non_Copyable = false; +// static constexpr bool Moveable = true; +// static constexpr bool Non_Moveable = false; +// +// //******************************************* +// // Declaration. +// template +// struct operation_type; +// +// //******************************************* +// // Specialisation for null operation. +// template <> +// struct operation_type +// { +// static void do_operation(variant::int operation, char* pstorage, const char* pvalue) +// { +// // This should never occur. +//#if defined(ETL_IN_UNIT_TEST) +// assert(false); +//#endif +// } +// }; +// +// //******************************************* +// // Specialisation for no-copyable & non-moveable types. +// template +// struct operation_type +// { +// static void do_operation(variant::int operation, char* pstorage, const char* pvalue) +// { +// switch (operation) +// { +// case variant::Destroy: +// { +// reinterpret_cast(pstorage)->~T(); +// break; +// } +// +// default: +// { +// // This should never occur. +//#if defined(ETL_IN_UNIT_TEST) +// assert(false); +//#endif +// break; +// } +// } +// } +// }; +// +// //******************************************* +// // Specialisation for no-copyable & moveable types. +// template +// struct operation_type +// { +// static void do_operation(variant::int operation, char* pstorage, const char* pvalue) +// { +// switch (operation) +// { +// case variant::Move: +// { +// ::new (pstorage) T(etl::move(*reinterpret_cast(const_cast(pvalue)))); +// break; +// } +// +// case variant::Destroy: +// { +// reinterpret_cast(pstorage)->~T(); +// break; +// } +// +// default: +// { +// // This should never occur. +//#if defined(ETL_IN_UNIT_TEST) +// assert(false); +//#endif +// break; +// } +// } +// } +// }; +// +// //******************************************* +// // Specialisation for copyable & non-moveable types. +// template +// struct operation_type +// { +// static void do_operation(variant::int operation, char* pstorage, const char* pvalue) +// { +// switch (operation) +// { +// case variant::Copy: +// { +// ::new (pstorage) T(*reinterpret_cast(pvalue)); +// break; +// } +// +// case variant::Destroy: +// { +// reinterpret_cast(pstorage)->~T(); +// break; +// } +// +// default: +// { +// // This should never occur. +//#if defined(ETL_IN_UNIT_TEST) +// assert(false); +//#endif +// break; +// } +// } +// } +// }; +// +// //******************************************* +// // Specialisation for copyable & moveable types. +// template +// struct operation_type +// { +// static void do_operation(variant::int int, char* pstorage, const char* pvalue) +// { +// switch (int) +// { +// case variant::Copy: +// { +// ::new (pstorage) T(*reinterpret_cast(pvalue)); +// break; +// } +// +// case variant::Move: +// { +// ::new (pstorage) T(etl::move(*reinterpret_cast(const_cast(pvalue)))); +// break; +// } +// +// case variant::Destroy: +// { +// reinterpret_cast(pstorage)->~T(); +// break; +// } +// +// default: +// { +// assert(false); +// break; +// } +// } +// } +// }; #if ETL_CPP17_SUPPORTED && !defined(ETL_VARIANT_FORCE_CPP11) //*************************************************************************** @@ -912,6 +1140,12 @@ namespace etl } } + //*************************************************************************** + /// The internal storage. + /// Aligned on a suitable boundary, which should be good for all types. + //*************************************************************************** + etl::uninitialized_buffer data; + //*************************************************************************** /// The operation function. //*************************************************************************** @@ -952,27 +1186,6 @@ namespace etl return (index == v.index()); } - //*************************************************************************** - /// variant_alternative - //*************************************************************************** - template - struct variant_alternative; - - template - struct variant_alternative> - { - using type = typename etl::private_variant::parameter_pack::template type_from_index::type; - }; - - template - struct variant_alternative - { - using type = typename variant_alternative::type; - }; - - template - using variant_alternative_t = typename variant_alternative::type; - //*************************************************************************** /// get //*************************************************************************** diff --git a/include/etl/utility.h b/include/etl/utility.h index adee90d8..df3f86e0 100644 --- a/include/etl/utility.h +++ b/include/etl/utility.h @@ -420,7 +420,9 @@ namespace etl explicit ETL_CONSTEXPR in_place_t() {} }; - inline ETL_CONSTANT in_place_t in_place; +#if ETL_CPP17_SUPPORTED + inline constexpr in_place_t in_place; +#endif //************************* template struct in_place_type_t @@ -428,8 +430,10 @@ namespace etl explicit ETL_CONSTEXPR in_place_type_t(){}; }; +#if ETL_CPP17_SUPPORTED template - inline ETL_CONSTANT in_place_type_t in_place_type; + inline constexpr in_place_type_t in_place_type; +#endif //************************* template struct in_place_index_t @@ -437,8 +441,10 @@ namespace etl explicit ETL_CONSTEXPR in_place_index_t() {} }; +#if ETL_CPP17_SUPPORTED template - inline ETL_CONSTANT in_place_index_t in_place_index; + inline constexpr in_place_index_t in_place_index; +#endif } #endif diff --git a/test/etl_profile.h b/test/etl_profile.h index ec26e76c..8b455130 100644 --- a/test/etl_profile.h +++ b/test/etl_profile.h @@ -101,7 +101,7 @@ SOFTWARE. #endif #define ETL_OVERLOAD_FORCE_CPP14 -#define ETL_VARIANT_FORCE_CPP11 +//#define ETL_VARIANT_FORCE_CPP11 #define ETL_VARIANT_CPP11_MAX_16_TYPES #if defined(ETL_NO_STL) diff --git a/test/test_variant_new.cpp b/test/test_variant_new.cpp index ae0cfc81..87079ab0 100644 --- a/test/test_variant_new.cpp +++ b/test/test_variant_new.cpp @@ -415,6 +415,70 @@ namespace CHECK_EQUAL(std::string("Some Text"), etl::get(variant_text_etl)); } + //************************************************************************* + TEST(test_construct_multiple_parameters_by_type) + { + test_variant_emplace variant_etl1(etl::in_place_type_t(), "1"); + CHECK(etl::holds_alternative(variant_etl1)); + CHECK_EQUAL(D1("1"), etl::get(variant_etl1)); + + test_variant_emplace variant_etl2(etl::in_place_type_t{}, "1", "2"); + CHECK(etl::holds_alternative(variant_etl2)); + CHECK_EQUAL(D2("1", "2"), etl::get(variant_etl2)); + + test_variant_emplace variant_etl3(etl::in_place_type_t{}, "1", "2", "3"); + CHECK(etl::holds_alternative(variant_etl3)); + CHECK_EQUAL(D3("1", "2", "3"), etl::get(variant_etl3)); + + test_variant_emplace variant_etl4(etl::in_place_type_t{}, "1", "2", "3", "4"); + CHECK(etl::holds_alternative(variant_etl4)); + CHECK_EQUAL(D4("1", "2", "3", "4"), etl::get(variant_etl4)); + } + + //************************************************************************* + TEST(test_construct_multiple_parameters_by_index) + { + test_variant_emplace variant_etl1(etl::in_place_index_t<1U>{}, "1"); + CHECK(etl::holds_alternative(variant_etl1)); + CHECK_EQUAL(D1("1"), etl::get(variant_etl1)); + + test_variant_emplace variant_etl2(etl::in_place_index_t<2>{}, "1", "2"); + CHECK(etl::holds_alternative(variant_etl2)); + CHECK_EQUAL(D2("1", "2"), etl::get(variant_etl2)); + + test_variant_emplace variant_etl3(etl::in_place_index_t<3>{}, "1", "2", "3"); + CHECK(etl::holds_alternative(variant_etl3)); + CHECK_EQUAL(D3("1", "2", "3"), etl::get(variant_etl3)); + + test_variant_emplace variant_etl4(etl::in_place_index_t<4U>{}, "1", "2", "3", "4"); + CHECK(etl::holds_alternative(variant_etl4)); + CHECK_EQUAL(D4("1", "2", "3", "4"), etl::get(variant_etl4)); + } + + //************************************************************************* + TEST(test_construct_with_initializer_list_by_type) + { + etl::variant, std::string> v(etl::in_place_type_t>{}, { 0, 1, 2, 3 }); + + std::vector expected = { 0, 1, 2, 3 }; + std::vector result = etl::get>(v); + + CHECK_EQUAL(expected.size(), result.size()); + CHECK_ARRAY_EQUAL(expected.data(), result.data(), expected.size()); + } + + //************************************************************************* + TEST(test_construct_with_initializer_list_by_index) + { + etl::variant, std::string> v(etl::in_place_index_t<0U>{}, { 0, 1, 2, 3 }); + + std::vector expected = { 0, 1, 2, 3 }; + std::vector result = etl::get>(v); + + CHECK_EQUAL(expected.size(), result.size()); + CHECK_ARRAY_EQUAL(expected.data(), result.data(), expected.size()); + } + //************************************************************************* TEST(test_emplace_value) {