diff --git a/include/experimental/p3242_bits/copy.hpp b/include/experimental/p3242_bits/copy.hpp new file mode 100644 index 00000000..ef7e3d0e --- /dev/null +++ b/include/experimental/p3242_bits/copy.hpp @@ -0,0 +1,114 @@ +//@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 +#pragma once + +#include "../__p0009_bits/default_accessor.hpp" +#include "../__p0009_bits/extents.hpp" +#include "../__p0009_bits/layout_left.hpp" +#include "../__p0009_bits/layout_right.hpp" +#include "../__p0009_bits/mdspan.hpp" +#include +#include +#include +#include +#include + +namespace MDSPAN_IMPL_STANDARD_NAMESPACE { +namespace MDSPAN_IMPL_PROPOSED_NAMESPACE { +namespace detail { + +template +constexpr void apply_fun_over_extents(const Extents &ext, F &&fun, + ArrayType &indices, + std::index_sequence<>) { + std::apply(std::forward(fun), indices); +} + +template +constexpr void apply_fun_over_extents(const Extents &ext, F &&fun, + ArrayType &indices, + std::index_sequence) { + using index_type = typename Extents::index_type; + for (index_type i = 0; i < ext.extent(R); ++i) { + indices[R] = i; + apply_fun_over_extents(ext, std::forward(fun), indices, std::index_sequence{}); + } +} + +template struct make_reverse_index_sequence_impl; + +template +struct make_reverse_index_sequence_impl> { + using type = std::index_sequence<(N - 1 - Indices)...>; +}; + +template +using make_reverse_index_sequence = typename make_reverse_index_sequence_impl< + N, std::make_index_sequence>::type; + +template +struct mdspan_copy_impl { + using extents_type = typename DstMDSpanType::extents_type; + + static constexpr void copy_over_extents(const extents_type &ext, + const SrcMDSpanType &src, + const DstMDSpanType &dst) { + // Generic copy algorithm; this assumes a roughly layout-right traversal + // but this may not be cache efficient if we can't determine anything about + // the layout memory ordering + constexpr auto rank = extents_type::rank(); + auto indices = std::array{}; + apply_fun_over_extents( + ext, [&src, &dst](auto... idxs) { dst[idxs...] = src[idxs...]; }, + indices, std::make_index_sequence{}); + } +}; + +template + requires (SrcLayout::template mapping::is_always_exhaustive() && DstLayout::template mapping::is_always_exhaustive()) +struct mdspan_copy_impl< + mdspan, + mdspan> { + using extents_type = DstExtents; + using src_mdspan_type = mdspan>; + using dst_mdspan_type = mdspan>; + + static constexpr void copy_over_extents(const extents_type &ext, + const src_mdspan_type &src, + const dst_mdspan_type &dst) { + std::copy(src.data_handle(), src.data_handle() + src.mapping().required_span_size(), dst.data_handle()); + } +}; +} // namespace detail + +template +constexpr void copy( + mdspan src, + mdspan + dst) { + using src_type = + mdspan; + using dst_type = + mdspan; + detail::mdspan_copy_impl::copy_over_extents(DstExtents{src.extents()}, + src, dst); +} +} // namespace MDSPAN_IMPL_PROPOSED_NAMESPACE +} // namespace MDSPAN_IMPL_STANDARD_NAMESPACE diff --git a/include/mdspan/mdspan.hpp b/include/mdspan/mdspan.hpp index 4a0e354f..fa06d212 100644 --- a/include/mdspan/mdspan.hpp +++ b/include/mdspan/mdspan.hpp @@ -37,6 +37,7 @@ #if MDSPAN_HAS_CXX_17 #include "../experimental/__p2642_bits/layout_padded.hpp" #include "../experimental/__p2630_bits/submdspan.hpp" +#include "../experimental/p3242_bits/copy.hpp" #endif #include "../experimental/__p2389_bits/dims.hpp" diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 1693ac65..4c5167f2 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -99,6 +99,7 @@ if(NOT CMAKE_CXX_STANDARD STREQUAL "14") mdspan_add_test(test_submdspan_static_slice) mdspan_add_test(test_layout_padded_left ENABLE_PRECONDITIONS) mdspan_add_test(test_layout_padded_right ENABLE_PRECONDITIONS) + mdspan_add_test(test_mdspan_copy_and_fill) endif() # both of those don't work yet since its using vector if(NOT MDSPAN_ENABLE_CUDA AND NOT MDSPAN_ENABLE_HIP) diff --git a/tests/test_mdspan_copy_and_fill.cpp b/tests/test_mdspan_copy_and_fill.cpp new file mode 100644 index 00000000..f71fb940 --- /dev/null +++ b/tests/test_mdspan_copy_and_fill.cpp @@ -0,0 +1,139 @@ +//@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 + +template +constexpr auto make_mdarray(const Extents &exts) { + Kokkos::Experimental::mdarray mds{exts}; + for (size_t i = 0; i < mds.mapping().required_span_size(); ++i) + mds.data()[i] = static_cast(i); + + return mds; +} + +template +constexpr auto make_constexpr_array_impl(std::index_sequence) { + constexpr auto sz = (Extents::static_extent(Indices) * ...); + std::array ret; + for (size_t i = 0; i < sz; ++i) + ret[i] = static_cast(i); + + return ret; +} + +template +constexpr auto array_size_impl(std::index_sequence) { + return (Extents::static_extent(Indices) * ...); +} + + +template +constexpr size_t array_size() { + return array_size_impl(); +} + + +template +constexpr auto make_constexpr_array() { + return make_constexpr_array_impl(std::make_index_sequence{}); +} + +template +constexpr auto make_mdarray_copy(const Kokkos::mdspan &src) { + Kokkos::Experimental::mdarray dst{}; + Kokkos::Experimental::copy(src, dst.to_mdspan()); + + return dst; +} + +template +constexpr bool test_mdspan_copy_check(const SrcExtents &src_exts, + const DstExtents &dst_exts) { + Kokkos::Experimental::mdarray src1 = + make_mdarray(src_exts); + Kokkos::Experimental::mdarray dst1{dst_exts}; + + if (dst1.container() == src1.container()) return false; + Kokkos::Experimental::copy(src1.to_mdspan(), dst1.to_mdspan()); + return dst1.container() == src1.container(); +} + +template +void test_mdspan_copy_impl(const SrcExtents &src_exts, + const DstExtents &dst_exts) { + ASSERT_TRUE( + (test_mdspan_copy_check(src_exts, dst_exts))); +} + +template +constexpr bool test_mdspan_copy_constexpr_impl() { + auto arr = make_constexpr_array(); + Kokkos::Experimental::mdarray src1(SrcExtents{}, arr); + Kokkos::Experimental::mdarray dst1{}; + + Kokkos::Experimental::copy(src1.to_mdspan(), dst1.to_mdspan()); + + for ( std::size_t i = 0; i < arr.size(); ++i ) + if (dst1.container()[i] != src1.container()[i]) + return false; + + return true; +} + +template +void test_mdspan_copy_constexpr() { + static_assert(test_mdspan_copy_constexpr_impl()); +} + +TEST(TestMdspanCopyAndFill, test_mdspan_copy) { + test_mdspan_copy_impl( + Kokkos::extents{}, Kokkos::extents{}); + test_mdspan_copy_impl( + Kokkos::extents{}, Kokkos::extents{}); + test_mdspan_copy_impl( + Kokkos::extents{}, Kokkos::extents{}); + + test_mdspan_copy_impl( + Kokkos::dextents{5, 3}, Kokkos::extents{}); + test_mdspan_copy_impl( + Kokkos::dextents{5, 3}, Kokkos::extents{}); + test_mdspan_copy_impl( + Kokkos::dextents{5, 3}, Kokkos::extents{}); + + test_mdspan_copy_impl( + Kokkos::extents{}, Kokkos::dextents{5, 3}); + test_mdspan_copy_impl( + Kokkos::extents{}, Kokkos::dextents{5, 3}); + test_mdspan_copy_impl( + Kokkos::extents{}, Kokkos::dextents{5, 3}); + + test_mdspan_copy_impl( + Kokkos::dextents{5, 3}, Kokkos::dextents{5, 3}); + test_mdspan_copy_impl( + Kokkos::dextents{5, 3}, Kokkos::dextents{5, 3}); + test_mdspan_copy_impl( + Kokkos::dextents{5, 3}, Kokkos::dextents{5, 3}); + + test_mdspan_copy_constexpr, Kokkos::layout_left, + Kokkos::extents, Kokkos::layout_left>(); +}