Support etl::underlying_type with compiler builtin (#1045)

msvc is unsupported currently

Co-authored-by: John Wellbelove <jwellbelove@users.noreply.github.com>
This commit is contained in:
Jiang Yi 2025-04-30 18:01:44 +02:00 committed by GitHub
parent a24977a3db
commit f69da8577e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 161 additions and 0 deletions

View File

@ -2352,6 +2352,35 @@ typedef integral_constant<bool, true> true_type;
using type_identity_t = typename type_identity<T>::type;
#endif
#if ETL_USING_BUILTIN_UNDERLYING_TYPE
namespace private_type_traits
{
template <typename T, bool = is_enum<T>::value>
struct __underlying_type_impl;
template <typename T>
struct __underlying_type_impl<T, false>
{
};
template <typename T>
struct __underlying_type_impl<T, true>
{
using type = __underlying_type(T);
};
}
template <typename T>
struct underlying_type : private_type_traits::__underlying_type_impl<T, is_enum<T>::value>
{
};
#if ETL_USING_CPP11
template <typename T>
using underlying_type_t = typename underlying_type<T>::type;
#endif
#endif
#if ETL_USING_CPP11
//*********************************************
// has_duplicates

View File

@ -51,6 +51,10 @@ SOFTWARE.
#if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE)
#define ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE 1
#endif
#if !defined(ETL_USING_BUILTIN_UNDERLYING_TYPE)
#define ETL_USING_BUILTIN_UNDERLYING_TYPE 1
#endif
#endif
#if defined(__has_builtin) // Use __has_builtin to check for existence of builtin functions?
@ -73,6 +77,10 @@ SOFTWARE.
#if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE)
#define ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE (__has_builtin(__has_trivial_copy) || __has_builtin(__is_trivially_copyable))
#endif
#if !defined(ETL_USING_BUILTIN_UNDERLYING_TYPE)
#define ETL_USING_BUILTIN_UNDERLYING_TYPE __has_builtin(__underlying_type)
#endif
#endif
// The default. Set to 0, if not already set.
@ -96,6 +104,10 @@ SOFTWARE.
#define ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE 0
#endif
#if !defined(ETL_USING_BUILTIN_UNDERLYING_TYPE)
#define ETL_USING_BUILTIN_UNDERLYING_TYPE 0
#endif
namespace etl
{
namespace traits

View File

@ -2345,6 +2345,35 @@ typedef integral_constant<bool, true> true_type;
using type_identity_t = typename type_identity<T>::type;
#endif
#if ETL_USING_BUILTIN_UNDERLYING_TYPE
namespace private_type_traits
{
template <typename T, bool = is_enum<T>::value>
struct __underlying_type_impl;
template <typename T>
struct __underlying_type_impl<T, false>
{
};
template <typename T>
struct __underlying_type_impl<T, true>
{
using type = __underlying_type(T);
};
}
template <typename T>
struct underlying_type : private_type_traits::__underlying_type_impl<T, is_enum<T>::value>
{
};
#if ETL_USING_CPP11
template <typename T>
using underlying_type_t = typename underlying_type<T>::type;
#endif
#endif
#if ETL_USING_CPP11
//*********************************************
// has_duplicates

View File

@ -134,6 +134,14 @@ namespace etl
using forward_like_t = decltype(etl::forward_like<T>(etl::declval<U&>()));
#endif
#if ETL_USING_BUILTIN_UNDERLYING_TYPE && ETL_USING_CPP11
template <typename T>
ETL_CONSTEXPR underlying_type_t<T> to_underlying(T val) ETL_NOEXCEPT
{
return static_cast<underlying_type_t<T>>(val);
}
#endif
// We can't have std::swap and etl::swap templates coexisting in the unit tests
// as the compiler will be unable to decide which one to use, due to ADL.
#if ETL_NOT_USING_STL && !defined(ETL_IN_UNIT_TEST)

View File

@ -1364,6 +1364,46 @@ namespace
CHECK_CLOSE(type_identity_test_add(1.5f, 2), 3.5f, 0.01f);
}
//*************************************************************************
#if ETL_USING_BUILTIN_UNDERLYING_TYPE
TEST(test_underlying_type)
{
enum enum0_t : char
{
};
enum enum1_t : uint32_t
{
};
enum class enum2_t : short
{
};
enum class enum3_t : size_t
{
};
using enum4_t = enum1_t;
using enum5_t = std::add_const<enum2_t>::type;
CHECK_TRUE((std::is_same<etl::underlying_type<enum0_t>::type, char>::value));
CHECK_TRUE((std::is_same<etl::underlying_type<enum1_t>::type, uint32_t>::value));
CHECK_TRUE((std::is_same<etl::underlying_type<enum2_t>::type, short>::value));
CHECK_TRUE((std::is_same<etl::underlying_type<enum3_t>::type, size_t>::value));
CHECK_TRUE((std::is_same<etl::underlying_type<enum4_t>::type, uint32_t>::value));
CHECK_TRUE((std::is_same<etl::underlying_type<enum5_t>::type, short>::value));
#if ETL_USING_CPP11
CHECK_TRUE((std::is_same<etl::underlying_type_t<enum0_t>, char>::value));
CHECK_TRUE((std::is_same<etl::underlying_type_t<enum1_t>, uint32_t>::value));
CHECK_TRUE((std::is_same<etl::underlying_type_t<enum2_t>, short>::value));
CHECK_TRUE((std::is_same<etl::underlying_type_t<enum3_t>, size_t>::value));
CHECK_TRUE((std::is_same<etl::underlying_type_t<enum4_t>, uint32_t>::value));
CHECK_TRUE((std::is_same<etl::underlying_type_t<enum5_t>, short>::value));
#endif
}
#endif
//*************************************************************************
TEST(test_has_duplicates)
{

View File

@ -719,6 +719,49 @@ namespace
CHECK_EQUAL(forward_like_call_type::ConstRValue, template_function_fl<const TFL&&>(etl::move(u4)));
}
#if ETL_USING_BUILTIN_UNDERLYING_TYPE && ETL_USING_CPP11
TEST(test_to_underlying)
{
enum enum0_t : char
{
a0 = 'e',
a1 = 't',
a2 = 'l',
a3 = '3'
};
enum enum1_t : uint32_t
{
b0 = 2,
b1 = 3,
b2 = 5,
};
enum enum2_t : signed
{
c0 = -2,
c1 = 100,
};
using enum3_t = enum1_t;
enum0_t e0 = enum0_t::a1;
enum1_t e1 = enum1_t::b2;
enum2_t e2 = enum2_t::c0;
enum3_t e3 = enum3_t::b0;
CHECK_EQUAL(etl::to_underlying(e0), 't');
CHECK_EQUAL(etl::to_underlying(e1), 5);
CHECK_EQUAL(etl::to_underlying(e2), -2);
CHECK_EQUAL(etl::to_underlying(e3), 2);
CHECK_EQUAL(etl::to_underlying(enum0_t::a0), 'e');
CHECK_EQUAL(etl::to_underlying(enum0_t::a2), 'l');
CHECK_EQUAL(etl::to_underlying(enum0_t::a3), '3');
CHECK_EQUAL(etl::to_underlying(enum3_t::b1), 3);
CHECK_EQUAL(etl::to_underlying(enum2_t::c1), 100);
}
#endif
#if ETL_HAS_PACKED
//*********************************
TEST(test_packed)