Skip to content

Commit ef0adc1

Browse files
authored
Use canonicalize slices in submdspan (#457)
Signed-off-by: Christian Trott <crtrott@sandia.gov>
1 parent 884f17a commit ef0adc1

6 files changed

Lines changed: 48 additions & 107 deletions

File tree

include/experimental/__p0009_bits/config.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,13 @@
4545
#else
4646
#define MDSPAN_CXX_STD_23 202100L
4747
#endif
48+
#define MDSPAN_CXX_STD_26 202603L
4849

4950
#define MDSPAN_HAS_CXX_14 (MDSPAN_IMPL_CPLUSPLUS >= MDSPAN_CXX_STD_14)
5051
#define MDSPAN_HAS_CXX_17 (MDSPAN_IMPL_CPLUSPLUS >= MDSPAN_CXX_STD_17)
5152
#define MDSPAN_HAS_CXX_20 (MDSPAN_IMPL_CPLUSPLUS >= MDSPAN_CXX_STD_20)
5253
#define MDSPAN_HAS_CXX_23 (MDSPAN_IMPL_CPLUSPLUS >= MDSPAN_CXX_STD_23)
54+
#define MDSPAN_HAS_CXX_26 (MDSPAN_IMPL_CPLUSPLUS >= MDSPAN_CXX_STD_26)
5355

5456
static_assert(MDSPAN_IMPL_CPLUSPLUS >= MDSPAN_CXX_STD_14, "mdspan requires C++14 or later.");
5557

include/experimental/__p2630_bits/submdspan.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@ MDSPAN_INLINE_FUNCTION
2727
constexpr auto
2828
submdspan(const mdspan<ElementType, Extents, LayoutPolicy, AccessorPolicy> &src,
2929
SliceSpecifiers... slices) {
30-
const auto sub_submdspan_mapping_result = submdspan_mapping(src.mapping(), slices...);
30+
detail::check_submdspan_slice_mandates<Extents>(std::make_index_sequence<Extents::rank()>(), slices...);
31+
32+
const auto sub_submdspan_mapping_result = submdspan_mapping(src.mapping(),
33+
detail::canonical_slice<typename Extents::index_type>(slices)...);
3134
// NVCC has a problem with the deduction so lets figure out the type
3235
using sub_mapping_t = std::remove_cv_t<decltype(sub_submdspan_mapping_result.mapping)>;
3336
using sub_extents_t = typename sub_mapping_t::extents_type;

include/experimental/__p2630_bits/submdspan_canonicalize_slices.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,15 @@ constexpr bool check_submdspan_slice_mandate(
274274
return true;
275275
}
276276

277+
template<class Extents, size_t ... Idx, class ... Slices>
278+
MDSPAN_INLINE_FUNCTION
279+
constexpr bool check_submdspan_slice_mandates(
280+
const std::index_sequence<Idx...>& ,
281+
[[maybe_unused]] const Slices& ... slices)
282+
{
283+
return (check_submdspan_slice_mandate<typename Extents::index_type, Extents::static_extent(Idx), Slices>(slices) && ... && true);
284+
}
285+
277286
// ============================================================
278287
// canonical_slice: canonicalize a single slice
279288
//

include/experimental/__p2630_bits/submdspan_extents.hpp

Lines changed: 3 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -55,37 +55,6 @@ template <class OffsetType, class ExtentType, class StrideType>
5555
struct is_strided_slice<
5656
strided_slice<OffsetType, ExtentType, StrideType>> : std::true_type {};
5757

58-
// Helper for identifying valid pair like things
59-
template <class T, class IndexType> struct index_pair_like : std::false_type {};
60-
61-
template <class IdxT1, class IdxT2, class IndexType>
62-
struct index_pair_like<std::pair<IdxT1, IdxT2>, IndexType> {
63-
static constexpr bool value = std::is_convertible_v<IdxT1, IndexType> &&
64-
std::is_convertible_v<IdxT2, IndexType>;
65-
};
66-
67-
template <class IdxT1, class IdxT2, class IndexType>
68-
struct index_pair_like<std::tuple<IdxT1, IdxT2>, IndexType> {
69-
static constexpr bool value = std::is_convertible_v<IdxT1, IndexType> &&
70-
std::is_convertible_v<IdxT2, IndexType>;
71-
};
72-
73-
template <class IdxT1, class IdxT2, class IndexType>
74-
struct index_pair_like<tuple<IdxT1, IdxT2>, IndexType> {
75-
static constexpr bool value = std::is_convertible_v<IdxT1, IndexType> &&
76-
std::is_convertible_v<IdxT2, IndexType>;
77-
};
78-
79-
template <class IdxT, class IndexType>
80-
struct index_pair_like<std::complex<IdxT>, IndexType> {
81-
static constexpr bool value = std::is_convertible_v<IdxT, IndexType>;
82-
};
83-
84-
template <class IdxT, class IndexType>
85-
struct index_pair_like<std::array<IdxT, 2>, IndexType> {
86-
static constexpr bool value = std::is_convertible_v<IdxT, IndexType>;
87-
};
88-
8958
// first_of(slice): getting begin of slice specifier range
9059
MDSPAN_TEMPLATE_REQUIRES(
9160
class Integral,
@@ -98,8 +67,8 @@ constexpr Integral first_of(const Integral &i) {
9867

9968
template<class Integral, Integral v>
10069
MDSPAN_INLINE_FUNCTION
101-
constexpr Integral first_of(const std::integral_constant<Integral, v>&) {
102-
return integral_constant<Integral, v>();
70+
constexpr auto first_of(const constant_wrapper<v, Integral>&) {
71+
return constant_wrapper<v, Integral>();
10372
}
10473

10574
MDSPAN_INLINE_FUNCTION
@@ -108,38 +77,6 @@ first_of(const ::MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent_t &) {
10877
return integral_constant<size_t, 0>();
10978
}
11079

111-
MDSPAN_TEMPLATE_REQUIRES(
112-
class Slice,
113-
/* requires */(index_pair_like<Slice, size_t>::value)
114-
)
115-
MDSPAN_INLINE_FUNCTION
116-
constexpr auto first_of(const Slice &i) {
117-
return get<0>(i);
118-
}
119-
120-
MDSPAN_TEMPLATE_REQUIRES(
121-
class IdxT1, class IdxT2,
122-
/* requires */ (index_pair_like<std::tuple<IdxT1, IdxT2>, size_t>::value)
123-
)
124-
constexpr auto first_of(const std::tuple<IdxT1, IdxT2>& i) {
125-
return get<0>(i);
126-
}
127-
128-
MDSPAN_TEMPLATE_REQUIRES(
129-
class IdxT1, class IdxT2,
130-
/* requires */ (index_pair_like<std::pair<IdxT1, IdxT2>, size_t>::value)
131-
)
132-
MDSPAN_INLINE_FUNCTION
133-
constexpr auto first_of(const std::pair<IdxT1, IdxT2>& i) {
134-
return i.first;
135-
}
136-
137-
template<class T>
138-
MDSPAN_INLINE_FUNCTION
139-
constexpr auto first_of(const std::complex<T> &i) {
140-
return i.real();
141-
}
142-
14380
template <class OffsetType, class ExtentType, class StrideType>
14481
MDSPAN_INLINE_FUNCTION
14582
constexpr OffsetType
@@ -161,39 +98,6 @@ constexpr Integral
16198
return i;
16299
}
163100

164-
MDSPAN_TEMPLATE_REQUIRES(
165-
size_t k, class Extents, class Slice,
166-
/* requires */(index_pair_like<Slice, size_t>::value)
167-
)
168-
MDSPAN_INLINE_FUNCTION
169-
constexpr auto last_of(std::integral_constant<size_t, k>, const Extents &,
170-
const Slice &i) {
171-
return get<1>(i);
172-
}
173-
174-
MDSPAN_TEMPLATE_REQUIRES(
175-
size_t k, class Extents, class IdxT1, class IdxT2,
176-
/* requires */ (index_pair_like<std::tuple<IdxT1, IdxT2>, size_t>::value)
177-
)
178-
constexpr auto last_of(std::integral_constant<size_t, k>, const Extents &, const std::tuple<IdxT1, IdxT2>& i) {
179-
return get<1>(i);
180-
}
181-
182-
MDSPAN_TEMPLATE_REQUIRES(
183-
size_t k, class Extents, class IdxT1, class IdxT2,
184-
/* requires */ (index_pair_like<std::pair<IdxT1, IdxT2>, size_t>::value)
185-
)
186-
MDSPAN_INLINE_FUNCTION
187-
constexpr auto last_of(std::integral_constant<size_t, k>, const Extents &, const std::pair<IdxT1, IdxT2>& i) {
188-
return i.second;
189-
}
190-
191-
template<size_t k, class Extents, class T>
192-
MDSPAN_INLINE_FUNCTION
193-
constexpr auto last_of(std::integral_constant<size_t, k>, const Extents &, const std::complex<T> &i) {
194-
return i.imag();
195-
}
196-
197101
// Suppress spurious warning with NVCC about no return statement.
198102
// This is a known issue in NVCC and NVC++
199103
// Depending on the CUDA and GCC version we need both the builtin
@@ -220,7 +124,7 @@ constexpr auto last_of(std::integral_constant<size_t, k>, const Extents &ext,
220124
if constexpr (Extents::static_extent(k) == dynamic_extent) {
221125
return ext.extent(k);
222126
} else {
223-
return integral_constant<size_t, Extents::static_extent(k)>();
127+
return constant_wrapper<Extents::static_extent(k), size_t>();
224128
}
225129
#if defined(__NVCC__) && !defined(__CUDA_ARCH__) && defined(__GNUC__)
226130
// Even with CUDA_ARCH protection this thing warns about calling host function

include/experimental/__p2630_bits/submdspan_mapping.hpp

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -102,14 +102,19 @@ MDSPAN_INLINE_FUNCTION constexpr auto construct_sub_strides(
102102
}
103103

104104
template<class SliceSpecifier, class IndexType>
105-
struct is_range_slice {
106-
constexpr static bool value =
107-
std::is_same_v<SliceSpecifier, full_extent_t> ||
108-
index_pair_like<SliceSpecifier, IndexType>::value;
109-
};
105+
constexpr bool is_range_slice_v = false;
110106

111-
template<class SliceSpecifier, class IndexType>
112-
constexpr bool is_range_slice_v = is_range_slice<SliceSpecifier, IndexType>::value;
107+
template<class IndexType>
108+
constexpr bool is_range_slice_v<full_extent_t, IndexType> = true;
109+
110+
template<class OffsetType, class ExtentType, auto Stride, class IndexType>
111+
constexpr bool is_range_slice_v<
112+
strided_slice<
113+
OffsetType,
114+
ExtentType,
115+
constant_wrapper<Stride>>,
116+
IndexType
117+
> = (constant_wrapper<Stride>::value == IndexType(1));
113118

114119
template<class SliceSpecifier, class IndexType>
115120
struct is_index_slice {
@@ -209,6 +214,9 @@ MDSPAN_INLINE_FUNCTION constexpr auto
209214
layout_left::mapping<Extents>::submdspan_mapping_impl(
210215
SliceSpecifiers... slices) const {
211216

217+
// Implements mandate check
218+
detail::check_submdspan_slice_mandates<Extents>(std::make_index_sequence<Extents::rank()>(), slices...);
219+
212220
// compute sub extents
213221
using src_ext_t = Extents;
214222
auto dst_ext = submdspan_extents(extents(), slices...);
@@ -272,6 +280,9 @@ MDSPAN_INLINE_FUNCTION constexpr auto
272280
layout_left_padded<PaddingValue>::mapping<Extents>::submdspan_mapping_impl(
273281
SliceSpecifiers... slices) const {
274282

283+
// Implements mandate check
284+
detail::check_submdspan_slice_mandates<Extents>(std::make_index_sequence<Extents::rank()>(), slices...);
285+
275286
// compute sub extents
276287
using src_ext_t = Extents;
277288
auto dst_ext = submdspan_extents(extents(), slices...);
@@ -437,6 +448,9 @@ MDSPAN_INLINE_FUNCTION constexpr auto
437448
layout_right::mapping<Extents>::submdspan_mapping_impl(
438449
SliceSpecifiers... slices) const {
439450

451+
// Implements mandate check
452+
detail::check_submdspan_slice_mandates<Extents>(std::make_index_sequence<Extents::rank()>(), slices...);
453+
440454
// compute sub extents
441455
using src_ext_t = Extents;
442456
auto dst_ext = submdspan_extents(extents(), slices...);
@@ -502,6 +516,9 @@ MDSPAN_INLINE_FUNCTION constexpr auto
502516
layout_right_padded<PaddingValue>::mapping<Extents>::submdspan_mapping_impl(
503517
SliceSpecifiers... slices) const {
504518

519+
// Implements mandate check
520+
detail::check_submdspan_slice_mandates<Extents>(std::make_index_sequence<Extents::rank()>(), slices...);
521+
505522
// compute sub extents
506523
using src_ext_t = Extents;
507524
auto dst_ext = submdspan_extents(extents(), slices...);
@@ -577,6 +594,10 @@ template <class... SliceSpecifiers>
577594
MDSPAN_INLINE_FUNCTION constexpr auto
578595
layout_stride::mapping<Extents>::submdspan_mapping_impl(
579596
SliceSpecifiers... slices) const {
597+
598+
// Implements mandate check
599+
detail::check_submdspan_slice_mandates<Extents>(std::make_index_sequence<Extents::rank()>(), slices...);
600+
580601
auto dst_ext = submdspan_extents(extents(), slices...);
581602
using dst_ext_t = decltype(dst_ext);
582603
auto inv_map = detail::inv_map_rank(std::integral_constant<size_t, 0>(),

tests/test_submdspan.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,9 @@ using submdspan_test_types =
141141
// layout_right to layout_right Check Extents Preservation
142142
, std::tuple<Kokkos::layout_right, Kokkos::layout_right, Kokkos::extents<size_t,10>, args_t<10>, Kokkos::extents<size_t,10>, Kokkos::full_extent_t>
143143
, std::tuple<Kokkos::layout_right, Kokkos::layout_right, Kokkos::extents<size_t,10>, args_t<10>, Kokkos::extents<size_t,dyn>, std::pair<int,int>>
144+
#if defined(__cpp_lib_tuple_like) && (__cpp_lib_tuple_like >= 202311L) // submdspan uses structured binding for slices, which requires C++26 for complex
144145
, std::tuple<Kokkos::layout_right, Kokkos::layout_right, Kokkos::extents<size_t,10>, args_t<10>, Kokkos::extents<size_t,dyn>, std::complex<double>>
146+
#endif
145147
, std::tuple<Kokkos::layout_right, Kokkos::layout_right, Kokkos::extents<size_t,10>, args_t<10>, Kokkos::extents<size_t>, int>
146148
, std::tuple<Kokkos::layout_right, Kokkos::layout_right, Kokkos::extents<size_t,10,20>, args_t<10,20>, Kokkos::extents<size_t,10,20>, Kokkos::full_extent_t, Kokkos::full_extent_t>
147149
, std::tuple<Kokkos::layout_right, Kokkos::layout_right, Kokkos::extents<size_t,10,20>, args_t<10,20>, Kokkos::extents<size_t,dyn,20>, std::pair<int,int>, Kokkos::full_extent_t>

0 commit comments

Comments
 (0)