Skip to content

Commit

Permalink
Adding is_scoped_enum & to_underlying (kokkos#6356)
Browse files Browse the repository at this point in the history
* Added Impl::is_scoped_enum trait

* Changed to_underlying from a KOKKOS_INLINE_FUNCTION to a
KOKKOS_FUNCTION,
as templated functions are automatically inlined.

* Fixed formatting

* Removed C++ compatible Kokkos::Impl::underlying_type

* Added tests for is_scoped_enum applied to a user defined class

* Check to see if is_scoped_enum is derived from std::bool_constant

* Made a better check for being a public, unambiguous base
  • Loading branch information
nliber committed Aug 30, 2023
1 parent df37e47 commit 4617e4a
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 0 deletions.
27 changes: 27 additions & 0 deletions core/src/impl/Kokkos_Utilities.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,33 @@ template <class T>
using remove_cvref_t = typename remove_cvref<T>::type;
#endif

// same as C++23 std::to_underlying but with __host__ __device__ annotations
template <typename E>
KOKKOS_FUNCTION constexpr std::underlying_type_t<E> to_underlying(
E e) noexcept {
return static_cast<std::underlying_type_t<E>>(e);
}

#if defined(__cpp_lib_is_scoped_enum)
// since C++23
using std::is_scoped_enum;
using std::is_scoped_enum_v;
#else
template <typename E, bool = std::is_enum_v<E>>
struct is_scoped_enum_impl : std::false_type {};

template <typename E>
struct is_scoped_enum_impl<E, true>
: std::bool_constant<!std::is_convertible_v<E, std::underlying_type_t<E>>> {
};

template <typename E>
struct is_scoped_enum : is_scoped_enum_impl<E>::type {};

template <typename E>
inline constexpr bool is_scoped_enum_v = is_scoped_enum<E>::value;
#endif

//==============================================================================
// <editor-fold desc="is_specialization_of"> {{{1

Expand Down
90 changes: 90 additions & 0 deletions core/unit_test/TestUtilities.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,94 @@ void test_is_specialization_of() {
"");
}

namespace {
enum Enum { EZero, EOne };
enum EnumBool : bool { EBFalse, EBTrue };
enum class ScopedEnum { SEZero, SEOne };
enum class ScopedEnumShort : short { SESZero, SESOne };
class Class {};

template <typename Base, typename Derived>
inline constexpr bool is_public_unambiguous_base_of_v =
std::is_convertible_v<Derived*, Base*> && !std::is_same_v<Derived, Base>;
} // namespace

void test_to_underlying() {
using Kokkos::Impl::to_underlying;

constexpr auto e0 = to_underlying(EZero);
static_assert(e0 == 0);

constexpr auto e1 = to_underlying(EOne);
static_assert(e1 == 1);

constexpr auto eb0 = to_underlying(EBFalse);
constexpr bool b0 = false;
static_assert(std::is_same_v<decltype(eb0), decltype(b0)>);
static_assert(eb0 == b0);

constexpr auto eb1 = to_underlying(EBTrue);
constexpr bool b1 = true;
static_assert(std::is_same_v<decltype(eb1), decltype(b1)>);
static_assert(eb1 == b1);

constexpr auto se0 = to_underlying(ScopedEnum::SEZero);
static_assert(se0 == 0);

constexpr auto se1 = to_underlying(ScopedEnum::SEOne);
static_assert(se1 == 1);

constexpr auto ses0 = to_underlying(ScopedEnumShort::SESZero);
constexpr short s0 = 0;
static_assert(std::is_same_v<decltype(ses0), decltype(s0)>);
static_assert(ses0 == s0);

constexpr auto ses1 = to_underlying(ScopedEnumShort::SESOne);
constexpr short s1 = 1;
static_assert(std::is_same_v<decltype(ses1), decltype(s1)>);
static_assert(ses1 == s1);
}

void test_is_scoped_enum() {
using Kokkos::Impl::is_scoped_enum;
using Kokkos::Impl::is_scoped_enum_v;

static_assert(!is_scoped_enum<int>{});
static_assert(!is_scoped_enum<int>::value);
static_assert(!is_scoped_enum_v<int>);
static_assert(
is_public_unambiguous_base_of_v<std::false_type, is_scoped_enum<int>>);

static_assert(!is_scoped_enum<Class>{});
static_assert(!is_scoped_enum<Class>::value);
static_assert(!is_scoped_enum_v<Class>);
static_assert(
is_public_unambiguous_base_of_v<std::false_type, is_scoped_enum<Class>>);

static_assert(!is_scoped_enum<Enum>{});
static_assert(!is_scoped_enum<Enum>::value);
static_assert(!is_scoped_enum_v<Enum>);
static_assert(
is_public_unambiguous_base_of_v<std::false_type, is_scoped_enum<Enum>>);

static_assert(!is_scoped_enum<EnumBool>{});
static_assert(!is_scoped_enum<EnumBool>::value);
static_assert(!is_scoped_enum_v<EnumBool>);
static_assert(is_public_unambiguous_base_of_v<std::false_type,
is_scoped_enum<EnumBool>>);

static_assert(is_scoped_enum<ScopedEnum>{});
static_assert(is_scoped_enum<ScopedEnum>::value);
static_assert(is_scoped_enum_v<ScopedEnum>);
static_assert(is_public_unambiguous_base_of_v<std::true_type,
is_scoped_enum<ScopedEnum>>);

static_assert(is_scoped_enum<ScopedEnumShort>{});
static_assert(is_scoped_enum<ScopedEnumShort>::value);
static_assert(is_scoped_enum_v<ScopedEnumShort>);
static_assert(
is_public_unambiguous_base_of_v<std::true_type,
is_scoped_enum<ScopedEnumShort>>);
}

} // namespace Test

0 comments on commit 4617e4a

Please sign in to comment.