diff --git a/include/etl/generators/type_traits_generator.h b/include/etl/generators/type_traits_generator.h index ac421eb9..1ebdf3df 100644 --- a/include/etl/generators/type_traits_generator.h +++ b/include/etl/generators/type_traits_generator.h @@ -2352,6 +2352,35 @@ typedef integral_constant true_type; using type_identity_t = typename type_identity::type; #endif +#if ETL_USING_BUILTIN_UNDERLYING_TYPE +namespace private_type_traits +{ + template ::value> + struct __underlying_type_impl; + + template + struct __underlying_type_impl + { + }; + + template + struct __underlying_type_impl + { + using type = __underlying_type(T); + }; +} + +template +struct underlying_type : private_type_traits::__underlying_type_impl::value> +{ +}; + +#if ETL_USING_CPP11 +template +using underlying_type_t = typename underlying_type::type; +#endif +#endif + #if ETL_USING_CPP11 //********************************************* // has_duplicates diff --git a/include/etl/profiles/determine_builtin_support.h b/include/etl/profiles/determine_builtin_support.h index 725927f3..313a18a2 100644 --- a/include/etl/profiles/determine_builtin_support.h +++ b/include/etl/profiles/determine_builtin_support.h @@ -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 diff --git a/include/etl/type_traits.h b/include/etl/type_traits.h index 44b7805f..ad55f35f 100644 --- a/include/etl/type_traits.h +++ b/include/etl/type_traits.h @@ -2345,6 +2345,35 @@ typedef integral_constant true_type; using type_identity_t = typename type_identity::type; #endif +#if ETL_USING_BUILTIN_UNDERLYING_TYPE +namespace private_type_traits +{ + template ::value> + struct __underlying_type_impl; + + template + struct __underlying_type_impl + { + }; + + template + struct __underlying_type_impl + { + using type = __underlying_type(T); + }; +} + +template +struct underlying_type : private_type_traits::__underlying_type_impl::value> +{ +}; + +#if ETL_USING_CPP11 +template +using underlying_type_t = typename underlying_type::type; +#endif +#endif + #if ETL_USING_CPP11 //********************************************* // has_duplicates diff --git a/include/etl/utility.h b/include/etl/utility.h index 15b450e8..3c3e9988 100644 --- a/include/etl/utility.h +++ b/include/etl/utility.h @@ -134,6 +134,14 @@ namespace etl using forward_like_t = decltype(etl::forward_like(etl::declval())); #endif +#if ETL_USING_BUILTIN_UNDERLYING_TYPE && ETL_USING_CPP11 +template +ETL_CONSTEXPR underlying_type_t to_underlying(T val) ETL_NOEXCEPT +{ + return static_cast>(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) diff --git a/test/test_type_traits.cpp b/test/test_type_traits.cpp index a01e1b0a..cd919c12 100644 --- a/test/test_type_traits.cpp +++ b/test/test_type_traits.cpp @@ -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::type; + + CHECK_TRUE((std::is_same::type, char>::value)); + CHECK_TRUE((std::is_same::type, uint32_t>::value)); + CHECK_TRUE((std::is_same::type, short>::value)); + CHECK_TRUE((std::is_same::type, size_t>::value)); + CHECK_TRUE((std::is_same::type, uint32_t>::value)); + CHECK_TRUE((std::is_same::type, short>::value)); +#if ETL_USING_CPP11 + CHECK_TRUE((std::is_same, char>::value)); + CHECK_TRUE((std::is_same, uint32_t>::value)); + CHECK_TRUE((std::is_same, short>::value)); + CHECK_TRUE((std::is_same, size_t>::value)); + CHECK_TRUE((std::is_same, uint32_t>::value)); + CHECK_TRUE((std::is_same, short>::value)); +#endif + } +#endif + //************************************************************************* TEST(test_has_duplicates) { diff --git a/test/test_utility.cpp b/test/test_utility.cpp index e049198d..70b525ec 100644 --- a/test/test_utility.cpp +++ b/test/test_utility.cpp @@ -719,6 +719,49 @@ namespace CHECK_EQUAL(forward_like_call_type::ConstRValue, template_function_fl(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)