Skip to content

Commit 3643cca

Browse files
committed
More cleanup
Signed-off-by: Christian Trott <crtrott@sandia.gov>
1 parent b46f00f commit 3643cca

1 file changed

Lines changed: 42 additions & 111 deletions

File tree

include/experimental/__p2630_bits/submdspan_canonicalize_slices.hpp

Lines changed: 42 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ MDSPAN_TEMPLATE_REQUIRES(
7474
)
7575
MDSPAN_INLINE_FUNCTION
7676
constexpr auto index_cast(OtherIndexType&& i) noexcept {
77-
return static_cast<IndexType>(i);
77+
return static_cast<IndexType>(std::forward<OtherIndexType>(i));
7878
}
7979

8080
// ============================================================
@@ -91,6 +91,8 @@ MDSPAN_INLINE_FUNCTION
9191
constexpr auto canonical_index([[maybe_unused]] S s) {
9292
// TODO: might move to public semi/public only to get error earlier, and
9393
// don't duplicate check
94+
// TODO: add mandate for integral-constant-like representable as IndexType
95+
// TODO: add precondition check that index-cast is representable as IndexType
9496
static_assert(std::is_signed_v<IndexType> || std::is_unsigned_v<IndexType>);
9597
if constexpr (is_integral_constant_like_v<S>) {
9698
return cw<static_cast<IndexType>(index_cast<IndexType>(S::value))>;
@@ -119,108 +121,61 @@ constexpr auto subtract_ice([[maybe_unused]] X x, [[maybe_unused]] Y y) {
119121
}
120122
}
121123

122-
// ============================================================
123-
// check_static_bounds_result: result of a compile-time bounds check
124-
// ============================================================
125-
126-
enum class check_static_bounds_result {
127-
in_bounds,
128-
out_of_bounds,
129-
unknown
130-
};
131-
132-
// ============================================================
133-
// is_std_complex: detect std::complex (for pre-tuple-like compilers)
134-
// ============================================================
135-
136-
// Clang 21.0.0 does not define __cpp_lib_tuple_like, so it does not
137-
// support the tuple protocol for std::complex. Interestingly, it permits
138-
// structured binding, but decomposes it into one element, not two.
139-
// We work around with a special canonicalization case.
140-
#if ! defined(__cpp_lib_tuple_like) || (__cpp_lib_tuple_like < 202311L)
141-
template<class T>
142-
constexpr bool is_std_complex = false;
143-
template<class T>
144-
constexpr bool is_std_complex<std::complex<T>> = true;
145-
#endif
146-
147124
// ============================================================
148125
// check_static_bounds: compile-time bounds check for a slice
149126
//
150-
// Returns whether the k-th slice is statically in bounds,
151-
// out of bounds, or unknown (dynamic bounds or dynamic slice values).
127+
// Returns false if the slice is statically out of bounds.
152128
//
153129
// This function is called only in static_assert contexts.
154130
// ============================================================
155131

156-
template<size_t k, class S_k, class IndexType, size_t... Exts>
157-
constexpr check_static_bounds_result check_static_bounds(
158-
const extents<IndexType, Exts...>&)
132+
template<class IndexType, size_t Exts_k, class S_k>
133+
constexpr bool check_static_bounds()
159134
{
160-
#if defined(__cpp_pack_indexing)
161-
constexpr size_t Exts_k = Exts...[k];
162-
#else
163-
constexpr size_t Exts_k = [] () {
164-
size_t result = 0;
165-
size_t i = 0;
166-
(void) ((i++ == k ? (result = Exts, true) : false) || ...);
167-
return result;
168-
} ();
169-
#endif
170-
171135
if constexpr (std::is_convertible_v<S_k, full_extent_t>) {
172-
return check_static_bounds_result::in_bounds;
136+
return true;
173137
}
174138
else if constexpr (std::is_convertible_v<S_k, IndexType>) {
175139
if constexpr (is_integral_constant_like_v<S_k>) {
176140
if constexpr (de_ice(S_k{}) < 0) {
177-
return check_static_bounds_result::out_of_bounds;
141+
return false;
178142
}
179143
else if constexpr (
180144
Exts_k != dynamic_extent &&
181145
Exts_k <= static_cast<size_t>(de_ice(S_k{})))
182146
{
183-
return check_static_bounds_result::out_of_bounds;
184-
}
185-
else if constexpr (
186-
Exts_k != dynamic_extent &&
187-
static_cast<size_t>(de_ice(S_k{})) < Exts_k)
188-
{
189-
return check_static_bounds_result::in_bounds;
190-
}
191-
else {
192-
return check_static_bounds_result::unknown;
147+
return false;
193148
}
194-
}
195-
else {
196-
return check_static_bounds_result::unknown;
149+
else { return true; }
150+
} else {
151+
return true;
197152
}
198153
}
199154
else if constexpr (is_strided_slice<S_k>::value) {
200155
using offset_type = typename S_k::offset_type;
201156

202157
if constexpr (is_integral_constant_like_v<offset_type>) {
203158
if constexpr (de_ice(offset_type{}) < 0) {
204-
return check_static_bounds_result::out_of_bounds;
159+
return false;
205160
}
206161
else if constexpr (
207162
Exts_k != dynamic_extent &&
208163
Exts_k < static_cast<size_t>(de_ice(offset_type{})))
209164
{
210-
return check_static_bounds_result::out_of_bounds;
165+
return false;
211166
}
212167
else if constexpr (is_integral_constant_like_v<typename S_k::extent_type>) {
213168
using extent_type = typename S_k::extent_type;
214169

215170
if constexpr (de_ice(offset_type{}) + de_ice(extent_type{}) < 0) {
216-
return check_static_bounds_result::out_of_bounds;
171+
return false;
217172
}
218173
else if constexpr (
219174
Exts_k != dynamic_extent &&
220175
Exts_k <
221176
static_cast<size_t>(de_ice(offset_type{}) + de_ice(extent_type{})))
222177
{
223-
return check_static_bounds_result::out_of_bounds;
178+
return false;
224179
}
225180
else if constexpr (
226181
Exts_k != dynamic_extent &&
@@ -230,29 +185,25 @@ constexpr check_static_bounds_result check_static_bounds(
230185
static_cast<size_t>(
231186
de_ice(offset_type{}) + de_ice(extent_type{})) <= Exts_k)
232187
{
233-
return check_static_bounds_result::in_bounds;
188+
return true;
234189
}
235190
else {
236-
return check_static_bounds_result::unknown;
191+
return true;
237192
}
238193
}
239194
else {
240-
return check_static_bounds_result::unknown;
195+
return true;
241196
}
242197
}
243198
else {
244-
return check_static_bounds_result::unknown;
199+
return true;
245200
}
246-
}
247-
#if ! defined(__cpp_lib_tuple_like) || (__cpp_lib_tuple_like < 202311L)
248-
else if constexpr (is_std_complex<S_k>) {
249-
return check_static_bounds_result::unknown;
250-
}
251-
#endif
252-
else {
201+
} else {
253202
// General pair-like case: attempt to get the first and second elements.
254203
// If S_k cannot be structured-bound into two elements, this is ill-formed,
255204
// which implements the Mandates clause.
205+
// Doing this via these lambdas since we can do the declval only in a
206+
// non-evaluated context
256207
auto get_first = [] (S_k s_k) {
257208
auto [s_k0, _x] = s_k;
258209
return s_k0;
@@ -263,44 +214,45 @@ constexpr check_static_bounds_result check_static_bounds(
263214
};
264215
using S_k0 = decltype(get_first(std::declval<S_k>()));
265216
using S_k1 = decltype(get_second(std::declval<S_k>()));
217+
266218
if constexpr (is_integral_constant_like_v<S_k0>) {
267219
if constexpr (de_ice(S_k0{}) < 0) {
268-
return check_static_bounds_result::out_of_bounds;
220+
return false;
269221
}
270222
else if constexpr (
271223
Exts_k != dynamic_extent &&
272224
Exts_k < static_cast<size_t>(de_ice(S_k0{})))
273225
{
274-
return check_static_bounds_result::out_of_bounds;
226+
return false;
275227
}
276228
else if constexpr (is_integral_constant_like_v<S_k1>) {
277229
if constexpr (de_ice(S_k1{}) < de_ice(S_k0{})) {
278-
return check_static_bounds_result::out_of_bounds;
230+
return false;
279231
}
280232
else if constexpr (
281233
Exts_k != dynamic_extent &&
282234
Exts_k < static_cast<size_t>(de_ice(S_k1{})))
283235
{
284-
return check_static_bounds_result::out_of_bounds;
236+
return false;
285237
}
286238
else if constexpr (
287239
Exts_k != dynamic_extent &&
288240
0 <= de_ice(S_k0{}) &&
289241
de_ice(S_k0{}) <= de_ice(S_k1{}) &&
290242
static_cast<size_t>(de_ice(S_k1{})) <= Exts_k)
291243
{
292-
return check_static_bounds_result::in_bounds;
244+
return true;
293245
}
294246
else {
295-
return check_static_bounds_result::unknown;
247+
return true;
296248
}
297249
}
298250
else {
299-
return check_static_bounds_result::unknown;
251+
return true;
300252
}
301253
}
302254
else {
303-
return check_static_bounds_result::unknown;
255+
return true;
304256
}
305257
}
306258
}
@@ -313,32 +265,13 @@ constexpr check_static_bounds_result check_static_bounds(
313265
// mandate checking and canonicalization are distinct concerns.
314266
// ============================================================
315267

316-
template<size_t k, class IndexType, size_t... Extents, class Slice>
268+
template<class IndexType, size_t Extent, class Slice>
317269
MDSPAN_INLINE_FUNCTION
318-
constexpr void check_submdspan_slice_mandate(
319-
const extents<IndexType, Extents...>&,
320-
[[maybe_unused]] Slice)
270+
constexpr bool check_submdspan_slice_mandate(
271+
[[maybe_unused]] const Slice&)
321272
{
322-
static_assert(
323-
check_static_bounds<k, Slice>(extents<IndexType, Extents...>{}) !=
324-
check_static_bounds_result::out_of_bounds);
325-
}
326-
327-
// ============================================================
328-
// check_submdspan_slice_mandates: mandate check for all slices
329-
//
330-
// Calls check_submdspan_slice_mandate for each slice.
331-
// Separated from canonicalization so mandate checking is explicit.
332-
// ============================================================
333-
334-
template<size_t... Inds, class IndexType, size_t... Extents, class... Slices>
335-
MDSPAN_INLINE_FUNCTION
336-
constexpr void check_submdspan_slice_mandates(
337-
std::index_sequence<Inds...>,
338-
const extents<IndexType, Extents...>& exts,
339-
Slices... slices)
340-
{
341-
(check_submdspan_slice_mandate<Inds>(exts, slices), ...);
273+
static_assert(check_static_bounds<IndexType, Extent, Slice>());
274+
return true;
342275
}
343276

344277
// ============================================================
@@ -404,25 +337,23 @@ constexpr auto canonical_slice([[maybe_unused]] Slice s)
404337

405338
MDSPAN_TEMPLATE_REQUIRES(
406339
size_t... Inds,
407-
class IndexType,
408-
size_t... Extents,
340+
class Extents,
409341
class... Slices,
410-
/* requires */ (sizeof...(Slices) == sizeof...(Extents))
342+
/* requires */ (sizeof...(Slices) == Extents::rank())
411343
)
412344
MDSPAN_INLINE_FUNCTION
413345
constexpr auto canonical_slices_impl(
414346
std::index_sequence<Inds...>,
415-
const extents<IndexType, Extents...>& exts,
347+
const Extents&,
416348
Slices... slices)
417349
{
418350
// Mandate checks (static_asserts only, no computation).
419351
// Separated from canonicalization for clarity.
420-
check_submdspan_slice_mandates(
421-
std::make_index_sequence<sizeof...(Slices)>(), exts, slices...);
352+
(void)(check_submdspan_slice_mandate<typename Extents::index_type, Extents::static_extent(Inds)>(slices) && ... && true);
422353

423354
// Actual canonicalization: returns detail::tuple for device compatibility.
424355
return detail::tuple{
425-
canonical_slice<IndexType>(slices)...
356+
canonical_slice<typename Extents::index_type>(slices)...
426357
};
427358
}
428359

0 commit comments

Comments
 (0)