diff --git a/core/src/impl/Kokkos_ViewMapping.hpp b/core/src/impl/Kokkos_ViewMapping.hpp index 16ca33a87d0..2b0bbad24dd 100644 --- a/core/src/impl/Kokkos_ViewMapping.hpp +++ b/core/src/impl/Kokkos_ViewMapping.hpp @@ -3131,8 +3131,8 @@ class ViewMapping< using handle_type = typename ViewDataHandle::handle_type; - handle_type m_impl_handle; - offset_type m_impl_offset; + handle_type m_impl_handle = nullptr; + offset_type m_impl_offset{}; private: template @@ -3348,14 +3348,25 @@ class ViewMapping< //---------------------------------------- KOKKOS_DEFAULTED_FUNCTION ~ViewMapping() = default; - KOKKOS_INLINE_FUNCTION ViewMapping() : m_impl_handle(), m_impl_offset() {} + KOKKOS_DEFAULTED_FUNCTION ViewMapping() = default; KOKKOS_DEFAULTED_FUNCTION ViewMapping(const ViewMapping&) = default; KOKKOS_DEFAULTED_FUNCTION ViewMapping& operator=(const ViewMapping&) = default; - KOKKOS_DEFAULTED_FUNCTION ViewMapping(ViewMapping&&) = default; - KOKKOS_DEFAULTED_FUNCTION ViewMapping& operator=(ViewMapping&&) = default; + //! Move constructor. Leaves @p other in an empty state. + KOKKOS_INLINE_FUNCTION + ViewMapping(ViewMapping&& other) + : m_impl_handle(std::exchange(other.m_impl_handle, nullptr)), + m_impl_offset(std::move(other.m_impl_offset)) {} + + //! Move assignment. Leaves @p other in an empty state. + KOKKOS_INLINE_FUNCTION + ViewMapping& operator=(ViewMapping&& other) { + m_impl_handle = std::exchange(other.m_impl_handle, nullptr); + m_impl_offset = std::move(other.m_impl_offset); + return *this; + } //---------------------------------------- diff --git a/core/src/impl/Kokkos_ViewTracker.hpp b/core/src/impl/Kokkos_ViewTracker.hpp index 43958db3900..02ddd5ad4e6 100644 --- a/core/src/impl/Kokkos_ViewTracker.hpp +++ b/core/src/impl/Kokkos_ViewTracker.hpp @@ -42,9 +42,10 @@ struct ViewTracker { track_type m_tracker; - KOKKOS_INLINE_FUNCTION - ViewTracker() : m_tracker() {} + KOKKOS_DEFAULTED_FUNCTION + ViewTracker() = default; + //! Copy constructor. KOKKOS_INLINE_FUNCTION ViewTracker(const ViewTracker& vt) noexcept : m_tracker(vt.m_tracker, view_traits::is_managed) {} @@ -73,6 +74,7 @@ struct ViewTracker { KOKKOS_IF_ON_DEVICE((m_tracker.assign_force_disable(vt.m_track.m_tracker);)) } + //! Copy assignment. KOKKOS_INLINE_FUNCTION ViewTracker& operator=( const ViewTracker& rhs) noexcept { if (this == &rhs) return *this; @@ -89,6 +91,17 @@ struct ViewTracker { KOKKOS_INLINE_FUNCTION explicit ViewTracker(const track_type& tt) noexcept : m_tracker(tt, view_traits::is_managed) {} + + //! Move constructor. + KOKKOS_INLINE_FUNCTION + ViewTracker(ViewTracker&& other) : m_tracker(std::move(other.m_tracker)) {} + + //! Move assignment. + KOKKOS_INLINE_FUNCTION + ViewTracker& operator=(ViewTracker&& other) { + m_tracker = std::move(other.m_tracker); + return *this; + } }; } // namespace Impl diff --git a/core/unit_test/CMakeLists.txt b/core/unit_test/CMakeLists.txt index 8c9a6684987..d77c7832bc2 100644 --- a/core/unit_test/CMakeLists.txt +++ b/core/unit_test/CMakeLists.txt @@ -240,6 +240,7 @@ foreach(Tag Threads;Serial;OpenMP;Cuda;HPX;OpenMPTarget;OpenACC;HIP;SYCL) ViewMapping_b ViewMapping_subview ViewMemoryAccessViolation + ViewMove ViewOfClass ViewResize WorkGraph diff --git a/core/unit_test/TestViewMove.hpp b/core/unit_test/TestViewMove.hpp new file mode 100644 index 00000000000..9a13560c573 --- /dev/null +++ b/core/unit_test/TestViewMove.hpp @@ -0,0 +1,59 @@ +//@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 +#ifndef TESTVIEWMOVE_HPP_ +#define TESTVIEWMOVE_HPP_ + +#include +#include + +namespace Test { + +template +struct TestViewMove { + template , view_t>>> + TestViewMove(T&& view_) : view(std::forward(view_)) {} + + view_t view; +}; + +/** + * @test Ensure that @ref Kokkos::View and its members have proper move + * semantics. + */ +TEST(TEST_CATEGORY, view_move) { + using execution_space = TEST_EXECSPACE; + using view_t = Kokkos::View; + using tester_t = TestViewMove; + + view_t view("view move test", 5); + + EXPECT_EQ(view.use_count(), 1); + EXPECT_TRUE(view.is_allocated()); + + tester_t tester{std::move(view)}; + + //! As @ref view was moved, it's left in a pristine (a.k.a. *empty*) state. + EXPECT_EQ(view.use_count(), 0); + EXPECT_FALSE(view.is_allocated()); + + EXPECT_EQ(tester.view.use_count(), 1); + EXPECT_TRUE(tester.view.is_allocated()); +} + +} // namespace Test + +#endif // TESTVIEWMOVE_HPP_