Compiler compatibility changes

This commit is contained in:
John Wellbelove 2021-07-15 12:57:46 +01:00
parent de1a19775e
commit 9c68847c5c
4 changed files with 487 additions and 204 deletions

View File

@ -143,15 +143,206 @@ namespace etl
template <size_t I>
using type_from_index_t = typename type_from_index<I>::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 <typename T, bool IsCopyable, bool IsMoveable>
struct operation_type;
//*******************************************
// Specialisation for null operation.
template <>
struct operation_type<void, Non_Copyable, Non_Moveable>
{
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 <typename T>
struct operation_type<T, Non_Copyable, Non_Moveable>
{
static void do_operation(int operation, char* pstorage, const char* pvalue)
{
switch (operation)
{
case Destroy:
{
reinterpret_cast<const T*>(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 <typename T>
struct operation_type<T, Non_Copyable, Moveable>
{
static void do_operation(int operation, char* pstorage, const char* pvalue)
{
switch (operation)
{
case Move:
{
::new (pstorage) T(etl::move(*reinterpret_cast<T*>(const_cast<char*>(pvalue))));
break;
}
case Destroy:
{
reinterpret_cast<const T*>(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 <typename T>
struct operation_type<T, Copyable, Non_Moveable>
{
static void do_operation(int operation, char* pstorage, const char* pvalue)
{
switch (operation)
{
case Copy:
{
::new (pstorage) T(*reinterpret_cast<const T*>(pvalue));
break;
}
case Destroy:
{
reinterpret_cast<const T*>(pstorage)->~T();
break;
}
default:
{
// This should never occur.
#if defined(ETL_IN_UNIT_TEST)
assert(false);
#endif
break;
}
}
}
};
//*******************************************
// Specialisation for copyable & moveable types.
template <typename T>
struct operation_type<T, Copyable, Moveable>
{
static void do_operation(int operation, char* pstorage, const char* pvalue)
{
switch (operation)
{
case Copy:
{
::new (pstorage) T(*reinterpret_cast<const T*>(pvalue));
break;
}
case Move:
{
::new (pstorage) T(etl::move(*reinterpret_cast<T*>(const_cast<char*>(pvalue))));
break;
}
case Destroy:
{
reinterpret_cast<const T*>(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<size_t>::max;
// Forward declarations.
//***********************************
// variant. Forward declaration
template <typename... TTypes>
class variant;
//***************************************************************************
/// variant_alternative
//***************************************************************************
template <size_t Index, typename T>
struct variant_alternative;
template <size_t Index, typename... TTypes>
struct variant_alternative<Index, etl::variant<TTypes...>>
{
using type = typename etl::private_variant::parameter_pack<TTypes...>::template type_from_index<Index>::type;
};
template <size_t Index, typename T>
struct variant_alternative<Index, const T>
{
using type = typename variant_alternative<Index, T>::type;
};
template <size_t Index, typename T>
using variant_alternative_t = typename variant_alternative<Index, T>::type;
//***********************************
// holds_alternative. Forward declaration
template <typename T, typename... TTypes>
ETL_CONSTEXPR14 bool holds_alternative(const etl::variant<TTypes...>& 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 <typename... UTypes>
friend class variant;
@ -240,13 +423,20 @@ namespace etl
//***************************************************************************
static const size_t Alignment = etl::largest_alignment<TTypes...>::value;
public:
//***************************************************************************
/// The operation templates.
//***************************************************************************
template <typename T, bool IsCopyable, bool IsMoveable>
using operation_type = private_variant::operation_type<T, IsCopyable, IsMoveable>;
//***************************************************************************
/// The internal storage.
/// Aligned on a suitable boundary, which should be good for all types.
//***************************************************************************
etl::uninitialized_buffer<Size, 1U, Alignment> 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::remove_reference_t<T>, etl::is_copy_constructible<etl::remove_reference_t<T>>::value, etl::is_move_constructible<etl::remove_reference_t<T>>::value>::do_operation)
, type_id(etl::private_variant::parameter_pack<TTypes...>::template index_of_type<etl::remove_reference_t<T>>::value)
{
static_assert(etl::is_one_of<etl::remove_reference_t<T>>, TTypes...>::value, "Unsupported type");
static_assert(etl::is_one_of<etl::remove_reference_t<T>, TTypes...>::value, "Unsupported type");
construct_in_place_args<etl::remove_reference_t<T>>(data, std::forward<TArgs>(args)...);
}
@ -299,7 +489,7 @@ namespace etl
, type_id(Index)
{
using type = typename private_variant::parameter_pack<TTypes...>:: template type_from_index_t<Index>;
static_assert(etl::is_one_of<type>, TTypes... > ::value, "Unsupported type");
static_assert(etl::is_one_of<type, TTypes...> ::value, "Unsupported type");
construct_in_place_args<type>(data, std::forward<TArgs>(args)...);
@ -313,12 +503,12 @@ namespace etl
template <typename T, typename U, typename... TArgs >
ETL_CONSTEXPR14 explicit variant(etl::in_place_type_t<T>, std::initializer_list<U> init, TArgs&&... args)
: data()
, operation(operation_type<etl::remove_reference_t<T>>, etl::is_copy_constructible<etl::remove_reference_t<T>>::value, etl::is_move_constructible<type>::etl::remove_reference_t<T>>::do_operation)
, operation(operation_type<etl::remove_reference_t<T>, etl::is_copy_constructible<etl::remove_reference_t<T>>::value, etl::is_move_constructible<etl::remove_reference_t<T>>::value>::do_operation)
, type_id(private_variant::parameter_pack<TTypes...>:: template index_of_type<etl::remove_reference_t<T>>::value)
{
static_assert(etl::is_one_of<etl::remove_reference_t<T>>, TTypes... > ::value, "Unsupported type");
static_assert(etl::is_one_of<etl::remove_reference_t<T>, TTypes...> ::value, "Unsupported type");
construct_in_place_args<etl::remove_reference_t<T>>(data, std::forward<TArgs>(args)...);
construct_in_place_args<etl::remove_reference_t<T>>(data, init, std::forward<TArgs>(args)...);
}
//***************************************************************************
@ -330,9 +520,9 @@ namespace etl
, type_id(Index)
{
using type = typename private_variant::parameter_pack<TTypes...>:: template type_from_index_t<Index>;
static_assert(etl::is_one_of<type>, TTypes... > ::value, "Unsupported type");
static_assert(etl::is_one_of<type, TTypes...> ::value, "Unsupported type");
construct_in_place_args<type>(data, std::forward<TArgs>(args)...);
construct_in_place_args<type>(data, init, std::forward<TArgs>(args)...);
operation = operation_type<type, etl::is_copy_constructible<type>::value, etl::is_move_constructible<type>::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<void, false, false>::do_operation; // Null operation.
@ -410,7 +600,7 @@ namespace etl
using type = etl::remove_reference_t<T>;
operation(command::Destroy, data, nullptr);
operation(private_variant::Destroy, data, nullptr);
construct_in_place_args<type>(data, std::forward<TArgs>(args)...);
@ -432,7 +622,7 @@ namespace etl
static_assert(etl::is_one_of<type, TTypes...>::value, "Unsupported type");
operation(command::Destroy, data, nullptr);
operation(private_variant::Destroy, data, nullptr);
construct_in_place<type>(data, etl::forward<T>(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 <size_t Index, typename... VTypes>
friend ETL_CONSTEXPR14 etl::variant_alternative_t<Index, etl::variant<VTypes...>>&
get(etl::variant<VTypes...>& v);
template <size_t Index, typename... VTypes>
friend ETL_CONSTEXPR14 etl::variant_alternative_t<Index, etl::variant<VTypes...>>&&
get(etl::variant<VTypes...>&& v);
template <size_t Index, typename... VTypes>
friend ETL_CONSTEXPR14 const etl::variant_alternative_t<Index, const etl::variant<VTypes...>>&
get(const etl::variant<VTypes...>& v);
template <size_t Index, typename... VTypes>
friend ETL_CONSTEXPR14 const etl::variant_alternative_t<Index, const etl::variant<VTypes...>>&&
get(const etl::variant<VTypes...>&& v);
template <typename T, typename... VTypes>
friend ETL_CONSTEXPR14 T& get(etl::variant<VTypes...>& v);
template <typename T, typename... VTypes>
friend ETL_CONSTEXPR14 T&& get(etl::variant<VTypes...>&& v);
template <typename T, typename... VTypes>
friend ETL_CONSTEXPR14 const T& get(const etl::variant<VTypes...>& v);
template <typename T, typename... VTypes>
friend ETL_CONSTEXPR14 const T&& get(const etl::variant<VTypes...>&& 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 <typename T, bool IsCopyable, bool IsMoveable>
struct operation_type;
//*******************************************
// Specialisation for null operation.
template <>
struct operation_type<void, false, false>
{
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 <typename T>
struct operation_type<T, false, false>
{
static void do_operation(variant::command operation, char* pstorage, const char* pvalue)
{
switch (operation)
{
case variant::command::Destroy:
{
reinterpret_cast<const T*>(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 <typename T>
struct operation_type<T, false, true>
{
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<T*>(const_cast<char*>(pvalue))));
break;
}
case variant::command::Destroy:
{
reinterpret_cast<const T*>(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 <typename T>
struct operation_type<T, true, false>
{
static void do_operation(variant::command operation, char* pstorage, const char* pvalue)
{
switch (operation)
{
case variant::command::Copy:
{
::new (pstorage) T(*reinterpret_cast<const T*>(pvalue));
break;
}
case variant::command::Destroy:
{
reinterpret_cast<const T*>(pstorage)->~T();
break;
}
default:
{
// This should never occur.
#if defined(ETL_IN_UNIT_TEST)
assert(false);
#endif
break;
}
}
}
};
//*******************************************
// Specialisation for copyable & moveable types.
template <typename T>
struct operation_type<T, true, true>
{
static void do_operation(variant::command command, char* pstorage, const char* pvalue)
{
switch (command)
{
case variant::command::Copy:
{
::new (pstorage) T(*reinterpret_cast<const T*>(pvalue));
break;
}
case variant::command::Move:
{
::new (pstorage) T(etl::move(*reinterpret_cast<T*>(const_cast<char*>(pvalue))));
break;
}
case variant::command::Destroy:
{
reinterpret_cast<const T*>(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 <typename T, bool IsCopyable, bool IsMoveable>
// struct operation_type;
//
// //*******************************************
// // Specialisation for null operation.
// template <>
// struct operation_type<void, Non_Copyable, Non_Moveable>
// {
// 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 <typename T>
// struct operation_type<T, Non_Copyable, Non_Moveable>
// {
// static void do_operation(variant::int operation, char* pstorage, const char* pvalue)
// {
// switch (operation)
// {
// case variant::Destroy:
// {
// reinterpret_cast<const T*>(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 <typename T>
// struct operation_type<T, Non_Copyable, Moveable>
// {
// static void do_operation(variant::int operation, char* pstorage, const char* pvalue)
// {
// switch (operation)
// {
// case variant::Move:
// {
// ::new (pstorage) T(etl::move(*reinterpret_cast<T*>(const_cast<char*>(pvalue))));
// break;
// }
//
// case variant::Destroy:
// {
// reinterpret_cast<const T*>(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 <typename T>
// struct operation_type<T, Copyable, Non_Moveable>
// {
// static void do_operation(variant::int operation, char* pstorage, const char* pvalue)
// {
// switch (operation)
// {
// case variant::Copy:
// {
// ::new (pstorage) T(*reinterpret_cast<const T*>(pvalue));
// break;
// }
//
// case variant::Destroy:
// {
// reinterpret_cast<const T*>(pstorage)->~T();
// break;
// }
//
// default:
// {
// // This should never occur.
//#if defined(ETL_IN_UNIT_TEST)
// assert(false);
//#endif
// break;
// }
// }
// }
// };
//
// //*******************************************
// // Specialisation for copyable & moveable types.
// template <typename T>
// struct operation_type<T, Copyable, Moveable>
// {
// static void do_operation(variant::int int, char* pstorage, const char* pvalue)
// {
// switch (int)
// {
// case variant::Copy:
// {
// ::new (pstorage) T(*reinterpret_cast<const T*>(pvalue));
// break;
// }
//
// case variant::Move:
// {
// ::new (pstorage) T(etl::move(*reinterpret_cast<T*>(const_cast<char*>(pvalue))));
// break;
// }
//
// case variant::Destroy:
// {
// reinterpret_cast<const T*>(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<Size, 1U, Alignment> data;
//***************************************************************************
/// The operation function.
//***************************************************************************
@ -952,27 +1186,6 @@ namespace etl
return (index == v.index());
}
//***************************************************************************
/// variant_alternative
//***************************************************************************
template <size_t Index, typename T>
struct variant_alternative;
template <size_t Index, typename... TTypes>
struct variant_alternative<Index, etl::variant<TTypes...>>
{
using type = typename etl::private_variant::parameter_pack<TTypes...>::template type_from_index<Index>::type;
};
template <size_t Index, typename T>
struct variant_alternative<Index, const T>
{
using type = typename variant_alternative<Index, T>::type;
};
template <size_t Index, typename T>
using variant_alternative_t = typename variant_alternative<Index, T>::type;
//***************************************************************************
/// get
//***************************************************************************

View File

@ -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 <typename T> struct in_place_type_t
@ -428,8 +430,10 @@ namespace etl
explicit ETL_CONSTEXPR in_place_type_t(){};
};
#if ETL_CPP17_SUPPORTED
template <typename T>
inline ETL_CONSTANT in_place_type_t<T> in_place_type;
inline constexpr in_place_type_t<T> in_place_type;
#endif
//*************************
template <std::size_t I> struct in_place_index_t
@ -437,8 +441,10 @@ namespace etl
explicit ETL_CONSTEXPR in_place_index_t() {}
};
#if ETL_CPP17_SUPPORTED
template <std::size_t I>
inline ETL_CONSTANT in_place_index_t<I> in_place_index;
inline constexpr in_place_index_t<I> in_place_index;
#endif
}
#endif

View File

@ -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)

View File

@ -415,6 +415,70 @@ namespace
CHECK_EQUAL(std::string("Some Text"), etl::get<std::string>(variant_text_etl));
}
//*************************************************************************
TEST(test_construct_multiple_parameters_by_type)
{
test_variant_emplace variant_etl1(etl::in_place_type_t<D1>(), "1");
CHECK(etl::holds_alternative<D1>(variant_etl1));
CHECK_EQUAL(D1("1"), etl::get<D1>(variant_etl1));
test_variant_emplace variant_etl2(etl::in_place_type_t<D2>{}, "1", "2");
CHECK(etl::holds_alternative<D2>(variant_etl2));
CHECK_EQUAL(D2("1", "2"), etl::get<D2>(variant_etl2));
test_variant_emplace variant_etl3(etl::in_place_type_t<D3>{}, "1", "2", "3");
CHECK(etl::holds_alternative<D3>(variant_etl3));
CHECK_EQUAL(D3("1", "2", "3"), etl::get<D3>(variant_etl3));
test_variant_emplace variant_etl4(etl::in_place_type_t<D4>{}, "1", "2", "3", "4");
CHECK(etl::holds_alternative<D4>(variant_etl4));
CHECK_EQUAL(D4("1", "2", "3", "4"), etl::get<D4>(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<D1>(variant_etl1));
CHECK_EQUAL(D1("1"), etl::get<D1>(variant_etl1));
test_variant_emplace variant_etl2(etl::in_place_index_t<2>{}, "1", "2");
CHECK(etl::holds_alternative<D2>(variant_etl2));
CHECK_EQUAL(D2("1", "2"), etl::get<D2>(variant_etl2));
test_variant_emplace variant_etl3(etl::in_place_index_t<3>{}, "1", "2", "3");
CHECK(etl::holds_alternative<D3>(variant_etl3));
CHECK_EQUAL(D3("1", "2", "3"), etl::get<D3>(variant_etl3));
test_variant_emplace variant_etl4(etl::in_place_index_t<4U>{}, "1", "2", "3", "4");
CHECK(etl::holds_alternative<D4>(variant_etl4));
CHECK_EQUAL(D4("1", "2", "3", "4"), etl::get<D4>(variant_etl4));
}
//*************************************************************************
TEST(test_construct_with_initializer_list_by_type)
{
etl::variant<std::vector<int>, std::string> v(etl::in_place_type_t<std::vector<int>>{}, { 0, 1, 2, 3 });
std::vector<int> expected = { 0, 1, 2, 3 };
std::vector<int> result = etl::get<std::vector<int>>(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::vector<int>, std::string> v(etl::in_place_index_t<0U>{}, { 0, 1, 2, 3 });
std::vector<int> expected = { 0, 1, 2, 3 };
std::vector<int> result = etl::get<std::vector<int>>(v);
CHECK_EQUAL(expected.size(), result.size());
CHECK_ARRAY_EQUAL(expected.data(), result.data(), expected.size());
}
//*************************************************************************
TEST(test_emplace_value)
{