From c6dded142976fca8d635564678e578e82b214441 Mon Sep 17 00:00:00 2001 From: AI agent Date: Mon, 6 Apr 2026 11:43:28 +0000 Subject: [PATCH 1/2] Add explicit-pitch makeView coverage --- test/unit/mem/constCorrectness.cpp | 74 ++++++++++++++++++++++++++++++ test/unit/mem/subDataStorage.cpp | 59 ++++++++++++++++++++++++ 2 files changed, 133 insertions(+) diff --git a/test/unit/mem/constCorrectness.cpp b/test/unit/mem/constCorrectness.cpp index 881838376..d1828eef3 100644 --- a/test/unit/mem/constCorrectness.cpp +++ b/test/unit/mem/constCorrectness.cpp @@ -703,6 +703,80 @@ TEST_CASE( } } +TEST_CASE( + "alpaka::makeView(api, pointer, extents, pitches, alignment) preserves explicit-pitch host metadata and inner " + "constness", + "[mem][view][correctness][makeView]") +{ + auto const extents = alpaka::Vec{2u, 3u, 4u}; + auto const explicitPitches = alpaka::Vec{80u, 20u, 4u}; + alignas(64) std::array mutableStorage{}; + alignas(64) std::array innerConstStorage{}; + + auto mutableSeedView + = alpaka::makeView(alpaka::api::host, mutableStorage.data(), extents, alpaka::Alignment<64>{}); + auto const& outerConstSeedView = mutableSeedView; + auto innerConstSeedView + = alpaka::makeView(alpaka::api::host, innerConstStorage.data(), extents, alpaka::Alignment<64>{}); + + auto mutableExplicitPitchView + = alpaka::makeView(mutableSeedView, mutableStorage.data(), extents, explicitPitches, alpaka::Alignment<64>{}); + auto const outerConstExplicitPitchView = alpaka::makeView( + outerConstSeedView, + mutableStorage.data(), + extents, + explicitPitches, + alpaka::Alignment<64>{}); + auto innerConstExplicitPitchView = alpaka::makeView( + innerConstSeedView, + innerConstStorage.data(), + extents, + explicitPitches, + alpaka::Alignment<64>{}); + + SECTION("compile-time explicit pitches stay part of the returned host view contract") + { + // The explicit-pitch overload should keep the host API, vector types, alignment, and mutability encoded by the + // caller instead of rebuilding a packed view. + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + + static_assert(std::same_as< + std::remove_cvref_t, + std::remove_cvref_t>); + static_assert(std::same_as< + std::remove_cvref_t, + std::remove_cvref_t>); + static_assert(std::same_as>); + static_assert(!std::is_const_v>); + static_assert( + !std::is_const_v>); + + static_assert(std::same_as< + std::remove_cvref_t, + std::remove_cvref_t>); + static_assert(std::same_as< + std::remove_cvref_t, + std::remove_cvref_t>); + static_assert(std::same_as>); + static_assert(std::is_const_v>); + static_assert( + std::is_const_v>); + + static_assert(std::same_as< + std::remove_cvref_t, + std::remove_cvref_t>); + static_assert(std::same_as< + std::remove_cvref_t, + std::remove_cvref_t>); + static_assert(std::same_as>); + static_assert(std::is_const_v>); + static_assert( + std::is_const_v>); + } +} + TEST_CASE("View::getMdSpan keeps host mutability boundaries", "[mem][view][mdspan][correctness]") { alignas(32) std::array storage{}; diff --git a/test/unit/mem/subDataStorage.cpp b/test/unit/mem/subDataStorage.cpp index 9bbc21e33..67df737e8 100644 --- a/test/unit/mem/subDataStorage.cpp +++ b/test/unit/mem/subDataStorage.cpp @@ -288,6 +288,65 @@ TEST_CASE( } } +TEST_CASE( + "alpaka::makeView(api, pointer, extents, pitches, alignment) keeps padded host pitches and subview aliasing", + "[mem][view][SubDataStorage]") +{ + auto const extents = alpaka::Vec{2u, 3u, 4u}; + auto const explicitPitches = alpaka::Vec{80u, 20u, 4u}; + auto const packedPitches = alpaka::calculatePitchesFromExtents(extents); + alignas(64) std::array storage{}; + storage.fill(-1); + + auto explicitPitchView + = alpaka::makeView(alpaka::api::host, storage.data(), extents, explicitPitches, alpaka::Alignment<64>{}); + + SECTION("explicit host pitches override the packed layout for indexing") + { + // The explicit-pitch overload must use the caller-provided padded layout instead of silently recomputing a + // packed one from the extents. + REQUIRE(explicitPitchView.getApi() == alpaka::api::host); + REQUIRE(explicitPitchView.getExtents() == extents); + REQUIRE(explicitPitchView.getPitches() == explicitPitches); + REQUIRE(explicitPitchView.data() == storage.data()); + REQUIRE(explicitPitches != packedPitches); + STATIC_REQUIRE(std::is_same_v>); + + storage[5] = -50; + storage[4] = -40; + REQUIRE(explicitPitchView[alpaka::Vec{0u, 1u, 0u}] == -50); + + storage[20] = 220; + storage[12] = 120; + REQUIRE(explicitPitchView[alpaka::Vec{1u, 0u, 0u}] == 220); + + auto const sampleIdx = alpaka::Vec{1u, 2u, 3u}; + explicitPitchView[sampleIdx] = 1323; + REQUIRE(storage[33] == 1323); + REQUIRE(storage[23] == -1); + REQUIRE(&explicitPitchView[sampleIdx] == &storage[33]); + } + + SECTION("offset subviews keep the padded pitch contract") + { + // Follow-on subviews should keep the same padded pitches after shifting the origin into the caller-defined + // layout. + auto const offset = alpaka::Vec{1u, 1u, 1u}; + auto const subExtents = alpaka::Vec{1u, 2u, 3u}; + auto subView = explicitPitchView.getSubView(offset, subExtents); + + REQUIRE(subView.getExtents() == subExtents); + REQUIRE(subView.getPitches() == explicitPitchView.getPitches()); + REQUIRE(subView.data() == &explicitPitchView[offset]); + STATIC_REQUIRE(std::is_same_v>); + + subView[alpaka::Vec{0u, 1u, 2u}] = 777; + REQUIRE(explicitPitchView[offset + alpaka::Vec{0u, 1u, 2u}] == 777); + REQUIRE(storage[33] == 777); + REQUIRE(storage[23] == -1); + } +} + TEST_CASE( "alpaka::View::getSubView(BoundaryDirection) covers host lower upper core and const aliasing", "[mem][view][SubDataStorage]") From 4c176c505a89905b345c8b1f33b0649c05b252aa Mon Sep 17 00:00:00 2001 From: AI agent Date: Wed, 8 Apr 2026 18:16:16 +0000 Subject: [PATCH 2/2] Add packed makeView coverage --- test/unit/mem/constCorrectness.cpp | 58 ++++++++++++++++++++++++++++++ test/unit/mem/mdIterator.cpp | 39 ++++++++++++++++++++ 2 files changed, 97 insertions(+) diff --git a/test/unit/mem/constCorrectness.cpp b/test/unit/mem/constCorrectness.cpp index d1828eef3..c5a02587b 100644 --- a/test/unit/mem/constCorrectness.cpp +++ b/test/unit/mem/constCorrectness.cpp @@ -777,6 +777,64 @@ TEST_CASE( } } +TEST_CASE( + "alpaka::makeView(api, pointer, extents, alignment) preserves packed host metadata and inner constness", + "[mem][view][correctness][makeView]") +{ + auto const extents = alpaka::Vec{2u, 3u, 4u}; + auto const packedPitches = alpaka::calculatePitchesFromExtents(extents); + alignas(64) std::array mutableStorage{}; + alignas(64) std::array innerConstStorage{}; + + auto mutablePackedView + = alpaka::makeView(alpaka::api::host, mutableStorage.data(), extents, alpaka::Alignment<64>{}); + auto const outerConstPackedView + = alpaka::makeView(alpaka::api::host, mutableStorage.data(), extents, alpaka::Alignment<64>{}); + auto innerConstPackedView + = alpaka::makeView(alpaka::api::host, innerConstStorage.data(), extents, alpaka::Alignment<64>{}); + + SECTION("compile-time packed pitches stay part of the returned host view contract") + { + // The packed overload should derive the host pitch type from the extents while preserving alignment and + // pointed-to constness. + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + + static_assert(std::same_as< + std::remove_cvref_t, + std::remove_cvref_t>); + static_assert(std::same_as< + std::remove_cvref_t, + std::remove_cvref_t>); + static_assert(std::same_as>); + static_assert(!std::is_const_v>); + static_assert(!std::is_const_v>); + + static_assert(std::same_as< + std::remove_cvref_t, + std::remove_cvref_t>); + static_assert(std::same_as< + std::remove_cvref_t, + std::remove_cvref_t>); + static_assert(std::same_as>); + static_assert(std::is_const_v>); + static_assert( + std::is_const_v>); + + static_assert(std::same_as< + std::remove_cvref_t, + std::remove_cvref_t>); + static_assert(std::same_as< + std::remove_cvref_t, + std::remove_cvref_t>); + static_assert(std::same_as>); + static_assert(std::is_const_v>); + static_assert( + std::is_const_v>); + } +} + TEST_CASE("View::getMdSpan keeps host mutability boundaries", "[mem][view][mdspan][correctness]") { alignas(32) std::array storage{}; diff --git a/test/unit/mem/mdIterator.cpp b/test/unit/mem/mdIterator.cpp index 78ac2564f..1b7864b43 100644 --- a/test/unit/mem/mdIterator.cpp +++ b/test/unit/mem/mdIterator.cpp @@ -136,6 +136,45 @@ TEST_CASE("mdIterator host coverage", "[mem][mdIterator][iterator]") REQUIRE(collectValues(constMdSpan) == visited); } + SECTION("packed makeView derives packed pitches and getMdSpan keeps that layout") + { + // The packed raw-pointer overload must derive pitches from extents instead of accepting a padded layout, and + // the immediate MdSpan view should expose the same packed contract. + auto const extents = alpaka::Vec{2u, 3u, 4u}; + auto const packedPitches = alpaka::calculatePitchesFromExtents(extents); + auto const explicitPitches = alpaka::Vec{80u, 20u, 4u}; + alignas(64) std::array storage{}; + for(std::size_t i = 0; i < storage.size(); ++i) + storage[i] = static_cast(i); + + auto packedView = alpaka::makeView(api::host, storage.data(), extents, alpaka::Alignment<64>{}); + auto mdSpan = packedView.getMdSpan(); + + REQUIRE(packedView.getApi() == api::host); + REQUIRE(packedView.getExtents() == extents); + REQUIRE(packedView.getPitches() == packedPitches); + REQUIRE(packedView.getPitches() != explicitPitches); + REQUIRE(packedView.data() == storage.data()); + STATIC_REQUIRE(std::is_same_v>); + + storage[15] = 1500; + storage[23] = 2300; + auto const sampleIdx = alpaka::Vec{1u, 0u, 3u}; + REQUIRE(packedView[sampleIdx] == 1500); + REQUIRE(&packedView[sampleIdx] == &storage[15]); + + REQUIRE(mdSpan.getExtents() == packedView.getExtents()); + REQUIRE(mdSpan.getPitches() == packedView.getPitches()); + REQUIRE(mdSpan.data() == packedView.data()); + STATIC_REQUIRE(std::is_same_v>); + + mdSpan[sampleIdx] = 777; + REQUIRE(packedView[sampleIdx] == 777); + REQUIRE(storage[15] == 777); + REQUIRE(storage[23] == 2300); + REQUIRE(&mdSpan[sampleIdx] == &packedView[sampleIdx]); + } + SECTION("pre-increment and post-increment advance one element at a time") { // Forward-iterator increments need to preserve the old value for post-increment and return self for