//@HEADER // ************************************************************************ // // Kokkos v. 4.0 // Copyright (2022) National Technology & Engineering // Solutions of Sandia, LLC (NTESS). // // Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions. // See https://kokkos.org/LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //@HEADER #include #include #include #include "experimental/__p0009_bits/layout_stride.hpp" namespace { template struct TestViewMDSpanConversion { using value_type = T; template using layout_left_padded = Kokkos::Experimental::layout_left_padded; template using layout_right_padded = Kokkos::Experimental::layout_right_padded; struct TestAccessor { using offset_policy = TestAccessor; using element_type = value_type; using reference = element_type &; using data_handle_type = element_type *; constexpr TestAccessor() noexcept = default; constexpr reference access(data_handle_type p, std::size_t i) noexcept { return p[i]; } constexpr data_handle_type offset(data_handle_type p, std::size_t i) noexcept { return p + i; } }; template static void test_conversion_from_mdspan( Kokkos::View ref, const MDSpanLayoutMapping &mapping) { using unmanaged_view_type = Kokkos::View>; using natural_mdspan_type = typename Kokkos::Impl::MDSpanViewTraits< typename unmanaged_view_type::traits>::mdspan_type; using mapping_type = MDSpanLayoutMapping; using mdspan_layout_type = typename MDSpanLayoutMapping::layout_type; using extents_type = typename mapping_type::extents_type; using mdspan_type = Kokkos::mdspan; static_assert(std::is_constructible_v); static_assert(std::is_convertible_v == std::is_convertible_v); // Manually create an mdspan from ref so we have a valid pointer to play // with const auto &exts = mapping.extents(); auto mds = mdspan_type{ref.data(), mapping}; auto test_view = unmanaged_view_type(mds); ASSERT_EQ(test_view.data(), ref.data()); ASSERT_EQ(test_view.data(), mds.data_handle()); ASSERT_EQ(test_view.layout(), ref.layout()); for (std::size_t r = 0; r < mdspan_type::rank(); ++r) { ASSERT_EQ(test_view.extent(r), ref.extent(r)); ASSERT_EQ(test_view.extent(r), exts.extent(r)); } } template static void test_conversion_to_mdspan( const MDSpanLayoutMapping &ref_layout_mapping, ViewType v) { using view_type = ViewType; using natural_mdspan_type = typename Kokkos::Impl::MDSpanViewTraits< typename view_type::traits>::mdspan_type; static_assert(natural_mdspan_type::rank() == view_type::rank); static_assert(std::is_same_v); constexpr bool is_strided_layout = std::is_same_v; if constexpr (!is_strided_layout) { static_assert(natural_mdspan_type::mapping_type::padding_value == Kokkos::dynamic_extent); } // test conversion operator to natural mdspan { natural_mdspan_type cvt = v; ASSERT_EQ(cvt.data_handle(), v.data()); ASSERT_EQ(cvt.mapping(), ref_layout_mapping); if constexpr (!is_strided_layout && natural_mdspan_type::rank() > 1) { ASSERT_EQ(cvt.mapping().stride(1), ref_layout_mapping.stride(1)); } } // test to_mdspan() returning natural mdspan { auto cvt = v.to_mdspan(); static_assert(std::is_same_v); ASSERT_EQ(cvt.data_handle(), v.data()); ASSERT_EQ(cvt.mapping(), ref_layout_mapping); } // test conversion operator to different mdspan type { using element_type = const typename natural_mdspan_type::element_type; using const_acc_type = Kokkos::Impl::SpaceAwareAccessor< typename ViewType::memory_space, Kokkos::default_accessor>; using mdspan_type = Kokkos::mdspan< element_type, Kokkos::dextents, typename natural_mdspan_type::layout_type, const_acc_type>; mdspan_type cvt = v; ASSERT_EQ(cvt.data_handle(), v.data()); ASSERT_EQ(cvt.mapping(), ref_layout_mapping); } } template static void test_conversion_to_mdspan_with_accessor( const MDSpanLayoutMapping &ref_layout_mapping, ViewType v, const AccessorType &a) { auto cvt = v.to_mdspan(a); static_assert(decltype(cvt)::rank() == ViewType::rank); static_assert(std::is_same_v); ASSERT_EQ(cvt.data_handle(), v.data()); ASSERT_EQ(cvt.mapping(), ref_layout_mapping); } template using natural_mdspan_type_for_view = typename Kokkos::Impl::MDSpanViewTraits< typename ViewType::traits>::mdspan_type; static void run_test() { // Verify we can only convert to compatible mdspans static_assert(std::is_convertible_v< Kokkos::View, natural_mdspan_type_for_view>>); static_assert( std::is_convertible_v< Kokkos::View, natural_mdspan_type_for_view>>); // Do not cast const away static_assert(!std::is_convertible_v< Kokkos::View, natural_mdspan_type_for_view>>); // Mismatched dim static_assert(!std::is_convertible_v< Kokkos::View, natural_mdspan_type_for_view>>); // Mismatched layouts static_assert( !std::is_convertible_v, natural_mdspan_type_for_view>>); static_assert( !std::is_convertible_v, natural_mdspan_type_for_view>>); // nvcc doesn't do CTAD properly here, making this way more verbose.. // LayoutLeft test_conversion_from_mdspan( Kokkos::View("ref", 7), typename layout_left_padded<7>::template mapping< Kokkos::dextents>{ Kokkos::dextents(7)}); test_conversion_from_mdspan( Kokkos::View("ref"), typename layout_left_padded<7>::template mapping< Kokkos::extents>{ Kokkos::extents()}); test_conversion_from_mdspan( Kokkos::View("ref"), typename layout_left_padded<7>::template mapping< Kokkos::dextents>{ Kokkos::dextents(7)}); test_conversion_from_mdspan( Kokkos::View("ref", 7), typename layout_left_padded<7>::template mapping< Kokkos::extents>{ Kokkos::extents()}); test_conversion_from_mdspan( Kokkos::View("ref", 7, 3), typename layout_left_padded<7>::template mapping< Kokkos::dextents>{ Kokkos::dextents(7, 3)}); test_conversion_from_mdspan( Kokkos::View( "ref"), typename layout_left_padded<7>::template mapping< Kokkos::extents>{ Kokkos::extents()}); test_conversion_from_mdspan( Kokkos::View( "ref"), typename layout_left_padded<7>::template mapping< Kokkos::dextents>{ Kokkos::dextents(7, 3)}); test_conversion_from_mdspan( Kokkos::View("ref", 7, 3), typename layout_left_padded<7>::template mapping< Kokkos::extents>{ Kokkos::extents()}); // LayoutRight test_conversion_from_mdspan( Kokkos::View("ref", 7), typename layout_right_padded<7>::template mapping< Kokkos::dextents>{ Kokkos::dextents(7)}); test_conversion_from_mdspan( Kokkos::View("ref"), typename layout_right_padded<7>::template mapping< Kokkos::extents>{ Kokkos::extents()}); test_conversion_from_mdspan( Kokkos::View("ref"), typename layout_right_padded<7>::template mapping< Kokkos::dextents>{ Kokkos::dextents(7)}); test_conversion_from_mdspan( Kokkos::View("ref", 7), typename layout_right_padded<7>::template mapping< Kokkos::extents>{ Kokkos::extents()}); test_conversion_from_mdspan( Kokkos::View("ref", 3, 7), typename layout_right_padded<7>::template mapping< Kokkos::dextents>{ Kokkos::dextents(3, 7)}); test_conversion_from_mdspan( Kokkos::View( "ref"), typename layout_right_padded<7>::template mapping< Kokkos::extents>{ Kokkos::extents()}); test_conversion_from_mdspan( Kokkos::View( "ref"), typename layout_right_padded<7>::template mapping< Kokkos::dextents>{ Kokkos::dextents(3, 7)}); test_conversion_from_mdspan( Kokkos::View("ref", 3, 7), typename layout_right_padded<7>::template mapping< Kokkos::extents>{ Kokkos::extents()}); // LayoutStride { const size_t strides[] = {2}; test_conversion_from_mdspan( Kokkos::View( "ref", Kokkos::LayoutStride{7, 2}), Kokkos::layout_stride::mapping>{ Kokkos::mdspan_non_standard, Kokkos::dextents{7}, strides}); } { const size_t strides[] = {2}; test_conversion_from_mdspan( Kokkos::View( "ref", Kokkos::LayoutStride{7, 2}), Kokkos::layout_stride::mapping>{ Kokkos::mdspan_non_standard, {}, strides}); } { const size_t strides[] = {2}; test_conversion_from_mdspan( Kokkos::View( "ref", Kokkos::LayoutStride{7, 2}), Kokkos::layout_stride::mapping>{ Kokkos::mdspan_non_standard, Kokkos::dextents{7}, strides}); } { const size_t strides[] = {2}; test_conversion_from_mdspan( Kokkos::View( "ref", Kokkos::LayoutStride{7, 2}), Kokkos::layout_stride::mapping>{ Kokkos::mdspan_non_standard, Kokkos::extents(), strides}); } { const size_t strides[] = {2, 4}; test_conversion_from_mdspan( Kokkos::View( "ref", Kokkos::LayoutStride{7, 2, 3, 4}), Kokkos::layout_stride::mapping>{ Kokkos::mdspan_non_standard, Kokkos::dextents(7, 3), strides}); } { const size_t strides[] = {2, 4}; test_conversion_from_mdspan( Kokkos::View( "ref", Kokkos::LayoutStride{7, 2, 3, 4}), Kokkos::layout_stride::mapping>{ Kokkos::mdspan_non_standard, Kokkos::extents(), strides}); } { const size_t strides[] = {2, 4}; test_conversion_from_mdspan( Kokkos::View( "ref", Kokkos::LayoutStride{7, 2, 3, 4}), Kokkos::layout_stride::mapping>{ Kokkos::mdspan_non_standard, Kokkos::dextents(7, 3), strides}); } { const size_t strides[] = {2, 4}; test_conversion_from_mdspan( Kokkos::View( "ref", Kokkos::LayoutStride{7, 2, 3, 4}), Kokkos::layout_stride::mapping>{ Kokkos::mdspan_non_standard, Kokkos::extents(), strides}); } // Conversion to mdspan test_conversion_to_mdspan( layout_left_padded::mapping< Kokkos::extents>({}, 4), Kokkos::View("v", 4)); test_conversion_to_mdspan( layout_left_padded::mapping< Kokkos::extents>({}, 4), Kokkos::View("v", 4, 7)); test_conversion_to_mdspan( layout_right_padded::mapping< Kokkos::extents>({}, 4), Kokkos::View("v", 4)); test_conversion_to_mdspan( layout_right_padded::mapping< Kokkos::extents>({}, 7), Kokkos::View("v", 4, 7)); { const size_t strides[] = {5}; test_conversion_to_mdspan( Kokkos::layout_stride::mapping>( Kokkos::mdspan_non_standard, {}, strides), Kokkos::View( "v", Kokkos::LayoutStride{4, 5})); } { const size_t strides[] = {5, 9}; test_conversion_to_mdspan( Kokkos::layout_stride::mapping>( Kokkos::mdspan_non_standard, {}, strides), Kokkos::View( "v", Kokkos::LayoutStride{4, 5, 7, 9})); } // Aligned types (for padded layouts) test_conversion_to_mdspan( layout_left_padded::mapping< Kokkos::extents>({}, 128), Kokkos::View( Kokkos::view_alloc("v", Kokkos::AllowPadding), 127, 7)); test_conversion_to_mdspan( layout_right_padded::mapping< Kokkos::extents>({}, 128), Kokkos::View( Kokkos::view_alloc("v", Kokkos::AllowPadding), 7, 127)); // Conversion with standard default_accessor test_conversion_to_mdspan_with_accessor( layout_left_padded::mapping< Kokkos::extents>({}, 4), Kokkos::View("v", 4), Kokkos::default_accessor{}); test_conversion_to_mdspan_with_accessor( layout_left_padded::mapping< Kokkos::extents>({}, 4), Kokkos::View("v", 4, 7), Kokkos::default_accessor{}); test_conversion_to_mdspan_with_accessor( layout_right_padded::mapping< Kokkos::extents>({}, 4), Kokkos::View("v", 4), Kokkos::default_accessor{}); test_conversion_to_mdspan_with_accessor( layout_right_padded::mapping< Kokkos::extents>({}, 7), Kokkos::View("v", 4, 7), Kokkos::default_accessor{}); { const size_t strides[] = {5}; test_conversion_to_mdspan_with_accessor( Kokkos::layout_stride::mapping>( Kokkos::mdspan_non_standard, {}, strides), Kokkos::View( "v", Kokkos::LayoutStride{4, 5}), Kokkos::default_accessor{}); } { const size_t strides[] = {5, 9}; test_conversion_to_mdspan_with_accessor( Kokkos::layout_stride::mapping>( Kokkos::mdspan_non_standard, {}, strides), Kokkos::View( "v", Kokkos::LayoutStride{4, 5, 7, 9}), Kokkos::default_accessor{}); } // Conversion with a test accessor test_conversion_to_mdspan_with_accessor( layout_left_padded::mapping< Kokkos::extents>({}, 4), Kokkos::View("v", 4), TestAccessor{}); test_conversion_to_mdspan_with_accessor( layout_left_padded::mapping< Kokkos::extents>({}, 4), Kokkos::View("v", 4, 7), TestAccessor{}); test_conversion_to_mdspan_with_accessor( layout_right_padded::mapping< Kokkos::extents>({}, 4), Kokkos::View("v", 4), TestAccessor{}); test_conversion_to_mdspan_with_accessor( layout_right_padded::mapping< Kokkos::extents>({}, 7), Kokkos::View("v", 4, 7), TestAccessor{}); { const size_t strides[] = {5}; test_conversion_to_mdspan_with_accessor( Kokkos::layout_stride::mapping>( Kokkos::mdspan_non_standard, {}, strides), Kokkos::View( "v", Kokkos::LayoutStride{4, 5}), TestAccessor{}); } { const size_t strides[] = {5, 9}; test_conversion_to_mdspan_with_accessor( Kokkos::layout_stride::mapping>( Kokkos::mdspan_non_standard, {}, strides), Kokkos::View( "v", Kokkos::LayoutStride{4, 5, 7, 9}), TestAccessor{}); } } }; TEST(TEST_CATEGORY, view_mdspan_conversion) { TestViewMDSpanConversion::run_test(); TestViewMDSpanConversion::run_test(); TestViewMDSpanConversion::run_test(); } } // namespace