Extract submdspan_canonicalize_slices as standalone function (from PR #408)#451
Extract submdspan_canonicalize_slices as standalone function (from PR #408)#451Copilot wants to merge 7 commits into
submdspan_canonicalize_slices as standalone function (from PR #408)#451Conversation
Co-authored-by: crtrott <9490481+crtrott@users.noreply.github.com>
submdspan_canonicalize_slices as standalone function (from PR #408)
| template<size_t k, class Slice, class IndexType, size_t... Extents> | ||
| MDSPAN_INLINE_FUNCTION | ||
| constexpr auto submdspan_canonicalize_one_slice( | ||
| [[maybe_unused]] const extents<IndexType, Extents...>& exts, | ||
| [[maybe_unused]] Slice s) | ||
| { |
There was a problem hiding this comment.
Neither exts, nor Extents, nor k is actually used in this function. Can we not simply template it on IndexType and Slice, and only have that single Slice argument passed in?
There was a problem hiding this comment.
Done in 68134d1. Simplified to template<class IndexType, class Slice> with a single Slice s argument — the unused k, Extents, and exts are all removed.
| const extents<IndexType, Extents...>& exts, | ||
| Slices... slices) | ||
| { | ||
| (check_submdspan_slice_mandate<Inds>(exts, get_kth_in_pack<Inds>(slices...)), ...); |
There was a problem hiding this comment.
Doesn't this work?
| (check_submdspan_slice_mandate<Inds>(exts, get_kth_in_pack<Inds>(slices...)), ...); | |
| (check_submdspan_slice_mandate<Inds>(exts, slices), ...); |
There was a problem hiding this comment.
Done in 68134d1. Updated to (check_submdspan_slice_mandate<Inds>(exts, slices), ...);
crtrott
left a comment
There was a problem hiding this comment.
Couple things there I think we could do it differently, which I think would eliminate the need for the pack extraction function.
…_in_pack Co-authored-by: crtrott <9490481+crtrott@users.noreply.github.com>
nmm0
left a comment
There was a problem hiding this comment.
A bunch of comments, I think it mostly looks good but I wanna do another pass after some discussion/changes
| { | ||
| // Mandate checks (static_asserts only, no computation). | ||
| // Separated from canonicalization for clarity. | ||
| check_submdspan_slice_mandates( |
There was a problem hiding this comment.
I assume this was an ai-generated change -- I'm not sure it's clearer, and it may have some impact on compile time as you have to generate additional templates just for checking.
Since you are already processing one slice at a time I prefer the way it used to be with the mandate checking done on the slice
| return cw<static_cast<IndexType>(index_cast<IndexType>(S::value))>; | ||
| } | ||
| else { | ||
| return static_cast<IndexType>(index_cast<IndexType>(s)); |
There was a problem hiding this comment.
Another slight difference with the standard, should this be std::move(s)? I'm not 100% what the purpose of that is unless there is an index type that is movable...
| #endif | ||
| else { | ||
| // General pair-like case: structured binding into [first, last) | ||
| auto [s_k0, s_k1] = s; |
There was a problem hiding this comment.
Another std::move(s) from the standard
There was a problem hiding this comment.
Per https://eel.is/c++draft/mdspan.sub#helpers-12
| auto [s_k0, s_k1] = s; | |
| auto [s_k0, s_k1] = std::move(s); |
| constexpr check_static_bounds_result check_static_bounds( | ||
| const extents<IndexType, Exts...>&) | ||
| { | ||
| #if defined(__cpp_pack_indexing) |
There was a problem hiding this comment.
TBH I would rather just define this using index sequence while obvious pack indexing is much preferable it's C++26 so in most cases we will have to look at the alternate code.
This is especially true since we are using an index sequence to generate this anyway, so imo lets just pass down the indices
| } | ||
| else if constexpr (std::is_convertible_v<S_k, IndexType>) { | ||
| if constexpr (is_integral_constant_like_v<S_k>) { | ||
| if constexpr (de_ice(S_k{}) < 0) { |
There was a problem hiding this comment.
Is this needed? I thought you could compare integral constants to integers
There was a problem hiding this comment.
I think you still need it. there were weird scenarios.
There was a problem hiding this comment.
Ok I will take your word for it :P
There was a problem hiding this comment.
integral-constant-like does require convertibility to integers, but it's not clear to me that the compiler will always be able to figure out that it needs to convert the value to int.
Signed-off-by: Christian Trott <crtrott@sandia.gov>
Signed-off-by: Christian Trott <crtrott@sandia.gov>
7601c60 to
38a26c7
Compare
Signed-off-by: Christian Trott <crtrott@sandia.gov>
38a26c7 to
3643cca
Compare
nmm0
left a comment
There was a problem hiding this comment.
Last couple of comments I think things are mostly good just one or two minor issues
| } | ||
| else if constexpr (std::is_convertible_v<S_k, IndexType>) { | ||
| if constexpr (is_integral_constant_like_v<S_k>) { | ||
| if constexpr (de_ice(S_k{}) < 0) { |
There was a problem hiding this comment.
Ok I will take your word for it :P
| #endif | ||
| else { | ||
| // General pair-like case: structured binding into [first, last) | ||
| auto [s_k0, s_k1] = s; |
There was a problem hiding this comment.
Per https://eel.is/c++draft/mdspan.sub#helpers-12
| auto [s_k0, s_k1] = s; | |
| auto [s_k0, s_k1] = std::move(s); |
| { | ||
| // Mandate checks (static_asserts only, no computation). | ||
| // Separated from canonicalization for clarity. | ||
| (void)(check_submdspan_slice_mandate<typename Extents::index_type, Extents::static_extent(Inds)>(slices) && ... && true); |
There was a problem hiding this comment.
Why make check_submdspan_slice_mandate return bool if its result is not used?
There was a problem hiding this comment.
because I need some statically expandable fold expression which doesn't warn about ignored expression.
I.e. , operator warns about "left thing is getting ignored" and thus I decided to go with a && expansion.
There was a problem hiding this comment.
@nmm0 It's a good thought! We could just make check_submdspan_slice_mandate return bool without a static_assert, and static_assert on the whole fold expression. The idea here is to make it easier to figure out which extent static_asserted.
Signed-off-by: Christian Trott <crtrott@sandia.gov>
mhoemmen
left a comment
There was a problem hiding this comment.
Thanks Christian! : - ) I posted some suggestions in the comments.
| using extent_t = std::integral_constant<int, 4>; | ||
| using stride_t = std::integral_constant<int, 2>; | ||
| const auto slice0 = | ||
| MDSPAN_IMPL_STANDARD_NAMESPACE::strided_slice<offset_t, extent_t, stride_t>{}; |
There was a problem hiding this comment.
This is called extent_slice now. (I imagine the plan is to change that later, though. I'm just remarking on it to remind myself.)
| test_canonicalize_slices(tuple{}, MDSPAN_IMPL_STANDARD_NAMESPACE::extents<size_t>{}); | ||
| } | ||
|
|
||
| TEST(CanonicalizeSlices, Rank1_full) { |
There was a problem hiding this comment.
Should we consider adding a test for a slice type that's convertible to full_extent_t, but not the same as full_extent_t?
| } // namespace detail | ||
|
|
||
| // ============================================================ | ||
| // submdspan_canonicalize_slices: public API |
There was a problem hiding this comment.
| // submdspan_canonicalize_slices: public API | |
| // canonical_slices: public API |
| { | ||
| // Mandate checks (static_asserts only, no computation). | ||
| // Separated from canonicalization for clarity. | ||
| (void)(check_submdspan_slice_mandate<typename Extents::index_type, Extents::static_extent(Inds)>(slices) && ... && true); |
There was a problem hiding this comment.
@nmm0 It's a good thought! We could just make check_submdspan_slice_mandate return bool without a static_assert, and static_assert on the whole fold expression. The idea here is to make it easier to figure out which extent static_asserted.
| // TODO: Later introduce canonical-range-slice | ||
| return strided_slice<decltype(offset), decltype(extent), decltype(stride)>{ |
There was a problem hiding this comment.
| // TODO: Later introduce canonical-range-slice | |
| return strided_slice<decltype(offset), decltype(extent), decltype(stride)>{ | |
| // TODO: Rename to extent_slice | |
| return strided_slice<decltype(offset), decltype(extent), decltype(stride)>{ |
| // TODO: Later introduce canonical-range-slice | ||
| return strided_slice<decltype(offset), decltype(extent), decltype(stride)>{ |
There was a problem hiding this comment.
| // TODO: Later introduce canonical-range-slice | |
| return strided_slice<decltype(offset), decltype(extent), decltype(stride)>{ | |
| // TODO: Rename to extent_slice | |
| return strided_slice<decltype(offset), decltype(extent), decltype(stride)>{ |
| } | ||
| else if constexpr (std::is_convertible_v<S_k, IndexType>) { | ||
| if constexpr (is_integral_constant_like_v<S_k>) { | ||
| if constexpr (de_ice(S_k{}) < 0) { |
There was a problem hiding this comment.
integral-constant-like does require convertibility to integers, but it's not clear to me that the compiler will always be able to figure out that it needs to convert the value to int.
| MDSPAN_INLINE_FUNCTION | ||
| constexpr auto subtract_ice([[maybe_unused]] X x, [[maybe_unused]] Y y) { | ||
| if constexpr ( | ||
| is_integral_constant_like_v<remove_cvref_t<X>> && |
There was a problem hiding this comment.
Have we fixed the definition of this to match the Standard concept? Before, it would only be true for std::integral_constant and Kokkos::integral_constant specializations.
submdspan_canonicalize_slicesimplementationinclude/experimental/__p2630_bits/submdspan_canonicalize_slices.hpptests/test_canonicalize_slices.cppwith 10 teststests/CMakeLists.txtandsubmdspan.hppsubmdspan_canonicalize_one_slice: simplified totemplate<class IndexType, class Slice>— removed unusedk,Extents, andextsparameterscheck_submdspan_slice_mandates: use direct parallel pack expansion(check_submdspan_slice_mandate<Inds>(exts, slices), ...)instead ofget_kth_in_packsubmdspan_canonicalize_slices_impltuple return: usesubmdspan_canonicalize_one_slice<IndexType>(slices)...instead ofget_kth_in_packget_kth_in_packhelper (no longer needed)✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.