Skip to content

Commit f69da85

Browse files
Support etl::underlying_type with compiler builtin (#1045)
msvc is unsupported currently Co-authored-by: John Wellbelove <[email protected]>
1 parent a24977a commit f69da85

File tree

6 files changed

+161
-0
lines changed

6 files changed

+161
-0
lines changed

include/etl/generators/type_traits_generator.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2352,6 +2352,35 @@ typedef integral_constant<bool, true> true_type;
23522352
using type_identity_t = typename type_identity<T>::type;
23532353
#endif
23542354

2355+
#if ETL_USING_BUILTIN_UNDERLYING_TYPE
2356+
namespace private_type_traits
2357+
{
2358+
template <typename T, bool = is_enum<T>::value>
2359+
struct __underlying_type_impl;
2360+
2361+
template <typename T>
2362+
struct __underlying_type_impl<T, false>
2363+
{
2364+
};
2365+
2366+
template <typename T>
2367+
struct __underlying_type_impl<T, true>
2368+
{
2369+
using type = __underlying_type(T);
2370+
};
2371+
}
2372+
2373+
template <typename T>
2374+
struct underlying_type : private_type_traits::__underlying_type_impl<T, is_enum<T>::value>
2375+
{
2376+
};
2377+
2378+
#if ETL_USING_CPP11
2379+
template <typename T>
2380+
using underlying_type_t = typename underlying_type<T>::type;
2381+
#endif
2382+
#endif
2383+
23552384
#if ETL_USING_CPP11
23562385
//*********************************************
23572386
// has_duplicates

include/etl/profiles/determine_builtin_support.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ SOFTWARE.
5151
#if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE)
5252
#define ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE 1
5353
#endif
54+
55+
#if !defined(ETL_USING_BUILTIN_UNDERLYING_TYPE)
56+
#define ETL_USING_BUILTIN_UNDERLYING_TYPE 1
57+
#endif
5458
#endif
5559

5660
#if defined(__has_builtin) // Use __has_builtin to check for existence of builtin functions?
@@ -73,6 +77,10 @@ SOFTWARE.
7377
#if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE)
7478
#define ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE (__has_builtin(__has_trivial_copy) || __has_builtin(__is_trivially_copyable))
7579
#endif
80+
81+
#if !defined(ETL_USING_BUILTIN_UNDERLYING_TYPE)
82+
#define ETL_USING_BUILTIN_UNDERLYING_TYPE __has_builtin(__underlying_type)
83+
#endif
7684
#endif
7785

7886
// The default. Set to 0, if not already set.
@@ -96,6 +104,10 @@ SOFTWARE.
96104
#define ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE 0
97105
#endif
98106

107+
#if !defined(ETL_USING_BUILTIN_UNDERLYING_TYPE)
108+
#define ETL_USING_BUILTIN_UNDERLYING_TYPE 0
109+
#endif
110+
99111
namespace etl
100112
{
101113
namespace traits

include/etl/type_traits.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2345,6 +2345,35 @@ typedef integral_constant<bool, true> true_type;
23452345
using type_identity_t = typename type_identity<T>::type;
23462346
#endif
23472347

2348+
#if ETL_USING_BUILTIN_UNDERLYING_TYPE
2349+
namespace private_type_traits
2350+
{
2351+
template <typename T, bool = is_enum<T>::value>
2352+
struct __underlying_type_impl;
2353+
2354+
template <typename T>
2355+
struct __underlying_type_impl<T, false>
2356+
{
2357+
};
2358+
2359+
template <typename T>
2360+
struct __underlying_type_impl<T, true>
2361+
{
2362+
using type = __underlying_type(T);
2363+
};
2364+
}
2365+
2366+
template <typename T>
2367+
struct underlying_type : private_type_traits::__underlying_type_impl<T, is_enum<T>::value>
2368+
{
2369+
};
2370+
2371+
#if ETL_USING_CPP11
2372+
template <typename T>
2373+
using underlying_type_t = typename underlying_type<T>::type;
2374+
#endif
2375+
#endif
2376+
23482377
#if ETL_USING_CPP11
23492378
//*********************************************
23502379
// has_duplicates

include/etl/utility.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,14 @@ namespace etl
134134
using forward_like_t = decltype(etl::forward_like<T>(etl::declval<U&>()));
135135
#endif
136136

137+
#if ETL_USING_BUILTIN_UNDERLYING_TYPE && ETL_USING_CPP11
138+
template <typename T>
139+
ETL_CONSTEXPR underlying_type_t<T> to_underlying(T val) ETL_NOEXCEPT
140+
{
141+
return static_cast<underlying_type_t<T>>(val);
142+
}
143+
#endif
144+
137145
// We can't have std::swap and etl::swap templates coexisting in the unit tests
138146
// as the compiler will be unable to decide which one to use, due to ADL.
139147
#if ETL_NOT_USING_STL && !defined(ETL_IN_UNIT_TEST)

test/test_type_traits.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1364,6 +1364,46 @@ namespace
13641364
CHECK_CLOSE(type_identity_test_add(1.5f, 2), 3.5f, 0.01f);
13651365
}
13661366

1367+
//*************************************************************************
1368+
#if ETL_USING_BUILTIN_UNDERLYING_TYPE
1369+
TEST(test_underlying_type)
1370+
{
1371+
enum enum0_t : char
1372+
{
1373+
};
1374+
1375+
enum enum1_t : uint32_t
1376+
{
1377+
};
1378+
1379+
enum class enum2_t : short
1380+
{
1381+
};
1382+
1383+
enum class enum3_t : size_t
1384+
{
1385+
};
1386+
1387+
using enum4_t = enum1_t;
1388+
using enum5_t = std::add_const<enum2_t>::type;
1389+
1390+
CHECK_TRUE((std::is_same<etl::underlying_type<enum0_t>::type, char>::value));
1391+
CHECK_TRUE((std::is_same<etl::underlying_type<enum1_t>::type, uint32_t>::value));
1392+
CHECK_TRUE((std::is_same<etl::underlying_type<enum2_t>::type, short>::value));
1393+
CHECK_TRUE((std::is_same<etl::underlying_type<enum3_t>::type, size_t>::value));
1394+
CHECK_TRUE((std::is_same<etl::underlying_type<enum4_t>::type, uint32_t>::value));
1395+
CHECK_TRUE((std::is_same<etl::underlying_type<enum5_t>::type, short>::value));
1396+
#if ETL_USING_CPP11
1397+
CHECK_TRUE((std::is_same<etl::underlying_type_t<enum0_t>, char>::value));
1398+
CHECK_TRUE((std::is_same<etl::underlying_type_t<enum1_t>, uint32_t>::value));
1399+
CHECK_TRUE((std::is_same<etl::underlying_type_t<enum2_t>, short>::value));
1400+
CHECK_TRUE((std::is_same<etl::underlying_type_t<enum3_t>, size_t>::value));
1401+
CHECK_TRUE((std::is_same<etl::underlying_type_t<enum4_t>, uint32_t>::value));
1402+
CHECK_TRUE((std::is_same<etl::underlying_type_t<enum5_t>, short>::value));
1403+
#endif
1404+
}
1405+
#endif
1406+
13671407
//*************************************************************************
13681408
TEST(test_has_duplicates)
13691409
{

test/test_utility.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,49 @@ namespace
719719
CHECK_EQUAL(forward_like_call_type::ConstRValue, template_function_fl<const TFL&&>(etl::move(u4)));
720720
}
721721

722+
#if ETL_USING_BUILTIN_UNDERLYING_TYPE && ETL_USING_CPP11
723+
TEST(test_to_underlying)
724+
{
725+
enum enum0_t : char
726+
{
727+
a0 = 'e',
728+
a1 = 't',
729+
a2 = 'l',
730+
a3 = '3'
731+
};
732+
733+
enum enum1_t : uint32_t
734+
{
735+
b0 = 2,
736+
b1 = 3,
737+
b2 = 5,
738+
};
739+
740+
enum enum2_t : signed
741+
{
742+
c0 = -2,
743+
c1 = 100,
744+
};
745+
746+
using enum3_t = enum1_t;
747+
748+
enum0_t e0 = enum0_t::a1;
749+
enum1_t e1 = enum1_t::b2;
750+
enum2_t e2 = enum2_t::c0;
751+
enum3_t e3 = enum3_t::b0;
752+
753+
CHECK_EQUAL(etl::to_underlying(e0), 't');
754+
CHECK_EQUAL(etl::to_underlying(e1), 5);
755+
CHECK_EQUAL(etl::to_underlying(e2), -2);
756+
CHECK_EQUAL(etl::to_underlying(e3), 2);
757+
CHECK_EQUAL(etl::to_underlying(enum0_t::a0), 'e');
758+
CHECK_EQUAL(etl::to_underlying(enum0_t::a2), 'l');
759+
CHECK_EQUAL(etl::to_underlying(enum0_t::a3), '3');
760+
CHECK_EQUAL(etl::to_underlying(enum3_t::b1), 3);
761+
CHECK_EQUAL(etl::to_underlying(enum2_t::c1), 100);
762+
}
763+
#endif
764+
722765
#if ETL_HAS_PACKED
723766
//*********************************
724767
TEST(test_packed)

0 commit comments

Comments
 (0)