From bab16205c194c8e3105c9e69c9318c2a4f599115 Mon Sep 17 00:00:00 2001 From: yasahi-hpc <57478230+yasahi-hpc@users.noreply.github.com> Date: Tue, 23 Jul 2024 06:24:40 +0200 Subject: [PATCH] More traits for unary and binary operations (#119) * More traits for unary and binary operations * Reduce combinations for same precision, layout and rank tests * Add mssing execution_space type check * fix: rename precision traits and improve comments --------- Co-authored-by: Yuuichi Asahi --- common/src/KokkosFFT_traits.hpp | 118 +++++++- common/unit_test/Test_Traits.cpp | 502 ++++++++++++++++++++++++++++++- common/unit_test/Test_Utils.hpp | 96 +++++- 3 files changed, 694 insertions(+), 22 deletions(-) diff --git a/common/src/KokkosFFT_traits.hpp b/common/src/KokkosFFT_traits.hpp index ec89df49..312797bd 100644 --- a/common/src/KokkosFFT_traits.hpp +++ b/common/src/KokkosFFT_traits.hpp @@ -9,6 +9,9 @@ namespace KokkosFFT { namespace Impl { + +// Traits for unary operation + template struct base_floating_point { using value_type = T; @@ -60,15 +63,15 @@ struct is_admissible_value_type< template struct is_admissible_value_type< - T, std::enable_if_t::value && + T, std::enable_if_t && (is_real_v || is_complex_v)>> : std::true_type {}; /// \brief Helper to check if a type is an acceptable value type /// (float/double/Kokkos::complex/Kokkos::complex) for Kokkos-FFT -/// When applied to Kokkos::View, then check if a value type is an -/// acceptable real/complex type. +/// When applied to Kokkos::View, then check if a value type is an acceptable +/// real/complex type. template inline constexpr bool is_admissible_value_type_v = is_admissible_value_type::value; @@ -80,7 +83,7 @@ template struct is_layout_left_or_right< ViewType, std::enable_if_t< - Kokkos::is_view::value && + Kokkos::is_view_v && (std::is_same_v || std::is_same_v)>> : std::true_type {}; @@ -96,7 +99,7 @@ struct is_admissible_view : std::false_type {}; template struct is_admissible_view< - ViewType, std::enable_if_t::value && + ViewType, std::enable_if_t && is_layout_left_or_right_v && is_admissible_value_type_v>> : std::true_type {}; @@ -107,6 +110,111 @@ template inline constexpr bool is_admissible_view_v = is_admissible_view::value; +template +struct is_operatable_view : std::false_type {}; + +template +struct is_operatable_view< + ExecutionSpace, ViewType, + std::enable_if_t< + Kokkos::is_execution_space_v && + is_admissible_view_v && + Kokkos::SpaceAccessibility< + ExecutionSpace, typename ViewType::memory_space>::accessible>> + : std::true_type {}; + +/// \brief Helper to check if a View is an acceptable View for Kokkos-FFT and +/// memory space is accessible from the ExecutionSpace +template +inline constexpr bool is_operatable_view_v = + is_operatable_view::value; + +// Traits for binary operations +template +struct have_same_base_floating_point_type : std::false_type {}; + +template +struct have_same_base_floating_point_type< + T1, T2, + std::enable_if_t && !Kokkos::is_view_v && + std::is_same_v, + base_floating_point_type>>> + : std::true_type {}; + +template +struct have_same_base_floating_point_type< + InViewType, OutViewType, + std::enable_if_t< + Kokkos::is_view_v && Kokkos::is_view_v && + std::is_same_v< + base_floating_point_type, + base_floating_point_type< + typename OutViewType::non_const_value_type>>>> + : std::true_type {}; + +/// \brief Helper to check if two value have the same base floating point type. +/// When applied to Kokkos::View, then check if values of views have the same +/// base floating point type. +template +inline constexpr bool have_same_base_floating_point_type_v = + have_same_base_floating_point_type::value; + +template +struct have_same_layout : std::false_type {}; + +template +struct have_same_layout< + InViewType, OutViewType, + std::enable_if_t && + Kokkos::is_view_v && + std::is_same_v>> + : std::true_type {}; + +/// \brief Helper to check if two views have the same layout type. +template +inline constexpr bool have_same_layout_v = + have_same_layout::value; + +template +struct have_same_rank : std::false_type {}; + +template +struct have_same_rank< + InViewType, OutViewType, + std::enable_if_t && + Kokkos::is_view_v && + InViewType::rank() == OutViewType::rank()>> + : std::true_type {}; + +/// \brief Helper to check if two views have the same rank. +template +inline constexpr bool have_same_rank_v = + have_same_rank::value; + +template +struct are_operatable_views : std::false_type {}; + +template +struct are_operatable_views< + ExecutionSpace, InViewType, OutViewType, + std::enable_if_t< + is_operatable_view_v && + is_operatable_view_v && + have_same_base_floating_point_type_v && + have_same_layout_v && + have_same_rank_v>> : std::true_type {}; + +/// \brief Helper to check if Views are acceptable View for Kokkos-FFT and +/// memory space are accessible from the ExecutionSpace. +/// In addition, precisions, layout and rank are checked to be identical. +template +inline constexpr bool are_operatable_views_v = + are_operatable_views::value; + +// Other traits + /// \brief Helper to define a managable View type from the original view type template struct managable_view_type { diff --git a/common/unit_test/Test_Traits.cpp b/common/unit_test/Test_Traits.cpp index 01eb2e02..8d09753d 100644 --- a/common/unit_test/Test_Traits.cpp +++ b/common/unit_test/Test_Traits.cpp @@ -6,6 +6,16 @@ #include "KokkosFFT_traits.hpp" #include "Test_Utils.hpp" +// All the tests in this file are compile time tests, so we skip all the tests +// by GTEST_SKIP(). gtest is used for type parameterization. + +// Define the types to combine +using base_real_types = std::tuple; + +// Define the layouts to combine +using base_layout_types = + std::tuple; + using real_types = ::testing::Types; using view_types = ::testing::Types, @@ -18,10 +28,25 @@ using view_types = std::pair, std::pair>; +// Define all the combinations +using paired_value_types = + tuple_to_types_t>; + +using paired_layout_types = + tuple_to_types_t>; + +using paired_view_types = + tuple_to_types_t>; + template struct RealAndComplexTypes : public ::testing::Test { using real_type = T; using complex_type = Kokkos::complex; + + virtual void SetUp() { + GTEST_SKIP() << "Skipping all tests for this fixture"; + } }; template @@ -29,10 +54,48 @@ struct RealAndComplexViewTypes : public ::testing::Test { using real_type = typename T::first_type; using complex_type = Kokkos::complex; using layout_type = typename T::second_type; + virtual void SetUp() { + GTEST_SKIP() << "Skipping all tests for this fixture"; + } +}; + +template +struct PairedValueTypes : public ::testing::Test { + using real_type1 = typename std::tuple_element_t<0, T>; + using real_type2 = typename std::tuple_element_t<1, T>; + + virtual void SetUp() { + GTEST_SKIP() << "Skipping all tests for this fixture"; + } +}; + +template +struct PairedLayoutTypes : public ::testing::Test { + using layout_type1 = typename std::tuple_element_t<0, T>; + using layout_type2 = typename std::tuple_element_t<1, T>; + + virtual void SetUp() { + GTEST_SKIP() << "Skipping all tests for this fixture"; + } +}; + +template +struct PairedViewTypes : public ::testing::Test { + using real_type1 = typename std::tuple_element_t<0, T>; + using layout_type1 = typename std::tuple_element_t<1, T>; + using real_type2 = typename std::tuple_element_t<2, T>; + using layout_type2 = typename std::tuple_element_t<3, T>; + + virtual void SetUp() { + GTEST_SKIP() << "Skipping all tests for this fixture"; + } }; TYPED_TEST_SUITE(RealAndComplexTypes, real_types); TYPED_TEST_SUITE(RealAndComplexViewTypes, view_types); +TYPED_TEST_SUITE(PairedValueTypes, paired_value_types); +TYPED_TEST_SUITE(PairedLayoutTypes, paired_layout_types); +TYPED_TEST_SUITE(PairedViewTypes, paired_view_types); // Tests for real type deduction template @@ -42,8 +105,11 @@ void test_get_real_type() { using real_type_from_ComplexType = KokkosFFT::Impl::base_floating_point_type; + // base floating point type of RealType is RealType static_assert(std::is_same_v, "Real type not deduced correctly from real type"); + + // base floating point type of Kokkos::complex is RealType static_assert(std::is_same_v, "Real type not deduced correctly from complex type"); } @@ -51,26 +117,32 @@ void test_get_real_type() { // Tests for admissible real types (float or double) template void test_admissible_real_type() { + // Tests that a real type is float or double if constexpr (std::is_same_v || std::is_same_v) { + // T is float or double static_assert(KokkosFFT::Impl::is_real_v, "Real type must be float or double"); } else { + // T is not float or double static_assert(!KokkosFFT::Impl::is_real_v, - "Real type must be float or double"); + "Real type must not be float or double"); } } template void test_admissible_complex_type() { using real_type = KokkosFFT::Impl::base_floating_point_type; + // Tests that a base floating point type of complex value is float or double if constexpr (std::is_same_v || std::is_same_v) { + // T is Kokkos::complex or Kokkos::complex static_assert(KokkosFFT::Impl::is_complex_v, "Complex type must be Kokkos::complex or " "Kokkos::complex"); } else { + // T is not Kokkos::complex or Kokkos::complex static_assert(!KokkosFFT::Impl::is_complex_v, - "Complex type must be Kokkos::complex or " + "Complex type must not be Kokkos::complex or " "Kokkos::complex"); } } @@ -99,26 +171,38 @@ template void test_admissible_value_type() { using ViewType = Kokkos::View; using real_type = KokkosFFT::Impl::base_floating_point_type; + // Tests that a Value or View has a addmissible value type if constexpr (std::is_same_v || std::is_same_v) { + // Base floating point type of a Value is float or double + static_assert(KokkosFFT::Impl::is_admissible_value_type_v, + "Base value type must be float or double"); + + // Base floating point type of a View is float or double static_assert(KokkosFFT::Impl::is_admissible_value_type_v, - "Real type must be float or double"); + "Base value type of a View must be float or double"); } else { + // Base floating point type of a Value is not float or double + static_assert(!KokkosFFT::Impl::is_admissible_value_type_v, + "Base value type of a View must not be float or double"); + + // Base floating point type of a View is not float or double static_assert(!KokkosFFT::Impl::is_admissible_value_type_v, - "Real type must be float or double"); + "Base value type of a View must not be float or double"); } } template void test_admissible_layout_type() { using ViewType = Kokkos::View; + // Tests that the View has a layout in LayoutLeft or LayoutRight if constexpr (std::is_same_v || std::is_same_v) { static_assert(KokkosFFT::Impl::is_layout_left_or_right_v, "View Layout must be either LayoutLeft or LayoutRight."); } else { static_assert(!KokkosFFT::Impl::is_layout_left_or_right_v, - "View Layout must be either LayoutLeft or LayoutRight."); + "View Layout must not be either LayoutLeft or LayoutRight."); } } @@ -126,19 +210,78 @@ template void test_admissible_view_type() { using ViewType = Kokkos::View; using real_type = KokkosFFT::Impl::base_floating_point_type; - if constexpr ( - (std::is_same_v || std::is_same_v)&&( - std::is_same_v || - std::is_same_v)) { - static_assert(KokkosFFT::Impl::is_admissible_view_v, - "View value type must be float, double, " - "Kokkos::Complex, Kokkos::Complex. Layout " - "must be either LayoutLeft or LayoutRight."); + + // Tests that the View has a base floating point type in float or double + if constexpr ((std::is_same_v || + std::is_same_v)) { + // Tests that the View has a layout in LayoutLeft or LayoutRight + if constexpr (std::is_same_v || + std::is_same_v) { + static_assert(KokkosFFT::Impl::is_admissible_view_v, + "View value type must be float, double, " + "Kokkos::Complex, Kokkos::Complex. Layout " + "must be either LayoutLeft or LayoutRight."); + } else { + // View is not admissible because layout is not in LayoutLeft or + // LayoutRight + static_assert(!KokkosFFT::Impl::is_admissible_view_v, + "Layout must be either LayoutLeft or LayoutRight."); + } } else { + // View is not admissible because the base floating point type is not in + // float or double static_assert(!KokkosFFT::Impl::is_admissible_view_v, - "View value type must be float, double, " - "Kokkos::Complex, Kokkos::Complex. Layout " - "must be either LayoutLeft or LayoutRight."); + "Base value type must be float or double"); + } +} + +// \brief Test if a View is operatable +// \tparam ExecutionSpace1 Execution space for the device +// \tparam ExecutionSpace2 Execution space for the View memory space +// \tparam T Value type of the View +// \tparam LayoutType Layout type of the View +template +void test_operatable_view_type() { + using ViewType = Kokkos::View; + using real_type = KokkosFFT::Impl::base_floating_point_type; + + // Tests that a View is accessible from the ExecutionSpace + if constexpr (Kokkos::SpaceAccessibility< + ExecutionSpace1, + typename ViewType::memory_space>::accessible) { + // Tests that the View has a base floating point type in float or double + if constexpr ((std::is_same_v || + std::is_same_v)) { + // Tests that the View has a layout in LayoutLeft or LayoutRight + if constexpr (std::is_same_v || + std::is_same_v) { + // View is operatable + static_assert( + KokkosFFT::Impl::is_operatable_view_v, + "View value type must be float, double, " + "Kokkos::Complex, or Kokkos::Complex. Layout " + "must be either LayoutLeft or LayoutRight."); + } else { + // View is not operatable because layout is not in LayoutLeft or + // LayoutRight + static_assert( + !KokkosFFT::Impl::is_operatable_view_v, + "Layout must be either LayoutLeft or LayoutRight."); + } + } else { + // View is not operatable because the base floating point type is not in + // float or double + static_assert( + !KokkosFFT::Impl::is_operatable_view_v, + "Base value type must be float or double"); + } + } else { + // View is not operatable because it is not accessible from + // ExecutionSpace + static_assert( + !KokkosFFT::Impl::is_operatable_view_v, + "ExecutionSpace cannot access data in ViewType"); } } @@ -168,3 +311,330 @@ TYPED_TEST(RealAndComplexViewTypes, admissible_view_type) { test_admissible_view_type(); test_admissible_view_type(); } + +TYPED_TEST(RealAndComplexViewTypes, operatable_view_type) { + using real_type = typename TestFixture::real_type; + using complex_type = typename TestFixture::complex_type; + using layout_type = typename TestFixture::layout_type; + using host_space = Kokkos::DefaultHostExecutionSpace; + using device_space = Kokkos::DefaultExecutionSpace; + + test_operatable_view_type(); + test_operatable_view_type(); + test_operatable_view_type(); + test_operatable_view_type(); + + test_operatable_view_type(); + test_operatable_view_type(); + test_operatable_view_type(); + test_operatable_view_type(); +} + +// Tests for multiple Views +template +void test_have_same_base_floating_point_type() { + using real_type1 = RealType1; + using real_type2 = RealType2; + using complex_type1 = Kokkos::complex; + using complex_type2 = Kokkos::complex; + + using RealViewType1 = Kokkos::View; + using ComplexViewType1 = Kokkos::View; + using RealViewType2 = Kokkos::View; + using ComplexViewType2 = Kokkos::View; + + // Tests that Values or Views have the same base floating point type + if constexpr (std::is_same_v) { + // Values must have the same base floating point type + static_assert( + KokkosFFT::Impl::have_same_base_floating_point_type_v, + "Values must have the same base floating point type"); + static_assert( + KokkosFFT::Impl::have_same_base_floating_point_type_v, + "Values must have the same base floating point type"); + static_assert( + KokkosFFT::Impl::have_same_base_floating_point_type_v, + "Values must have the same base floating point type"); + + // Views must have the same base floating point type + static_assert( + KokkosFFT::Impl::have_same_base_floating_point_type_v, + "ViewTypes must have the same base floating point type"); + static_assert( + KokkosFFT::Impl::have_same_base_floating_point_type_v, + "ViewTypes must have the same base floating point type"); + static_assert( + KokkosFFT::Impl::have_same_base_floating_point_type_v, + "ViewTypes must have the same base floating point type"); + static_assert( + KokkosFFT::Impl::have_same_base_floating_point_type_v, + "ViewTypes must have the same base floating point type"); + } else { + // Values must not have the same base floating point type + static_assert( + !KokkosFFT::Impl::have_same_base_floating_point_type_v, + "Values must not have the same base floating point type"); + static_assert( + !KokkosFFT::Impl::have_same_base_floating_point_type_v, + "Values must not have the same base floating point type"); + + // Views must not have the same base floating point type + static_assert( + !KokkosFFT::Impl::have_same_base_floating_point_type_v, + "ViewTypes must not have the same base floating point type"); + static_assert(!KokkosFFT::Impl::have_same_base_floating_point_type_v< + RealViewType1, ComplexViewType2>, + "ViewTypes must not have the same base floating point type"); + static_assert( + !KokkosFFT::Impl::have_same_base_floating_point_type_v, + "ViewTypes must not have the same base floating point type"); + static_assert(!KokkosFFT::Impl::have_same_base_floating_point_type_v< + ComplexViewType1, ComplexViewType2>, + "ViewTypes must not have the same base floating point type"); + } +} + +template +void test_have_same_layout() { + using RealType = double; + using ViewType1 = Kokkos::View; + using ViewType2 = Kokkos::View; + + // Tests that Views have the same layout + if constexpr (std::is_same_v) { + // Views must have the same layout + static_assert(KokkosFFT::Impl::have_same_layout_v, + "ViewTypes must have the same layout"); + } else { + // Views must not have the same layout + static_assert(!KokkosFFT::Impl::have_same_layout_v, + "ViewTypes must not have the same layout"); + } +} + +template +void test_have_same_rank() { + using RealType = double; + using DynamicRank1ViewType = Kokkos::View; + using DynamicRank2ViewType = Kokkos::View; + using StaticRank1ViewType = Kokkos::View; + using StaticRank2ViewType = Kokkos::View; + using DynamicStaticRank2ViewType = Kokkos::View; + + // Views must have the same rank + static_assert(KokkosFFT::Impl::have_same_rank_v, + "ViewTypes must have the same rank"); + static_assert(KokkosFFT::Impl::have_same_rank_v, + "ViewTypes must have the same rank"); + static_assert(KokkosFFT::Impl::have_same_rank_v, + "ViewTypes must have the same rank"); + + // Views must not have the same rank + static_assert(!KokkosFFT::Impl::have_same_rank_v, + "ViewTypes must not have the same rank"); + static_assert(!KokkosFFT::Impl::have_same_rank_v, + "ViewTypes must not have the same rank"); + static_assert(!KokkosFFT::Impl::have_same_rank_v, + "ViewTypes must not have the same rank"); + static_assert(!KokkosFFT::Impl::have_same_rank_v, + "ViewTypes must not have the same rank"); + static_assert(!KokkosFFT::Impl::have_same_rank_v, + "ViewTypes must not have the same rank"); + static_assert(!KokkosFFT::Impl::have_same_rank_v, + "ViewTypes must not have the same rank"); +} + +// \brief Test if two Views are operatable +// \tparam ExecutionSpace1 Execution space for the device +// \tparam ExecutionSpace2 Execution space for the View memory space +// \tparam RealType1 Base Real Value type of the View1 +// \tparam LayoutType1 Layout type of the View1 +// \tparam RealType2 Base Real Value type of the View2 +// \tparam LayoutType2 Layout type of the View2 +template +void test_are_operatable_views() { + using real_type1 = RealType1; + using real_type2 = RealType2; + using complex_type1 = Kokkos::complex; + using complex_type2 = Kokkos::complex; + + using RealViewType1 = Kokkos::View; + using ComplexViewType1 = + Kokkos::View; + using RealViewType2 = Kokkos::View; + using ComplexViewType2 = + Kokkos::View; + using RealViewType3 = + Kokkos::View; + using ComplexViewType3 = + Kokkos::View; + + // Tests that the Views are accessible from the ExecutionSpace + if constexpr (Kokkos::SpaceAccessibility< + ExecutionSpace1, + typename RealViewType1::memory_space>::accessible) { + // Tests that the Views have the same base floating point type in float or + // double + if constexpr (std::is_same_v && + (std::is_same_v || + std::is_same_v)) { + // Tests that the Views have the same layout in LayoutLeft or LayoutRight + if constexpr (std::is_same_v && + (std::is_same_v || + std::is_same_v)) { + // Tests that the Views are operatable if they have the same rank + static_assert(KokkosFFT::Impl::are_operatable_views_v< + ExecutionSpace1, RealViewType1, RealViewType2>, + "InViewType and OutViewType must have the same rank"); + static_assert(KokkosFFT::Impl::are_operatable_views_v< + ExecutionSpace1, RealViewType1, ComplexViewType2>, + "InViewType and OutViewType must have the same rank"); + static_assert(KokkosFFT::Impl::are_operatable_views_v< + ExecutionSpace1, ComplexViewType1, RealViewType2>, + "InViewType and OutViewType must have the same rank"); + static_assert(KokkosFFT::Impl::are_operatable_views_v< + ExecutionSpace1, ComplexViewType1, ComplexViewType2>, + "InViewType and OutViewType must have the same rank"); + + // Tests that the Views are not operatable if the ranks are not the same + static_assert(!KokkosFFT::Impl::are_operatable_views_v< + ExecutionSpace1, RealViewType1, RealViewType3>, + "InViewType and OutViewType must have the same rank"); + static_assert(!KokkosFFT::Impl::are_operatable_views_v< + ExecutionSpace1, RealViewType1, ComplexViewType3>, + "InViewType and OutViewType must have the same rank"); + static_assert(!KokkosFFT::Impl::are_operatable_views_v< + ExecutionSpace1, ComplexViewType1, RealViewType3>, + "InViewType and OutViewType must have the same rank"); + static_assert(!KokkosFFT::Impl::are_operatable_views_v< + ExecutionSpace1, ComplexViewType1, ComplexViewType3>, + "InViewType and OutViewType must have the same rank"); + } else { + // Views are not operatable because they do not have the same layout in + // LayoutLeft or LayoutRight + static_assert(!KokkosFFT::Impl::are_operatable_views_v< + ExecutionSpace1, RealViewType1, RealViewType2>, + "Layouts are not identical or one of them is not " + "LayoutLeft or LayoutRight"); + static_assert(!KokkosFFT::Impl::are_operatable_views_v< + ExecutionSpace1, RealViewType1, ComplexViewType2>, + "Layouts are not identical or one of them is not " + "LayoutLeft or LayoutRight"); + static_assert(!KokkosFFT::Impl::are_operatable_views_v< + ExecutionSpace1, ComplexViewType1, RealViewType2>, + "Layouts are not identical or one of them is not " + "LayoutLeft or LayoutRight"); + static_assert(!KokkosFFT::Impl::are_operatable_views_v< + ExecutionSpace1, ComplexViewType1, ComplexViewType2>, + "Layouts are not identical or one of them is not " + "LayoutLeft or LayoutRight"); + } + } else { + // Views are not operatable because they do not have the same base + // floating point type in float or double + static_assert(!KokkosFFT::Impl::are_operatable_views_v< + ExecutionSpace1, RealViewType1, RealViewType2>, + "Base value types are not identical or one of them is not " + "float or double"); + static_assert(!KokkosFFT::Impl::are_operatable_views_v< + ExecutionSpace1, RealViewType1, ComplexViewType2>, + "Base value types are not identical or one of them is not " + "float or double"); + static_assert(!KokkosFFT::Impl::are_operatable_views_v< + ExecutionSpace1, ComplexViewType1, RealViewType2>, + "Base value types are not identical or one of them is not " + "float or double"); + static_assert(!KokkosFFT::Impl::are_operatable_views_v< + ExecutionSpace1, ComplexViewType1, ComplexViewType2>, + "Base value types are not identical or one of them is not " + "float or double"); + } + } else { + // Views are not operatable because they are not accessible from + // ExecutionSpace + static_assert( + !KokkosFFT::Impl::are_operatable_views_v, + "Either InViewType or OutViewType is not accessible from " + "ExecutionSpace"); + static_assert( + !KokkosFFT::Impl::are_operatable_views_v, + "Either InViewType or OutViewType is not accessible from " + "ExecutionSpace"); + static_assert(!KokkosFFT::Impl::are_operatable_views_v< + ExecutionSpace1, ComplexViewType1, RealViewType2>, + "Either InViewType or OutViewType is not accessible from " + "ExecutionSpace"); + static_assert(!KokkosFFT::Impl::are_operatable_views_v< + ExecutionSpace1, ComplexViewType1, ComplexViewType2>, + "Either InViewType or OutViewType is not accessible from " + "ExecutionSpace"); + } +} + +TYPED_TEST(PairedValueTypes, have_same_base_floating_point_type) { + using real_type1 = typename TestFixture::real_type1; + using real_type2 = typename TestFixture::real_type2; + + test_have_same_base_floating_point_type(); +} + +TYPED_TEST(PairedLayoutTypes, have_same_layout) { + using layout_type1 = typename TestFixture::layout_type1; + using layout_type2 = typename TestFixture::layout_type2; + + test_have_same_layout(); +} + +TYPED_TEST(PairedLayoutTypes, have_same_rank) { + using layout_type1 = typename TestFixture::layout_type1; + using layout_type2 = typename TestFixture::layout_type2; + + test_have_same_rank(); +} + +TYPED_TEST(PairedViewTypes, are_operatable_views) { + using real_type1 = typename TestFixture::real_type1; + using layout_type1 = typename TestFixture::layout_type1; + using real_type2 = typename TestFixture::real_type2; + using layout_type2 = typename TestFixture::layout_type2; + using host_space = Kokkos::DefaultHostExecutionSpace; + using device_space = Kokkos::DefaultExecutionSpace; + + test_are_operatable_views(); + test_are_operatable_views(); + test_are_operatable_views(); + test_are_operatable_views(); +} diff --git a/common/unit_test/Test_Utils.hpp b/common/unit_test/Test_Utils.hpp index d30aa9b0..28fe30ca 100644 --- a/common/unit_test/Test_Utils.hpp +++ b/common/unit_test/Test_Utils.hpp @@ -5,6 +5,9 @@ #ifndef TEST_UTILS_HPP #define TEST_UTILS_HPP +#include +#include +#include #include "Test_Types.hpp" template @@ -54,4 +57,95 @@ void display(std::string name, std::vector& values) { } } -#endif \ No newline at end of file +/// Transform a sequence S to a tuple: +/// - a std::integer_sequence to a +/// std::tuple...> +/// - a std::pair to a std::tuple +/// - identity otherwise (std::tuple) +template +struct to_tuple { + using type = S; +}; + +template +struct to_tuple> { + using type = std::tuple...>; +}; + +template +struct to_tuple> { + using type = std::tuple; +}; + +template +using to_tuple_t = typename to_tuple::type; + +template +struct for_each_tuple_cat; + +template +struct for_each_tuple_cat, Tuple> { + using type = std::tuple(), + std::declval()))...>; +}; + +/// Construct a tuple of tuples that is the result of the concatenation of the +/// tuples in TupleOfTuples with Tuple. +template +using for_each_tuple_cat_t = + typename for_each_tuple_cat::type; + +static_assert( + std::is_same_v, + std::tuple>, + std::tuple>, + std::tuple, + std::tuple>>); + +static_assert( + std::is_same_v>, + std::tuple>, + std::tuple>>); + +template +struct cartesian_product_impl; + +template +struct cartesian_product_impl< + std::tuple, TailTuples...>, OutTupleOfTuples> + : cartesian_product_impl< + std::tuple, + decltype(std::tuple_cat( + std::declval>>()...))> { +}; + +template +struct cartesian_product_impl, OutTupleOfTuples> { + using type = OutTupleOfTuples; +}; + +/// Generate a std::tuple cartesian product from multiple tuple-like structures +/// (std::tuple, std::integer_sequence and std::pair) Do not rely on the +/// ordering result. +template +using cartesian_product_t = + typename cartesian_product_impl...>, + std::tuple>>::type; + +/// Transform a std::tuple to a testing::Types, identity +/// otherwise +template +struct tuple_to_types { + using type = T; +}; + +template +struct tuple_to_types> { + using type = testing::Types; +}; + +template +using tuple_to_types_t = typename tuple_to_types::type; + +#endif