diff --git a/include/llama/RecordRef.hpp b/include/llama/RecordRef.hpp index 596127ded1..aa905f9e77 100644 --- a/include/llama/RecordRef.hpp +++ b/include/llama/RecordRef.hpp @@ -436,7 +436,7 @@ namespace llama else { LLAMA_FORCE_INLINE_RECURSIVE - return this->view.accessor(arrayIndex(), AbsolutCoord{}); + return this->view.access(arrayIndex(), AbsolutCoord{}); } } @@ -454,7 +454,7 @@ namespace llama else { LLAMA_FORCE_INLINE_RECURSIVE - return this->view.accessor(arrayIndex(), AbsolutCoord{}); + return this->view.access(arrayIndex(), AbsolutCoord{}); } } diff --git a/include/llama/View.hpp b/include/llama/View.hpp index 6632277744..b9bb0c8c44 100644 --- a/include/llama/View.hpp +++ b/include/llama/View.hpp @@ -16,10 +16,20 @@ namespace llama { + /// Default accessor. Passes through the given reference. + struct DefaultAccessor + { + template + LLAMA_FN_HOST_ACC_INLINE auto operator()(Reference&& r) const -> Reference + { + return std::forward(r); + } + }; + #ifdef __cpp_lib_concepts - template + template #else - template + template #endif struct View; @@ -321,13 +331,15 @@ namespace llama /// view should be created using \ref allocView. /// \tparam TMapping The mapping used by the view to map accesses into memory. /// \tparam BlobType The storage type used by the view holding memory. + /// \tparam TAccessor The accessor to use when an access is made through this view. #ifdef __cpp_lib_concepts - template + template #else - template + template #endif struct LLAMA_DECLSPEC_EMPTY_BASES View : private TMapping + , private TAccessor #if CAN_USE_RANGES , std::ranges::view_base #endif @@ -337,6 +349,7 @@ namespace llama using ArrayExtents = typename Mapping::ArrayExtents; using ArrayIndex = typename Mapping::ArrayIndex; using RecordDim = typename Mapping::RecordDim; + using Accessor = TAccessor; using iterator = Iterator; using const_iterator = Iterator; using size_type = typename ArrayExtents::value_type; @@ -371,6 +384,16 @@ namespace llama return static_cast(*this); } + LLAMA_FN_HOST_ACC_INLINE auto accessor() -> Accessor& + { + return static_cast(*this); + } + + LLAMA_FN_HOST_ACC_INLINE auto accessor() const -> const Accessor& + { + return static_cast(*this); + } + #if !(defined(_MSC_VER) && defined(__NVCC__)) template auto operator()(llama::ArrayIndex) const @@ -390,7 +413,7 @@ namespace llama else { LLAMA_FORCE_INLINE_RECURSIVE - return accessor(ai, RecordCoord<>{}); + return access(ai, RecordCoord<>{}); } } @@ -404,7 +427,7 @@ namespace llama else { LLAMA_FORCE_INLINE_RECURSIVE - return accessor(ai, RecordCoord<>{}); + return access(ai, RecordCoord<>{}); } } @@ -500,15 +523,15 @@ namespace llama friend struct RecordRef; template - LLAMA_FN_HOST_ACC_INLINE auto accessor(ArrayIndex ai, RecordCoord rc = {}) const -> decltype(auto) + LLAMA_FN_HOST_ACC_INLINE auto access(ArrayIndex ai, RecordCoord rc = {}) const -> decltype(auto) { - return mapToMemory(mapping(), ai, rc, storageBlobs); + return accessor()(mapToMemory(mapping(), ai, rc, storageBlobs)); } template - LLAMA_FN_HOST_ACC_INLINE auto accessor(ArrayIndex ai, RecordCoord rc = {}) -> decltype(auto) + LLAMA_FN_HOST_ACC_INLINE auto access(ArrayIndex ai, RecordCoord rc = {}) -> decltype(auto) { - return mapToMemory(mapping(), ai, rc, storageBlobs); + return accessor()(mapToMemory(mapping(), ai, rc, storageBlobs)); } }; @@ -551,6 +574,15 @@ namespace llama }); } + // Creates a new view from an existing view with the given accessor. + // \param view A view which's mapping and blobs are copied into a new view with the different accessor. If you no + // longer need the old view, consider moving it into the argument of this function. + template + LLAMA_FN_HOST_ACC_INLINE auto withAccessor(View view) + { + return View{std::move(view.mapping()), std::move(view.storageBlobs)}; + } + template inline constexpr auto isView = false; @@ -578,18 +610,6 @@ namespace llama { } - template - LLAMA_FN_HOST_ACC_INLINE auto accessor(ArrayIndex ai) const -> const auto& - { - return parentView.template accessor(ArrayIndex{ai + offset}); - } - - template - LLAMA_FN_HOST_ACC_INLINE auto accessor(ArrayIndex ai) -> auto& - { - return parentView.template accessor(ArrayIndex{ai + offset}); - } - /// Same as \ref View::operator()(ArrayIndex), but shifted by the offset of this \ref VirtualView. LLAMA_FN_HOST_ACC_INLINE auto operator()(ArrayIndex ai) const -> decltype(auto) { @@ -632,18 +652,16 @@ namespace llama ArrayIndex{ArrayIndex{static_cast(indices)...} + offset}); } - template - LLAMA_FN_HOST_ACC_INLINE auto operator()(RecordCoord = {}) const -> decltype(auto) + template + LLAMA_FN_HOST_ACC_INLINE auto operator()(RecordCoord rc = {}) const -> decltype(auto) { - LLAMA_FORCE_INLINE_RECURSIVE - return accessor(ArrayIndex{}); + return parentView(ArrayIndex{} + offset, rc); } - template - LLAMA_FN_HOST_ACC_INLINE auto operator()(RecordCoord = {}) -> decltype(auto) + template + LLAMA_FN_HOST_ACC_INLINE auto operator()(RecordCoord rc = {}) -> decltype(auto) { - LLAMA_FORCE_INLINE_RECURSIVE - return accessor(ArrayIndex{}); + return parentView(ArrayIndex{} + offset, rc); } StoredParentView parentView; diff --git a/tests/view.cpp b/tests/view.cpp index d468d5d106..56714adbc6 100644 --- a/tests/view.cpp +++ b/tests/view.cpp @@ -1,5 +1,6 @@ #include "common.hpp" +#include #include // clang-format off @@ -85,7 +86,7 @@ TEST_CASE("view.non-memory-owning") test(boost::mp11::mp_identity{}); } -TEST_CASE("view.access") +TEST_CASE("view.subscript") { using ArrayExtents = llama::ArrayExtentsDynamic; ArrayExtents extents{16, 16}; @@ -322,3 +323,54 @@ TEMPLATE_TEST_CASE("view.shallowCopy", "", llama::bloballoc::Vector, llama::blob auto copyOfCopy = llama::shallowCopy(copy); checkCopy(view, copyOfCopy); } + +TEMPLATE_TEST_CASE("view.withAccessor.DefaultAccessor", "", llama::bloballoc::Vector, llama::bloballoc::SharedPtr) +{ + auto view = llama::allocView(llama::mapping::AoS{llama::ArrayExtents{16, 16}, Particle{}}, TestType{}); + auto view2 = llama::withAccessor(llama::shallowCopy(view)); + iotaFillView(view2); + iotaCheckView(view); +} + +namespace +{ + struct AtomicAccessor + { + template + LLAMA_FN_HOST_ACC_INLINE auto operator()(Reference&& r) const + { + static_assert(std::is_lvalue_reference_v); + return std::atomic_ref{r}; + } + }; +} // namespace + +TEMPLATE_TEST_CASE("view.withAccessor.AtomicAccessor", "", llama::bloballoc::Vector, llama::bloballoc::SharedPtr) +{ + auto view = llama::allocView(llama::mapping::AoS{llama::ArrayExtents{16, 16}, Particle{}}, TestType{}); + auto view2 = llama::withAccessor(llama::shallowCopy(view)); + iotaFillView(view2); + iotaCheckView(view); +} + +namespace +{ + struct RestrictedAccessor + { + template + LLAMA_FN_HOST_ACC_INLINE auto operator()(Reference&& r) const -> __restrict Reference& + { + static_assert(std::is_lvalue_reference_v); + + return r; + } + }; +} // namespace + +TEMPLATE_TEST_CASE("view.withAccessor.RestrictedAccessor", "", llama::bloballoc::Vector, llama::bloballoc::SharedPtr) +{ + auto view = llama::allocView(llama::mapping::AoS{llama::ArrayExtents{16, 16}, Particle{}}, TestType{}); + auto view2 = llama::withAccessor(llama::shallowCopy(view)); + iotaFillView(view2); + iotaCheckView(view); +} \ No newline at end of file