Detect builtins (#1581)

Even without ETL_USE_TYPE_TRAITS_BUILTINS in the profile, we get
compiler builtins detected. Makes detection more consistent now.

Previously, some type trait builtins were detected automatically,
and some others needed to be activated via ETL_USE_TYPE_TRAITS_BUILTINS
in the profile explicitly.

Replaces: #1174

Co-authored-by: John Wellbelove <jwellbelove@users.noreply.github.com>
This commit is contained in:
Roland Reichwein 2026-09-02 09:58:40 +02:00 committed by GitHub
parent 452b6269f3
commit ed5219283b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 310 additions and 34 deletions

View File

@ -53,6 +53,44 @@ SOFTWARE.
namespace etl
{
namespace private_memory
{
//*************************************************************************
/// Checks whether a type can be copied to uninitialised storage by using
/// assignment instead of placement new.
//*************************************************************************
template <typename T>
struct is_trivially_copy_assignable_to_uninitialised_storage
: etl::bool_constant<etl::is_trivially_copyable<T>::value && etl::is_trivially_copy_constructible<T>::value
&& etl::is_trivially_copy_assignable<T>::value>
{
};
#if ETL_USING_CPP11
//*************************************************************************
/// Checks whether a type can be moved to uninitialised storage by using
/// assignment instead of placement new.
//*************************************************************************
template <typename T>
struct is_trivially_move_assignable_to_uninitialised_storage
: etl::bool_constant<etl::is_trivially_copyable<T>::value && etl::is_trivially_move_constructible<T>::value
&& etl::is_trivially_move_assignable<T>::value>
{
};
#endif
//*************************************************************************
/// Checks whether a value-initialised type can be copied to uninitialised
/// storage by using assignment instead of placement new.
//*************************************************************************
template <typename T>
struct is_trivially_value_assignable_to_uninitialised_storage
: etl::bool_constant<etl::is_trivially_constructible<T>::value && etl::is_trivially_copyable<T>::value
&& etl::is_trivially_copy_assignable<T>::value>
{
};
} // namespace private_memory
//*****************************************************************************
/// Obtain the address represented by p without forming a reference to the
/// object pointed to by p. Defined when not using the STL or C++20
@ -428,7 +466,9 @@ namespace etl
///\ingroup memory
//*****************************************************************************
template <typename TOutputIterator, typename T>
typename etl::enable_if< etl::is_trivially_constructible< typename etl::iterator_traits<TOutputIterator>::value_type>::value, TOutputIterator>::type
typename etl::enable_if<
etl::private_memory::is_trivially_copy_assignable_to_uninitialised_storage<typename etl::iterator_traits<TOutputIterator>::value_type>::value,
TOutputIterator>::type
uninitialized_fill(TOutputIterator o_begin, TOutputIterator o_end, const T& value)
{
etl::fill(o_begin, o_end, value);
@ -442,7 +482,8 @@ namespace etl
///\ingroup memory
//*****************************************************************************
template <typename TOutputIterator, typename T>
typename etl::enable_if< !etl::is_trivially_constructible< typename etl::iterator_traits<TOutputIterator>::value_type>::value,
typename etl::enable_if<
!etl::private_memory::is_trivially_copy_assignable_to_uninitialised_storage<typename etl::iterator_traits<TOutputIterator>::value_type>::value,
TOutputIterator>::type
uninitialized_fill(TOutputIterator o_begin, TOutputIterator o_end, const T& value)
{
@ -464,7 +505,9 @@ namespace etl
///\ingroup memory
//*****************************************************************************
template <typename TOutputIterator, typename T, typename TCounter>
typename etl::enable_if< etl::is_trivially_constructible< typename etl::iterator_traits<TOutputIterator>::value_type>::value, TOutputIterator>::type
typename etl::enable_if<
etl::private_memory::is_trivially_copy_assignable_to_uninitialised_storage<typename etl::iterator_traits<TOutputIterator>::value_type>::value,
TOutputIterator>::type
uninitialized_fill(TOutputIterator o_begin, TOutputIterator o_end, const T& value, TCounter& count)
{
count += static_cast<TCounter>(etl::distance(o_begin, o_end));
@ -481,7 +524,8 @@ namespace etl
///\ingroup memory
//*****************************************************************************
template <typename TOutputIterator, typename T, typename TCounter>
typename etl::enable_if< !etl::is_trivially_constructible< typename etl::iterator_traits<TOutputIterator>::value_type>::value,
typename etl::enable_if<
!etl::private_memory::is_trivially_copy_assignable_to_uninitialised_storage<typename etl::iterator_traits<TOutputIterator>::value_type>::value,
TOutputIterator>::type
uninitialized_fill(TOutputIterator o_begin, TOutputIterator o_end, const T& value, TCounter& count)
{
@ -577,7 +621,9 @@ namespace etl
///\ingroup memory
//*****************************************************************************
template <typename TInputIterator, typename TOutputIterator>
typename etl::enable_if< etl::is_trivially_constructible< typename etl::iterator_traits<TOutputIterator>::value_type>::value, TOutputIterator>::type
typename etl::enable_if<
etl::private_memory::is_trivially_copy_assignable_to_uninitialised_storage<typename etl::iterator_traits<TOutputIterator>::value_type>::value,
TOutputIterator>::type
uninitialized_copy(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin)
{
return etl::copy(i_begin, i_end, o_begin);
@ -589,7 +635,8 @@ namespace etl
///\ingroup memory
//*****************************************************************************
template <typename TInputIterator, typename TOutputIterator>
typename etl::enable_if< !etl::is_trivially_constructible< typename etl::iterator_traits<TOutputIterator>::value_type>::value,
typename etl::enable_if<
!etl::private_memory::is_trivially_copy_assignable_to_uninitialised_storage<typename etl::iterator_traits<TOutputIterator>::value_type>::value,
TOutputIterator>::type
uninitialized_copy(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin)
{
@ -614,7 +661,9 @@ namespace etl
///\ingroup memory
//*****************************************************************************
template <typename TInputIterator, typename TOutputIterator, typename TCounter>
typename etl::enable_if< etl::is_trivially_constructible< typename etl::iterator_traits<TOutputIterator>::value_type>::value, TOutputIterator>::type
typename etl::enable_if<
etl::private_memory::is_trivially_copy_assignable_to_uninitialised_storage<typename etl::iterator_traits<TOutputIterator>::value_type>::value,
TOutputIterator>::type
uninitialized_copy(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin, TCounter& count)
{
TOutputIterator o_end = etl::copy(i_begin, i_end, o_begin);
@ -630,7 +679,8 @@ namespace etl
///\ingroup memory
//*****************************************************************************
template <typename TInputIterator, typename TOutputIterator, typename TCounter>
typename etl::enable_if< !etl::is_trivially_constructible< typename etl::iterator_traits<TOutputIterator>::value_type>::value,
typename etl::enable_if<
!etl::private_memory::is_trivially_copy_assignable_to_uninitialised_storage<typename etl::iterator_traits<TOutputIterator>::value_type>::value,
TOutputIterator>::type
uninitialized_copy(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin, TCounter& count)
{
@ -910,7 +960,9 @@ namespace etl
///\ingroup memory
//*****************************************************************************
template <typename TInputIterator, typename TOutputIterator>
typename etl::enable_if< etl::is_trivially_constructible< typename etl::iterator_traits<TOutputIterator>::value_type>::value, TOutputIterator>::type
typename etl::enable_if<
etl::private_memory::is_trivially_move_assignable_to_uninitialised_storage<typename etl::iterator_traits<TOutputIterator>::value_type>::value,
TOutputIterator>::type
uninitialized_move(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin)
{
return etl::move(i_begin, i_end, o_begin);
@ -922,7 +974,8 @@ namespace etl
///\ingroup memory
//*****************************************************************************
template <typename TInputIterator, typename TOutputIterator>
typename etl::enable_if< !etl::is_trivially_constructible< typename etl::iterator_traits<TOutputIterator>::value_type>::value,
typename etl::enable_if<
!etl::private_memory::is_trivially_move_assignable_to_uninitialised_storage<typename etl::iterator_traits<TOutputIterator>::value_type>::value,
TOutputIterator>::type
uninitialized_move(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin)
{
@ -947,7 +1000,9 @@ namespace etl
///\ingroup memory
//*****************************************************************************
template <typename TInputIterator, typename TOutputIterator, typename TCounter>
typename etl::enable_if< etl::is_trivially_constructible< typename etl::iterator_traits<TOutputIterator>::value_type>::value, TOutputIterator>::type
typename etl::enable_if<
etl::private_memory::is_trivially_move_assignable_to_uninitialised_storage<typename etl::iterator_traits<TOutputIterator>::value_type>::value,
TOutputIterator>::type
uninitialized_move(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin, TCounter& count)
{
TOutputIterator o_end = etl::move(i_begin, i_end, o_begin);
@ -963,7 +1018,8 @@ namespace etl
///\ingroup memory
//*****************************************************************************
template <typename TInputIterator, typename TOutputIterator, typename TCounter>
typename etl::enable_if< !etl::is_trivially_constructible< typename etl::iterator_traits<TOutputIterator>::value_type>::value,
typename etl::enable_if<
!etl::private_memory::is_trivially_move_assignable_to_uninitialised_storage<typename etl::iterator_traits<TOutputIterator>::value_type>::value,
TOutputIterator>::type
uninitialized_move(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin, TCounter& count)
{
@ -1037,7 +1093,9 @@ namespace etl
///\ingroup memory
//*****************************************************************************
template <typename TInputIterator, typename TSize, typename TOutputIterator>
typename etl::enable_if< etl::is_trivially_constructible< typename etl::iterator_traits<TOutputIterator>::value_type>::value, TOutputIterator>::type
typename etl::enable_if<
etl::private_memory::is_trivially_move_assignable_to_uninitialised_storage<typename etl::iterator_traits<TOutputIterator>::value_type>::value,
TOutputIterator>::type
uninitialized_move_n(TInputIterator i_begin, TSize n, TOutputIterator o_begin)
{
return etl::move(i_begin, i_begin + n, o_begin);
@ -1049,7 +1107,8 @@ namespace etl
///\ingroup memory
//*****************************************************************************
template <typename TInputIterator, typename TSize, typename TOutputIterator>
typename etl::enable_if< !etl::is_trivially_constructible< typename etl::iterator_traits<TOutputIterator>::value_type>::value,
typename etl::enable_if<
!etl::private_memory::is_trivially_move_assignable_to_uninitialised_storage<typename etl::iterator_traits<TOutputIterator>::value_type>::value,
TOutputIterator>::type
uninitialized_move_n(TInputIterator i_begin, TSize n, TOutputIterator o_begin)
{
@ -1074,7 +1133,9 @@ namespace etl
///\ingroup memory
//*****************************************************************************
template <typename TInputIterator, typename TSize, typename TOutputIterator, typename TCounter>
typename etl::enable_if< etl::is_trivially_constructible< typename etl::iterator_traits<TOutputIterator>::value_type>::value, TOutputIterator>::type
typename etl::enable_if<
etl::private_memory::is_trivially_move_assignable_to_uninitialised_storage<typename etl::iterator_traits<TOutputIterator>::value_type>::value,
TOutputIterator>::type
uninitialized_move_n(TInputIterator i_begin, TSize n, TOutputIterator o_begin, TCounter& count)
{
TOutputIterator o_end = etl::move(i_begin, i_begin + n, o_begin);
@ -1090,7 +1151,8 @@ namespace etl
///\ingroup memory
//*****************************************************************************
template <typename TInputIterator, typename TSize, typename TOutputIterator, typename TCounter>
typename etl::enable_if< !etl::is_trivially_constructible< typename etl::iterator_traits<TOutputIterator>::value_type>::value,
typename etl::enable_if<
!etl::private_memory::is_trivially_move_assignable_to_uninitialised_storage<typename etl::iterator_traits<TOutputIterator>::value_type>::value,
TOutputIterator>::type
uninitialized_move_n(TInputIterator i_begin, TSize n, TOutputIterator o_begin, TCounter& count)
{
@ -1527,7 +1589,9 @@ namespace etl
///\ingroup memory
//*****************************************************************************
template <typename TOutputIterator>
typename etl::enable_if< etl::is_trivially_constructible< typename etl::iterator_traits<TOutputIterator>::value_type>::value, void>::type
typename etl::enable_if<
etl::private_memory::is_trivially_value_assignable_to_uninitialised_storage<typename etl::iterator_traits<TOutputIterator>::value_type>::value,
void>::type
uninitialized_value_construct(TOutputIterator o_begin, TOutputIterator o_end)
{
typedef typename etl::iterator_traits<TOutputIterator>::value_type value_type;
@ -1541,7 +1605,9 @@ namespace etl
///\ingroup memory
//*****************************************************************************
template <typename TOutputIterator>
typename etl::enable_if< !etl::is_trivially_constructible< typename etl::iterator_traits<TOutputIterator>::value_type>::value, void>::type
typename etl::enable_if<
!etl::private_memory::is_trivially_value_assignable_to_uninitialised_storage<typename etl::iterator_traits<TOutputIterator>::value_type>::value,
void>::type
uninitialized_value_construct(TOutputIterator o_begin, TOutputIterator o_end)
{
typedef typename etl::iterator_traits<TOutputIterator>::value_type value_type;

View File

@ -53,6 +53,10 @@ SOFTWARE.
#define ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE 1
#endif
#if !defined(ETL_USING_BUILTIN_HAS_TRIVIAL_CONSTRUCTOR)
#define ETL_USING_BUILTIN_HAS_TRIVIAL_CONSTRUCTOR 1
#endif
#if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_ASSIGNABLE)
#define ETL_USING_BUILTIN_IS_TRIVIALLY_ASSIGNABLE 1
#endif
@ -61,6 +65,10 @@ SOFTWARE.
#define ETL_USING_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE 1
#endif
#if !defined(ETL_USING_BUILTIN_HAS_TRIVIAL_DESTRUCTOR)
#define ETL_USING_BUILTIN_HAS_TRIVIAL_DESTRUCTOR 1
#endif
#if !defined(ETL_USING_BUILTIN_IS_DESTRUCTIBLE)
#define ETL_USING_BUILTIN_IS_DESTRUCTIBLE 1
#endif
@ -177,7 +185,14 @@ SOFTWARE.
#endif
#if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE)
#define ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE (__has_builtin(__has_trivial_constructor) || __has_builtin(__is_trivially_constructible))
#define ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE __has_builtin(__is_trivially_constructible)
#endif
// The legacy __has_trivial_constructor builtin. Deprecated by GCC 12 and
// removed by GCC 15, so it must be detected separately from the standard
// __is_trivially_constructible builtin.
#if !defined(ETL_USING_BUILTIN_HAS_TRIVIAL_CONSTRUCTOR)
#define ETL_USING_BUILTIN_HAS_TRIVIAL_CONSTRUCTOR __has_builtin(__has_trivial_constructor)
#endif
#if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_ASSIGNABLE)
@ -185,7 +200,14 @@ SOFTWARE.
#endif
#if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE)
#define ETL_USING_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE (__has_builtin(__has_trivial_destructor) || __has_builtin(__is_trivially_destructible))
#define ETL_USING_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE __has_builtin(__is_trivially_destructible)
#endif
// The legacy __has_trivial_destructor builtin. Deprecated by GCC 12 and
// removed by GCC 15, so it must be detected separately from the standard
// __is_trivially_destructible builtin.
#if !defined(ETL_USING_BUILTIN_HAS_TRIVIAL_DESTRUCTOR)
#define ETL_USING_BUILTIN_HAS_TRIVIAL_DESTRUCTOR __has_builtin(__has_trivial_destructor)
#endif
#if !defined(ETL_USING_BUILTIN_IS_DESTRUCTIBLE)

View File

@ -4195,6 +4195,7 @@ namespace etl
#if ETL_USING_CPP11
//***************************************************************************
/// is_constructible
#if !ETL_USING_BUILTIN_IS_CONSTRUCTIBLE
namespace private_type_traits
{
template <class, class T, class... TArgs>
@ -4207,11 +4208,19 @@ namespace etl
{
};
} // namespace private_type_traits
#endif
//*********************************************
// is_constructible
#if ETL_USING_BUILTIN_IS_CONSTRUCTIBLE
template <class T, class... TArgs>
struct is_constructible : public etl::bool_constant<__is_constructible(T, TArgs...)>
{
};
#else
template <class T, class... TArgs>
using is_constructible = private_type_traits::is_constructible_<void_t<>, T, TArgs...>;
#endif
//*********************************************
// is_copy_constructible
@ -4304,49 +4313,79 @@ namespace etl
//*********************************************
// is_nothrow_constructible
template <typename T, typename... TArgs>
#if ETL_USING_BUILTIN_IS_NOTHROW_CONSTRUCTIBLE
struct is_nothrow_constructible : public etl::bool_constant<__is_nothrow_constructible(T, TArgs...)>
#else
struct is_nothrow_constructible : public etl::bool_constant<etl::is_arithmetic<T>::value || etl::is_pointer<T>::value>
#endif
{
};
//*********************************************
// is_nothrow_default_constructible
template <typename T>
#if ETL_USING_BUILTIN_IS_NOTHROW_CONSTRUCTIBLE
struct is_nothrow_default_constructible : public etl::is_nothrow_constructible<T>
#else
struct is_nothrow_default_constructible : public etl::bool_constant<etl::is_arithmetic<T>::value || etl::is_pointer<T>::value>
#endif
{
};
//*********************************************
// is_nothrow_copy_constructible
template <typename T>
#if ETL_USING_BUILTIN_IS_NOTHROW_CONSTRUCTIBLE
struct is_nothrow_copy_constructible : public etl::is_nothrow_constructible<T, typename etl::add_lvalue_reference<const T>::type>
#else
struct is_nothrow_copy_constructible : public etl::bool_constant<etl::is_arithmetic<T>::value || etl::is_pointer<T>::value>
#endif
{
};
//*********************************************
// is_nothrow_move_constructible
template <typename T>
#if ETL_USING_BUILTIN_IS_NOTHROW_CONSTRUCTIBLE
struct is_nothrow_move_constructible : public etl::is_nothrow_constructible<T, typename etl::add_rvalue_reference<T>::type>
#else
struct is_nothrow_move_constructible : public etl::bool_constant<etl::is_arithmetic<T>::value || etl::is_pointer<T>::value>
#endif
{
};
//*********************************************
// is_nothrow_assignable
template <typename T, typename U>
#if ETL_USING_BUILTIN_IS_NOTHROW_ASSIGNABLE
struct is_nothrow_assignable : public etl::bool_constant<__is_nothrow_assignable(T, U)>
#else
struct is_nothrow_assignable : public etl::bool_constant<etl::is_arithmetic<T>::value || etl::is_pointer<T>::value>
#endif
{
};
//*********************************************
// is_nothrow_copy_assignable
template <typename T>
#if ETL_USING_BUILTIN_IS_NOTHROW_ASSIGNABLE
struct is_nothrow_copy_assignable
: public etl::is_nothrow_assignable<typename etl::add_lvalue_reference<T>::type, typename etl::add_lvalue_reference<const T>::type>
#else
struct is_nothrow_copy_assignable : public etl::bool_constant<etl::is_arithmetic<T>::value || etl::is_pointer<T>::value>
#endif
{
};
//*********************************************
// is_nothrow_move_assignable
template <typename T>
#if ETL_USING_BUILTIN_IS_NOTHROW_ASSIGNABLE
struct is_nothrow_move_assignable
: public etl::is_nothrow_assignable<typename etl::add_lvalue_reference<T>::type, typename etl::add_rvalue_reference<T>::type>
#else
struct is_nothrow_move_assignable : public etl::bool_constant<etl::is_arithmetic<T>::value || etl::is_pointer<T>::value>
#endif
{
};
#endif
@ -4354,35 +4393,68 @@ namespace etl
//*********************************************
// is_trivially_constructible
template <typename T>
#if ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE
struct is_trivially_constructible : public etl::bool_constant<__is_trivially_constructible(T)>
#elif ETL_USING_CPP11 && ETL_USING_BUILTIN_HAS_TRIVIAL_CONSTRUCTOR
struct is_trivially_constructible : public etl::bool_constant<__has_trivial_constructor(T) && etl::is_constructible<T>::value>
#else
struct is_trivially_constructible : public etl::bool_constant<etl::is_arithmetic<T>::value || etl::is_pointer<T>::value>
#endif
{
};
//*********************************************
// is_trivially_copy_constructible
template <typename T>
#if ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE
struct is_trivially_copy_constructible
: public etl::bool_constant<__is_trivially_constructible(T, typename etl::add_lvalue_reference<const T>::type)>
#elif ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE
// A trivially copyable type may still have a deleted copy constructor, so the
// copy constructor must be checked for as well.
struct is_trivially_copy_constructible : public etl::bool_constant<__is_trivially_copyable(T) && etl::is_copy_constructible<T>::value>
#else
struct is_trivially_copy_constructible : public etl::bool_constant<etl::is_arithmetic<T>::value || etl::is_pointer<T>::value>
#endif
{
};
//*********************************************
// is_trivially_default_constructible
template <typename T>
#if ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE || ETL_USING_BUILTIN_HAS_TRIVIAL_CONSTRUCTOR
struct is_trivially_default_constructible : public etl::is_trivially_constructible<T>
#else
struct is_trivially_default_constructible : public etl::bool_constant<etl::is_arithmetic<T>::value || etl::is_pointer<T>::value>
#endif
{
};
//*********************************************
// is_trivially_move_constructible
template <typename T>
#if ETL_USING_CPP11 && ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE
struct is_trivially_move_constructible : public etl::bool_constant<__is_trivially_constructible(T, typename etl::add_rvalue_reference<T>::type)>
#elif ETL_USING_CPP11 && ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE
// A trivially copyable type may still have a deleted move constructor, so the
// move constructor must be checked for as well.
struct is_trivially_move_constructible : public etl::bool_constant<__is_trivially_copyable(T) && etl::is_move_constructible<T>::value>
#else
struct is_trivially_move_constructible : public etl::bool_constant<etl::is_arithmetic<T>::value || etl::is_pointer<T>::value>
#endif
{
};
//*********************************************
// is_trivially_destructible
template <typename T>
#if ETL_USING_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE
struct is_trivially_destructible : public etl::bool_constant<__is_trivially_destructible(T)>
#elif ETL_USING_CPP11 && ETL_USING_BUILTIN_HAS_TRIVIAL_DESTRUCTOR
struct is_trivially_destructible : public etl::bool_constant<__has_trivial_destructor(T) && etl::is_destructible<T>::value>
#else
struct is_trivially_destructible : public etl::bool_constant<etl::is_arithmetic<T>::value || etl::is_pointer<T>::value>
#endif
{
};

View File

@ -138,6 +138,33 @@ namespace
}
};
#if ETL_USING_CPP11
// A trivially copyable type that can be copy constructed but not copy
// assigned. It must use the placement-new uninitialized algorithm path.
struct CopyConstructOnly
{
int value;
CopyConstructOnly() = default;
CopyConstructOnly(const CopyConstructOnly&) = default;
CopyConstructOnly& operator=(const CopyConstructOnly&) = delete;
};
// A trivially copyable type that can be move constructed but not move
// assigned. It must use the placement-new uninitialized algorithm path.
struct MoveConstructOnly
{
int value;
MoveConstructOnly() = default;
MoveConstructOnly(const MoveConstructOnly&) = delete;
MoveConstructOnly(MoveConstructOnly&&) = default;
MoveConstructOnly& operator=(MoveConstructOnly&&) = delete;
};
#endif
//***********************************
template <typename T>
struct NoDelete
@ -546,6 +573,59 @@ namespace
CHECK_EQUAL(0U, count);
}
#if ETL_USING_CPP11
//*************************************************************************
TEST(test_uninitialized_algorithms_use_construction_when_assignment_is_deleted)
{
CopyConstructOnly copy_source[2];
copy_source[0].value = 1;
copy_source[1].value = 2;
alignas(CopyConstructOnly) unsigned char copy_storage[sizeof(CopyConstructOnly) * 2U];
CopyConstructOnly* copy_destination = reinterpret_cast<CopyConstructOnly*>(copy_storage);
etl::uninitialized_copy(copy_source, copy_source + 2, copy_destination);
CHECK_EQUAL(1, copy_destination[0].value);
CHECK_EQUAL(2, copy_destination[1].value);
alignas(CopyConstructOnly) unsigned char fill_storage[sizeof(CopyConstructOnly) * 2U];
CopyConstructOnly* fill_destination = reinterpret_cast<CopyConstructOnly*>(fill_storage);
etl::uninitialized_fill(fill_destination, fill_destination + 2, copy_source[0]);
CHECK_EQUAL(1, fill_destination[0].value);
CHECK_EQUAL(1, fill_destination[1].value);
alignas(CopyConstructOnly) unsigned char value_storage[sizeof(CopyConstructOnly) * 2U];
CopyConstructOnly* value_destination = reinterpret_cast<CopyConstructOnly*>(value_storage);
etl::uninitialized_value_construct(value_destination, value_destination + 2);
CHECK_EQUAL(0, value_destination[0].value);
CHECK_EQUAL(0, value_destination[1].value);
MoveConstructOnly move_source[2];
move_source[0].value = 3;
move_source[1].value = 4;
alignas(MoveConstructOnly) unsigned char move_storage[sizeof(MoveConstructOnly) * 2U];
MoveConstructOnly* move_destination = reinterpret_cast<MoveConstructOnly*>(move_storage);
etl::uninitialized_move(move_source, move_source + 2, move_destination);
CHECK_EQUAL(3, move_destination[0].value);
CHECK_EQUAL(4, move_destination[1].value);
MoveConstructOnly move_n_source[2];
move_n_source[0].value = 5;
move_n_source[1].value = 6;
alignas(MoveConstructOnly) unsigned char move_n_storage[sizeof(MoveConstructOnly) * 2U];
MoveConstructOnly* move_n_destination = reinterpret_cast<MoveConstructOnly*>(move_n_storage);
etl::uninitialized_move_n(move_n_source, 2U, move_n_destination);
CHECK_EQUAL(5, move_n_destination[0].value);
CHECK_EQUAL(6, move_n_destination[1].value);
}
#endif
//*************************************************************************
TEST(test_uninitialized_default_construct_n_trivial)
{

View File

@ -150,6 +150,29 @@ namespace
NotDefaultConstructible& operator=(NotDefaultConstructible&&) = delete;
};
// The legacy compiler builtin for trivial construction does not test
// accessibility, unlike is_trivially_constructible.
struct PrivateTrivialDefaultConstructor
{
private:
PrivateTrivialDefaultConstructor() = default;
};
// The legacy compiler builtin for trivial destruction does not test
// accessibility or deletion, unlike is_trivially_destructible.
struct PrivateTrivialDestructor
{
private:
~PrivateTrivialDestructor() = default;
};
struct DeletedTrivialDestructor
{
~DeletedTrivialDestructor() = delete;
};
// A function to test etl::type_identity.
template <typename T>
T type_identity_test_add(T first, typename etl::type_identity<T>::type second)
@ -2851,7 +2874,8 @@ namespace
//*************************************************************************
TEST(test_is_trivially_constructible)
{
#if ETL_USING_STL || defined(ETL_USE_TYPE_TRAITS_BUILTINS) || defined(ETL_USER_DEFINED_TYPE_TRAITS)
#if ETL_USING_STL || defined(ETL_USE_TYPE_TRAITS_BUILTINS) || defined(ETL_USER_DEFINED_TYPE_TRAITS) || ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE \
|| ETL_USING_BUILTIN_HAS_TRIVIAL_CONSTRUCTOR
#if ETL_USING_CPP17
CHECK((etl::is_trivially_constructible_v<Copyable>) == (std::is_trivially_constructible_v<Copyable>));
CHECK((etl::is_trivially_constructible_v<Moveable>) == (std::is_trivially_constructible_v<Moveable>));
@ -2861,6 +2885,11 @@ namespace
CHECK((etl::is_trivially_constructible<Moveable>::value) == (std::is_trivially_constructible<Moveable>::value));
CHECK((etl::is_trivially_constructible<MoveableCopyable>::value) == (std::is_trivially_constructible<MoveableCopyable>::value));
#endif
#if ETL_USING_CPP11
CHECK(!etl::is_trivially_constructible<PrivateTrivialDefaultConstructor>::value);
CHECK((etl::is_trivially_constructible<PrivateTrivialDefaultConstructor>::value)
== (std::is_trivially_constructible<PrivateTrivialDefaultConstructor>::value));
#endif
#endif
}
@ -2919,7 +2948,8 @@ namespace
//*************************************************************************
TEST(test_is_trivially_destructible)
{
#if ETL_USING_STL || defined(ETL_USE_TYPE_TRAITS_BUILTINS) || defined(ETL_USER_DEFINED_TYPE_TRAITS)
#if ETL_USING_STL || defined(ETL_USE_TYPE_TRAITS_BUILTINS) || defined(ETL_USER_DEFINED_TYPE_TRAITS) || ETL_USING_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE \
|| ETL_USING_BUILTIN_HAS_TRIVIAL_DESTRUCTOR
#if ETL_USING_CPP17
CHECK((etl::is_trivially_destructible_v<Copyable>) == (std::is_trivially_destructible_v<Copyable>));
CHECK((etl::is_trivially_destructible_v<Moveable>) == (std::is_trivially_destructible_v<Moveable>));
@ -2929,6 +2959,12 @@ namespace
CHECK((etl::is_trivially_destructible<Moveable>::value) == (std::is_trivially_destructible<Moveable>::value));
CHECK((etl::is_trivially_destructible<MoveableCopyable>::value) == (std::is_trivially_destructible<MoveableCopyable>::value));
#endif
#if ETL_USING_CPP11
CHECK(!etl::is_trivially_destructible<PrivateTrivialDestructor>::value);
CHECK(!etl::is_trivially_destructible<DeletedTrivialDestructor>::value);
CHECK((etl::is_trivially_destructible<PrivateTrivialDestructor>::value) == (std::is_trivially_destructible<PrivateTrivialDestructor>::value));
CHECK((etl::is_trivially_destructible<DeletedTrivialDestructor>::value) == (std::is_trivially_destructible<DeletedTrivialDestructor>::value));
#endif
#endif
}