2 //===----------------------------------------------------------------------===//
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
9 // Copyright (2022) National Technology & Engineering
10 // Solutions of Sandia, LLC (NTESS).
12 // Under the terms of Contract DE-NA0003525 with NTESS,
13 // the U.S. Government retains certain rights in this software.
15 //===---------------------------------------------------------------------===//
17 #ifndef _LIBCPP___MDSPAN_EXTENTS_H
18 #define _LIBCPP___MDSPAN_EXTENTS_H
20 #include <__cxx03/__assert>
21 #include <__cxx03/__config>
22 #include <__cxx03/__type_traits/common_type.h>
23 #include <__cxx03/__type_traits/is_convertible.h>
24 #include <__cxx03/__type_traits/is_nothrow_constructible.h>
25 #include <__cxx03/__type_traits/is_same.h>
26 #include <__cxx03/__type_traits/make_unsigned.h>
27 #include <__cxx03/__utility/integer_sequence.h>
28 #include <__cxx03/__utility/unreachable.h>
29 #include <__cxx03/array>
30 #include <__cxx03/cinttypes>
31 #include <__cxx03/concepts>
32 #include <__cxx03/cstddef>
33 #include <__cxx03/limits>
34 #include <__cxx03/span>
36 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
37 # pragma GCC system_header
41 #include <__cxx03/__undef_macros>
43 _LIBCPP_BEGIN_NAMESPACE_STD
45 #if _LIBCPP_STD_VER >= 23
47 namespace __mdspan_detail
{
49 // ------------------------------------------------------------------
50 // ------------ __static_array --------------------------------------
51 // ------------------------------------------------------------------
52 // array like class which provides an array of static values with get
53 template <class _Tp
, _Tp
... _Values
>
54 struct __static_array
{
55 static constexpr array
<_Tp
, sizeof...(_Values
)> __array
= {_Values
...};
58 _LIBCPP_HIDE_FROM_ABI
static constexpr size_t __size() { return sizeof...(_Values
); }
59 _LIBCPP_HIDE_FROM_ABI
static constexpr _Tp
__get(size_t __index
) noexcept
{ return __array
[__index
]; }
61 template <size_t _Index
>
62 _LIBCPP_HIDE_FROM_ABI
static constexpr _Tp
__get() {
67 // ------------------------------------------------------------------
68 // ------------ __possibly_empty_array -----------------------------
69 // ------------------------------------------------------------------
71 // array like class which provides get function and operator [], and
72 // has a specialization for the size 0 case.
73 // This is needed to make the __maybe_static_array be truly empty, for
76 template <class _Tp
, size_t _Size
>
77 struct __possibly_empty_array
{
79 _LIBCPP_HIDE_FROM_ABI
constexpr _Tp
& operator[](size_t __index
) { return __vals_
[__index
]; }
80 _LIBCPP_HIDE_FROM_ABI
constexpr const _Tp
& operator[](size_t __index
) const { return __vals_
[__index
]; }
84 struct __possibly_empty_array
<_Tp
, 0> {
85 _LIBCPP_HIDE_FROM_ABI
constexpr _Tp
& operator[](size_t) { __libcpp_unreachable(); }
86 _LIBCPP_HIDE_FROM_ABI
constexpr const _Tp
& operator[](size_t) const { __libcpp_unreachable(); }
89 // ------------------------------------------------------------------
90 // ------------ static_partial_sums ---------------------------------
91 // ------------------------------------------------------------------
93 // Provides a compile time partial sum one can index into
95 template <size_t... _Values
>
96 struct __static_partial_sums
{
97 _LIBCPP_HIDE_FROM_ABI
static constexpr array
<size_t, sizeof...(_Values
)> __static_partial_sums_impl() {
98 array
<size_t, sizeof...(_Values
)> __values
{_Values
...};
99 array
<size_t, sizeof...(_Values
)> __partial_sums
{{}};
100 size_t __running_sum
= 0;
101 for (int __i
= 0; __i
!= sizeof...(_Values
); ++__i
) {
102 __partial_sums
[__i
] = __running_sum
;
103 __running_sum
+= __values
[__i
];
105 return __partial_sums
;
107 static constexpr array
<size_t, sizeof...(_Values
)> __result
{__static_partial_sums_impl()};
109 _LIBCPP_HIDE_FROM_ABI
static constexpr size_t __get(size_t __index
) { return __result
[__index
]; }
112 // ------------------------------------------------------------------
113 // ------------ __maybe_static_array --------------------------------
114 // ------------------------------------------------------------------
116 // array like class which has a mix of static and runtime values but
117 // only stores the runtime values.
118 // The type of the static and the runtime values can be different.
119 // The position of a dynamic value is indicated through a tag value.
120 template <class _TDynamic
, class _TStatic
, _TStatic _DynTag
, _TStatic
... _Values
>
121 struct __maybe_static_array
{
122 static_assert(is_convertible
<_TStatic
, _TDynamic
>::value
,
123 "__maybe_static_array: _TStatic must be convertible to _TDynamic");
124 static_assert(is_convertible
<_TDynamic
, _TStatic
>::value
,
125 "__maybe_static_array: _TDynamic must be convertible to _TStatic");
128 // Static values member
129 static constexpr size_t __size_
= sizeof...(_Values
);
130 static constexpr size_t __size_dynamic_
= ((_Values
== _DynTag
) + ... + 0);
131 using _StaticValues
= __static_array
<_TStatic
, _Values
...>;
132 using _DynamicValues
= __possibly_empty_array
<_TDynamic
, __size_dynamic_
>;
134 // Dynamic values member
135 _LIBCPP_NO_UNIQUE_ADDRESS _DynamicValues __dyn_vals_
;
137 // static mapping of indices to the position in the dynamic values array
138 using _DynamicIdxMap
= __static_partial_sums
<static_cast<size_t>(_Values
== _DynTag
)...>;
140 template <size_t... _Indices
>
141 _LIBCPP_HIDE_FROM_ABI
static constexpr _DynamicValues
__zeros(index_sequence
<_Indices
...>) noexcept
{
142 return _DynamicValues
{((void)_Indices
, 0)...};
146 _LIBCPP_HIDE_FROM_ABI
constexpr __maybe_static_array() noexcept
147 : __dyn_vals_
{__zeros(make_index_sequence
<__size_dynamic_
>())} {}
149 // constructors from dynamic values only -- this covers the case for rank() == 0
150 template <class... _DynVals
>
151 requires(sizeof...(_DynVals
) == __size_dynamic_
)
152 _LIBCPP_HIDE_FROM_ABI
constexpr __maybe_static_array(_DynVals
... __vals
)
153 : __dyn_vals_
{static_cast<_TDynamic
>(__vals
)...} {}
155 template <class _Tp
, size_t _Size
>
156 requires(_Size
== __size_dynamic_
)
157 _LIBCPP_HIDE_FROM_ABI
constexpr __maybe_static_array([[maybe_unused
]] const span
<_Tp
, _Size
>& __vals
) {
158 if constexpr (_Size
> 0) {
159 for (size_t __i
= 0; __i
< _Size
; __i
++)
160 __dyn_vals_
[__i
] = static_cast<_TDynamic
>(__vals
[__i
]);
164 // constructors from all values -- here rank will be greater than 0
165 template <class... _DynVals
>
166 requires(sizeof...(_DynVals
) != __size_dynamic_
)
167 _LIBCPP_HIDE_FROM_ABI
constexpr __maybe_static_array(_DynVals
... __vals
) {
168 static_assert(sizeof...(_DynVals
) == __size_
, "Invalid number of values.");
169 _TDynamic __values
[__size_
] = {static_cast<_TDynamic
>(__vals
)...};
170 for (size_t __i
= 0; __i
< __size_
; __i
++) {
171 _TStatic __static_val
= _StaticValues::__get(__i
);
172 if (__static_val
== _DynTag
) {
173 __dyn_vals_
[_DynamicIdxMap::__get(__i
)] = __values
[__i
];
175 // Not catching this could lead to out of bounds errors later
176 // e.g. using my_mdspan_t = mdspan<int, extents<int, 10>>; my_mdspan_t = m(new int[5], 5);
177 // Right-hand-side construction looks ok with allocation and size matching,
178 // but since (potentially elsewhere defined) my_mdspan_t has static size m now thinks its range is 10 not 5
179 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
180 __values
[__i
] == static_cast<_TDynamic
>(__static_val
),
181 "extents construction: mismatch of provided arguments with static extents.");
185 template <class _Tp
, size_t _Size
>
186 requires(_Size
!= __size_dynamic_
)
187 _LIBCPP_HIDE_FROM_ABI
constexpr __maybe_static_array(const span
<_Tp
, _Size
>& __vals
) {
188 static_assert(_Size
== __size_
|| __size_
== dynamic_extent
);
189 for (size_t __i
= 0; __i
< __size_
; __i
++) {
190 _TStatic __static_val
= _StaticValues::__get(__i
);
191 if (__static_val
== _DynTag
) {
192 __dyn_vals_
[_DynamicIdxMap::__get(__i
)] = static_cast<_TDynamic
>(__vals
[__i
]);
194 // Not catching this could lead to out of bounds errors later
195 // e.g. using my_mdspan_t = mdspan<int, extents<int, 10>>; my_mdspan_t = m(new int[N], span<int,1>(&N));
196 // Right-hand-side construction looks ok with allocation and size matching,
197 // but since (potentially elsewhere defined) my_mdspan_t has static size m now thinks its range is 10 not N
198 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
199 static_cast<_TDynamic
>(__vals
[__i
]) == static_cast<_TDynamic
>(__static_val
),
200 "extents construction: mismatch of provided arguments with static extents.");
205 _LIBCPP_HIDE_FROM_ABI
static constexpr _TStatic
__static_value(size_t __i
) noexcept
{
206 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__i
< __size_
, "extents access: index must be less than rank");
207 return _StaticValues::__get(__i
);
210 _LIBCPP_HIDE_FROM_ABI
constexpr _TDynamic
__value(size_t __i
) const {
211 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__i
< __size_
, "extents access: index must be less than rank");
212 _TStatic __static_val
= _StaticValues::__get(__i
);
213 return __static_val
== _DynTag
? __dyn_vals_
[_DynamicIdxMap::__get(__i
)] : static_cast<_TDynamic
>(__static_val
);
215 _LIBCPP_HIDE_FROM_ABI
constexpr _TDynamic
operator[](size_t __i
) const {
216 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__i
< __size_
, "extents access: index must be less than rank");
221 _LIBCPP_HIDE_FROM_ABI
static constexpr size_t __size() { return __size_
; }
222 _LIBCPP_HIDE_FROM_ABI
static constexpr size_t __size_dynamic() { return __size_dynamic_
; }
225 // Function to check whether a value is representable as another type
226 // value must be a positive integer otherwise returns false
227 // if _From is not an integral, we just check positivity
228 template <integral _To
, class _From
>
229 requires(integral
<_From
>)
230 _LIBCPP_HIDE_FROM_ABI
constexpr bool __is_representable_as(_From __value
) {
231 using _To_u
= make_unsigned_t
<_To
>;
232 using _From_u
= make_unsigned_t
<_From
>;
233 if constexpr (is_signed_v
<_From
>) {
237 if constexpr (static_cast<_To_u
>(numeric_limits
<_To
>::max()) >= static_cast<_From_u
>(numeric_limits
<_From
>::max())) {
240 return static_cast<_To_u
>(numeric_limits
<_To
>::max()) >= static_cast<_From_u
>(__value
);
244 template <integral _To
, class _From
>
245 requires(!integral
<_From
>)
246 _LIBCPP_HIDE_FROM_ABI
constexpr bool __is_representable_as(_From __value
) {
247 if constexpr (is_signed_v
<_To
>) {
248 if (static_cast<_To
>(__value
) < 0)
254 template <integral _To
, class... _From
>
255 _LIBCPP_HIDE_FROM_ABI
constexpr bool __are_representable_as(_From
... __values
) {
256 return (__mdspan_detail::__is_representable_as
<_To
>(__values
) && ... && true);
259 template <integral _To
, class _From
, size_t _Size
>
260 _LIBCPP_HIDE_FROM_ABI
constexpr bool __are_representable_as(span
<_From
, _Size
> __values
) {
261 for (size_t __i
= 0; __i
< _Size
; __i
++)
262 if (!__mdspan_detail::__is_representable_as
<_To
>(__values
[__i
]))
267 } // namespace __mdspan_detail
269 // ------------------------------------------------------------------
270 // ------------ extents ---------------------------------------------
271 // ------------------------------------------------------------------
273 // Class to describe the extents of a multi dimensional array.
274 // Used by mdspan, mdarray and layout mappings.
275 // See ISO C++ standard [mdspan.extents]
277 template <class _IndexType
, size_t... _Extents
>
280 // typedefs for integral types used
281 using index_type
= _IndexType
;
282 using size_type
= make_unsigned_t
<index_type
>;
283 using rank_type
= size_t;
285 static_assert(is_integral
<index_type
>::value
&& !is_same
<index_type
, bool>::value
,
286 "extents::index_type must be a signed or unsigned integer type");
287 static_assert(((__mdspan_detail::__is_representable_as
<index_type
>(_Extents
) || (_Extents
== dynamic_extent
)) && ...),
288 "extents ctor: arguments must be representable as index_type and nonnegative");
291 static constexpr rank_type __rank_
= sizeof...(_Extents
);
292 static constexpr rank_type __rank_dynamic_
= ((_Extents
== dynamic_extent
) + ... + 0);
294 // internal storage type using __maybe_static_array
295 using _Values
= __mdspan_detail::__maybe_static_array
<_IndexType
, size_t, dynamic_extent
, _Extents
...>;
296 [[no_unique_address
]] _Values __vals_
;
299 // [mdspan.extents.obs], observers of multidimensional index space
300 _LIBCPP_HIDE_FROM_ABI
static constexpr rank_type
rank() noexcept
{ return __rank_
; }
301 _LIBCPP_HIDE_FROM_ABI
static constexpr rank_type
rank_dynamic() noexcept
{ return __rank_dynamic_
; }
303 _LIBCPP_HIDE_FROM_ABI
constexpr index_type
extent(rank_type __r
) const noexcept
{ return __vals_
.__value(__r
); }
304 _LIBCPP_HIDE_FROM_ABI
static constexpr size_t static_extent(rank_type __r
) noexcept
{
305 return _Values::__static_value(__r
);
308 // [mdspan.extents.cons], constructors
309 _LIBCPP_HIDE_FROM_ABI
constexpr extents() noexcept
= default;
311 // Construction from just dynamic or all values.
312 // Precondition check is deferred to __maybe_static_array constructor
313 template <class... _OtherIndexTypes
>
314 requires((is_convertible_v
<_OtherIndexTypes
, index_type
> && ...) &&
315 (is_nothrow_constructible_v
<index_type
, _OtherIndexTypes
> && ...) &&
316 (sizeof...(_OtherIndexTypes
) == __rank_
|| sizeof...(_OtherIndexTypes
) == __rank_dynamic_
))
317 _LIBCPP_HIDE_FROM_ABI
constexpr explicit extents(_OtherIndexTypes
... __dynvals
) noexcept
318 : __vals_(static_cast<index_type
>(__dynvals
)...) {
319 // Not catching this could lead to out of bounds errors later
320 // e.g. mdspan m(ptr, dextents<char, 1>(200u)); leads to an extent of -56 on m
321 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__mdspan_detail::__are_representable_as
<index_type
>(__dynvals
...),
322 "extents ctor: arguments must be representable as index_type and nonnegative");
325 template <class _OtherIndexType
, size_t _Size
>
326 requires(is_convertible_v
<const _OtherIndexType
&, index_type
> &&
327 is_nothrow_constructible_v
<index_type
, const _OtherIndexType
&> &&
328 (_Size
== __rank_
|| _Size
== __rank_dynamic_
))
329 explicit(_Size
!= __rank_dynamic_
)
330 _LIBCPP_HIDE_FROM_ABI
constexpr extents(const array
<_OtherIndexType
, _Size
>& __exts
) noexcept
331 : __vals_(span(__exts
)) {
332 // Not catching this could lead to out of bounds errors later
333 // e.g. mdspan m(ptr, dextents<char, 1>(array<unsigned,1>(200))); leads to an extent of -56 on m
334 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__mdspan_detail::__are_representable_as
<index_type
>(span(__exts
)),
335 "extents ctor: arguments must be representable as index_type and nonnegative");
338 template <class _OtherIndexType
, size_t _Size
>
339 requires(is_convertible_v
<const _OtherIndexType
&, index_type
> &&
340 is_nothrow_constructible_v
<index_type
, const _OtherIndexType
&> &&
341 (_Size
== __rank_
|| _Size
== __rank_dynamic_
))
342 explicit(_Size
!= __rank_dynamic_
)
343 _LIBCPP_HIDE_FROM_ABI
constexpr extents(const span
<_OtherIndexType
, _Size
>& __exts
) noexcept
345 // Not catching this could lead to out of bounds errors later
346 // e.g. array a{200u}; mdspan<int, dextents<char,1>> m(ptr, extents(span<unsigned,1>(a))); leads to an extent of -56
348 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__mdspan_detail::__are_representable_as
<index_type
>(__exts
),
349 "extents ctor: arguments must be representable as index_type and nonnegative");
353 // Function to construct extents storage from other extents.
354 template <size_t _DynCount
, size_t _Idx
, class _OtherExtents
, class... _DynamicValues
>
355 requires(_Idx
< __rank_
)
356 _LIBCPP_HIDE_FROM_ABI
constexpr _Values
__construct_vals_from_extents(
357 integral_constant
<size_t, _DynCount
>,
358 integral_constant
<size_t, _Idx
>,
359 const _OtherExtents
& __exts
,
360 _DynamicValues
... __dynamic_values
) noexcept
{
361 if constexpr (static_extent(_Idx
) == dynamic_extent
)
362 return __construct_vals_from_extents(
363 integral_constant
<size_t, _DynCount
+ 1>(),
364 integral_constant
<size_t, _Idx
+ 1>(),
367 __exts
.extent(_Idx
));
369 return __construct_vals_from_extents(
370 integral_constant
<size_t, _DynCount
>(), integral_constant
<size_t, _Idx
+ 1>(), __exts
, __dynamic_values
...);
373 template <size_t _DynCount
, size_t _Idx
, class _OtherExtents
, class... _DynamicValues
>
374 requires((_Idx
== __rank_
) && (_DynCount
== __rank_dynamic_
))
375 _LIBCPP_HIDE_FROM_ABI
constexpr _Values
__construct_vals_from_extents(
376 integral_constant
<size_t, _DynCount
>,
377 integral_constant
<size_t, _Idx
>,
378 const _OtherExtents
&,
379 _DynamicValues
... __dynamic_values
) noexcept
{
380 return _Values
{static_cast<index_type
>(__dynamic_values
)...};
384 // Converting constructor from other extents specializations
385 template <class _OtherIndexType
, size_t... _OtherExtents
>
386 requires((sizeof...(_OtherExtents
) == sizeof...(_Extents
)) &&
387 ((_OtherExtents
== dynamic_extent
|| _Extents
== dynamic_extent
|| _OtherExtents
== _Extents
) && ...))
388 explicit((((_Extents
!= dynamic_extent
) && (_OtherExtents
== dynamic_extent
)) || ...) ||
389 (static_cast<make_unsigned_t
<index_type
>>(numeric_limits
<index_type
>::max()) <
390 static_cast<make_unsigned_t
<_OtherIndexType
>>(numeric_limits
<_OtherIndexType
>::max())))
391 _LIBCPP_HIDE_FROM_ABI
constexpr extents(const extents
<_OtherIndexType
, _OtherExtents
...>& __other
) noexcept
393 __construct_vals_from_extents(integral_constant
<size_t, 0>(), integral_constant
<size_t, 0>(), __other
)) {
394 if constexpr (rank() > 0) {
395 for (size_t __r
= 0; __r
< rank(); __r
++) {
396 if constexpr (static_cast<make_unsigned_t
<index_type
>>(numeric_limits
<index_type
>::max()) <
397 static_cast<make_unsigned_t
<_OtherIndexType
>>(numeric_limits
<_OtherIndexType
>::max())) {
398 // Not catching this could lead to out of bounds errors later
399 // e.g. dextents<char,1>> e(dextents<unsigned,1>(200)) leads to an extent of -56 on e
400 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
401 __mdspan_detail::__is_representable_as
<index_type
>(__other
.extent(__r
)),
402 "extents ctor: arguments must be representable as index_type and nonnegative");
404 // Not catching this could lead to out of bounds errors later
405 // e.g. mdspan<int, extents<int, 10>> m = mdspan<int, dextents<int, 1>>(new int[5], 5);
406 // Right-hand-side construction was ok, but m now thinks its range is 10 not 5
407 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
408 (_Values::__static_value(__r
) == dynamic_extent
) ||
409 (static_cast<index_type
>(__other
.extent(__r
)) == static_cast<index_type
>(_Values::__static_value(__r
))),
410 "extents construction: mismatch of provided arguments with static extents.");
415 // Comparison operator
416 template <class _OtherIndexType
, size_t... _OtherExtents
>
417 _LIBCPP_HIDE_FROM_ABI
friend constexpr bool
418 operator==(const extents
& __lhs
, const extents
<_OtherIndexType
, _OtherExtents
...>& __rhs
) noexcept
{
419 if constexpr (rank() != sizeof...(_OtherExtents
)) {
422 for (rank_type __r
= 0; __r
< __rank_
; __r
++) {
423 // avoid warning when comparing signed and unsigner integers and pick the wider of two types
424 using _CommonType
= common_type_t
<index_type
, _OtherIndexType
>;
425 if (static_cast<_CommonType
>(__lhs
.extent(__r
)) != static_cast<_CommonType
>(__rhs
.extent(__r
))) {
434 // Recursive helper classes to implement dextents alias for extents
435 namespace __mdspan_detail
{
437 template <class _IndexType
, size_t _Rank
, class _Extents
= extents
<_IndexType
>>
438 struct __make_dextents
;
440 template <class _IndexType
, size_t _Rank
, size_t... _ExtentsPack
>
441 struct __make_dextents
< _IndexType
, _Rank
, extents
<_IndexType
, _ExtentsPack
...>> {
443 typename __make_dextents
< _IndexType
, _Rank
- 1, extents
<_IndexType
, dynamic_extent
, _ExtentsPack
...>>::type
;
446 template <class _IndexType
, size_t... _ExtentsPack
>
447 struct __make_dextents
< _IndexType
, 0, extents
<_IndexType
, _ExtentsPack
...>> {
448 using type
= extents
<_IndexType
, _ExtentsPack
...>;
451 } // end namespace __mdspan_detail
453 // [mdspan.extents.dextents], alias template
454 template <class _IndexType
, size_t _Rank
>
455 using dextents
= typename
__mdspan_detail::__make_dextents
<_IndexType
, _Rank
>::type
;
457 # if _LIBCPP_STD_VER >= 26
458 // [mdspan.extents.dims], alias template `dims`
459 template <size_t _Rank
, class _IndexType
= size_t>
460 using dims
= dextents
<_IndexType
, _Rank
>;
463 // Deduction guide for extents
464 # if _LIBCPP_STD_VER >= 26
465 template <class... _IndexTypes
>
466 requires(is_convertible_v
<_IndexTypes
, size_t> && ...)
467 explicit extents(_IndexTypes
...) -> extents
<size_t, __maybe_static_ext
<_IndexTypes
>...>;
469 template <class... _IndexTypes
>
470 requires(is_convertible_v
<_IndexTypes
, size_t> && ...)
471 explicit extents(_IndexTypes
...) -> extents
<size_t, size_t(((void)sizeof(_IndexTypes
), dynamic_extent
))...>;
474 namespace __mdspan_detail
{
476 // Helper type traits for identifying a class as extents.
478 struct __is_extents
: false_type
{};
480 template <class _IndexType
, size_t... _ExtentsPack
>
481 struct __is_extents
<extents
<_IndexType
, _ExtentsPack
...>> : true_type
{};
484 inline constexpr bool __is_extents_v
= __is_extents
<_Tp
>::value
;
486 // Function to check whether a set of indices are a multidimensional
487 // index into extents. This is a word of power in the C++ standard
488 // requiring that the indices are larger than 0 and smaller than
489 // the respective extents.
491 template <integral _IndexType
, class _From
>
492 requires(integral
<_From
>)
493 _LIBCPP_HIDE_FROM_ABI
constexpr bool __is_index_in_extent(_IndexType __extent
, _From __value
) {
494 if constexpr (is_signed_v
<_From
>) {
498 using _Tp
= common_type_t
<_IndexType
, _From
>;
499 return static_cast<_Tp
>(__value
) < static_cast<_Tp
>(__extent
);
502 template <integral _IndexType
, class _From
>
503 requires(!integral
<_From
>)
504 _LIBCPP_HIDE_FROM_ABI
constexpr bool __is_index_in_extent(_IndexType __extent
, _From __value
) {
505 if constexpr (is_signed_v
<_IndexType
>) {
506 if (static_cast<_IndexType
>(__value
) < 0)
509 return static_cast<_IndexType
>(__value
) < __extent
;
512 template <size_t... _Idxs
, class _Extents
, class... _From
>
513 _LIBCPP_HIDE_FROM_ABI
constexpr bool
514 __is_multidimensional_index_in_impl(index_sequence
<_Idxs
...>, const _Extents
& __ext
, _From
... __values
) {
515 return (__mdspan_detail::__is_index_in_extent(__ext
.extent(_Idxs
), __values
) && ...);
518 template <class _Extents
, class... _From
>
519 _LIBCPP_HIDE_FROM_ABI
constexpr bool __is_multidimensional_index_in(const _Extents
& __ext
, _From
... __values
) {
520 return __mdspan_detail::__is_multidimensional_index_in_impl(
521 make_index_sequence
<_Extents::rank()>(), __ext
, __values
...);
524 } // namespace __mdspan_detail
526 #endif // _LIBCPP_STD_VER >= 23
528 _LIBCPP_END_NAMESPACE_STD
532 #endif // _LIBCPP___MDSPAN_EXTENTS_H