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
23 #include <__concepts/arithmetic.h>
24 #include <__cstddef/byte.h>
25 #include <__type_traits/common_type.h>
26 #include <__type_traits/is_convertible.h>
27 #include <__type_traits/is_nothrow_constructible.h>
28 #include <__type_traits/is_same.h>
29 #include <__type_traits/make_unsigned.h>
30 #include <__utility/integer_sequence.h>
31 #include <__utility/unreachable.h>
37 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
38 # pragma GCC system_header
42 #include <__undef_macros>
44 _LIBCPP_BEGIN_NAMESPACE_STD
46 #if _LIBCPP_STD_VER >= 23
48 namespace __mdspan_detail
{
50 // ------------------------------------------------------------------
51 // ------------ __static_array --------------------------------------
52 // ------------------------------------------------------------------
53 // array like class which provides an array of static values with get
54 template <class _Tp
, _Tp
... _Values
>
55 struct __static_array
{
56 static constexpr array
<_Tp
, sizeof...(_Values
)> __array
= {_Values
...};
59 _LIBCPP_HIDE_FROM_ABI
static constexpr size_t __size() { return sizeof...(_Values
); }
60 _LIBCPP_HIDE_FROM_ABI
static constexpr _Tp
__get(size_t __index
) noexcept
{ return __array
[__index
]; }
62 template <size_t _Index
>
63 _LIBCPP_HIDE_FROM_ABI
static constexpr _Tp
__get() {
68 // ------------------------------------------------------------------
69 // ------------ __possibly_empty_array -----------------------------
70 // ------------------------------------------------------------------
72 // array like class which provides get function and operator [], and
73 // has a specialization for the size 0 case.
74 // This is needed to make the __maybe_static_array be truly empty, for
77 template <class _Tp
, size_t _Size
>
78 struct __possibly_empty_array
{
80 _LIBCPP_HIDE_FROM_ABI
constexpr _Tp
& operator[](size_t __index
) { return __vals_
[__index
]; }
81 _LIBCPP_HIDE_FROM_ABI
constexpr const _Tp
& operator[](size_t __index
) const { return __vals_
[__index
]; }
85 struct __possibly_empty_array
<_Tp
, 0> {
86 _LIBCPP_HIDE_FROM_ABI
constexpr _Tp
& operator[](size_t) { __libcpp_unreachable(); }
87 _LIBCPP_HIDE_FROM_ABI
constexpr const _Tp
& operator[](size_t) const { __libcpp_unreachable(); }
90 // ------------------------------------------------------------------
91 // ------------ static_partial_sums ---------------------------------
92 // ------------------------------------------------------------------
94 // Provides a compile time partial sum one can index into
96 template <size_t... _Values
>
97 struct __static_partial_sums
{
98 _LIBCPP_HIDE_FROM_ABI
static constexpr array
<size_t, sizeof...(_Values
)> __static_partial_sums_impl() {
99 array
<size_t, sizeof...(_Values
)> __values
{_Values
...};
100 array
<size_t, sizeof...(_Values
)> __partial_sums
{{}};
101 size_t __running_sum
= 0;
102 for (int __i
= 0; __i
!= sizeof...(_Values
); ++__i
) {
103 __partial_sums
[__i
] = __running_sum
;
104 __running_sum
+= __values
[__i
];
106 return __partial_sums
;
108 static constexpr array
<size_t, sizeof...(_Values
)> __result
{__static_partial_sums_impl()};
110 _LIBCPP_HIDE_FROM_ABI
static constexpr size_t __get(size_t __index
) { return __result
[__index
]; }
113 // ------------------------------------------------------------------
114 // ------------ __maybe_static_array --------------------------------
115 // ------------------------------------------------------------------
117 // array like class which has a mix of static and runtime values but
118 // only stores the runtime values.
119 // The type of the static and the runtime values can be different.
120 // The position of a dynamic value is indicated through a tag value.
121 template <class _TDynamic
, class _TStatic
, _TStatic _DynTag
, _TStatic
... _Values
>
122 struct __maybe_static_array
{
123 static_assert(is_convertible
<_TStatic
, _TDynamic
>::value
,
124 "__maybe_static_array: _TStatic must be convertible to _TDynamic");
125 static_assert(is_convertible
<_TDynamic
, _TStatic
>::value
,
126 "__maybe_static_array: _TDynamic must be convertible to _TStatic");
129 // Static values member
130 static constexpr size_t __size_
= sizeof...(_Values
);
131 static constexpr size_t __size_dynamic_
= ((_Values
== _DynTag
) + ... + 0);
132 using _StaticValues
= __static_array
<_TStatic
, _Values
...>;
133 using _DynamicValues
= __possibly_empty_array
<_TDynamic
, __size_dynamic_
>;
135 // Dynamic values member
136 _LIBCPP_NO_UNIQUE_ADDRESS _DynamicValues __dyn_vals_
;
138 // static mapping of indices to the position in the dynamic values array
139 using _DynamicIdxMap
= __static_partial_sums
<static_cast<size_t>(_Values
== _DynTag
)...>;
141 template <size_t... _Indices
>
142 _LIBCPP_HIDE_FROM_ABI
static constexpr _DynamicValues
__zeros(index_sequence
<_Indices
...>) noexcept
{
143 return _DynamicValues
{((void)_Indices
, 0)...};
147 _LIBCPP_HIDE_FROM_ABI
constexpr __maybe_static_array() noexcept
148 : __dyn_vals_
{__zeros(make_index_sequence
<__size_dynamic_
>())} {}
150 // constructors from dynamic values only -- this covers the case for rank() == 0
151 template <class... _DynVals
>
152 requires(sizeof...(_DynVals
) == __size_dynamic_
)
153 _LIBCPP_HIDE_FROM_ABI
constexpr __maybe_static_array(_DynVals
... __vals
)
154 : __dyn_vals_
{static_cast<_TDynamic
>(__vals
)...} {}
156 template <class _Tp
, size_t _Size
>
157 requires(_Size
== __size_dynamic_
)
158 _LIBCPP_HIDE_FROM_ABI
constexpr __maybe_static_array([[maybe_unused
]] const span
<_Tp
, _Size
>& __vals
) {
159 if constexpr (_Size
> 0) {
160 for (size_t __i
= 0; __i
< _Size
; __i
++)
161 __dyn_vals_
[__i
] = static_cast<_TDynamic
>(__vals
[__i
]);
165 // constructors from all values -- here rank will be greater than 0
166 template <class... _DynVals
>
167 requires(sizeof...(_DynVals
) != __size_dynamic_
)
168 _LIBCPP_HIDE_FROM_ABI
constexpr __maybe_static_array(_DynVals
... __vals
) {
169 static_assert(sizeof...(_DynVals
) == __size_
, "Invalid number of values.");
170 _TDynamic __values
[__size_
] = {static_cast<_TDynamic
>(__vals
)...};
171 for (size_t __i
= 0; __i
< __size_
; __i
++) {
172 _TStatic __static_val
= _StaticValues::__get(__i
);
173 if (__static_val
== _DynTag
) {
174 __dyn_vals_
[_DynamicIdxMap::__get(__i
)] = __values
[__i
];
176 // Not catching this could lead to out of bounds errors later
177 // e.g. using my_mdspan_t = mdspan<int, extents<int, 10>>; my_mdspan_t = m(new int[5], 5);
178 // Right-hand-side construction looks ok with allocation and size matching,
179 // but since (potentially elsewhere defined) my_mdspan_t has static size m now thinks its range is 10 not 5
180 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
181 __values
[__i
] == static_cast<_TDynamic
>(__static_val
),
182 "extents construction: mismatch of provided arguments with static extents.");
186 template <class _Tp
, size_t _Size
>
187 requires(_Size
!= __size_dynamic_
)
188 _LIBCPP_HIDE_FROM_ABI
constexpr __maybe_static_array(const span
<_Tp
, _Size
>& __vals
) {
189 static_assert(_Size
== __size_
|| __size_
== dynamic_extent
);
190 for (size_t __i
= 0; __i
< __size_
; __i
++) {
191 _TStatic __static_val
= _StaticValues::__get(__i
);
192 if (__static_val
== _DynTag
) {
193 __dyn_vals_
[_DynamicIdxMap::__get(__i
)] = static_cast<_TDynamic
>(__vals
[__i
]);
195 // Not catching this could lead to out of bounds errors later
196 // e.g. using my_mdspan_t = mdspan<int, extents<int, 10>>; my_mdspan_t = m(new int[N], span<int,1>(&N));
197 // Right-hand-side construction looks ok with allocation and size matching,
198 // but since (potentially elsewhere defined) my_mdspan_t has static size m now thinks its range is 10 not N
199 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
200 static_cast<_TDynamic
>(__vals
[__i
]) == static_cast<_TDynamic
>(__static_val
),
201 "extents construction: mismatch of provided arguments with static extents.");
206 _LIBCPP_HIDE_FROM_ABI
static constexpr _TStatic
__static_value(size_t __i
) noexcept
{
207 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__i
< __size_
, "extents access: index must be less than rank");
208 return _StaticValues::__get(__i
);
211 _LIBCPP_HIDE_FROM_ABI
constexpr _TDynamic
__value(size_t __i
) const {
212 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__i
< __size_
, "extents access: index must be less than rank");
213 _TStatic __static_val
= _StaticValues::__get(__i
);
214 return __static_val
== _DynTag
? __dyn_vals_
[_DynamicIdxMap::__get(__i
)] : static_cast<_TDynamic
>(__static_val
);
216 _LIBCPP_HIDE_FROM_ABI
constexpr _TDynamic
operator[](size_t __i
) const {
217 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__i
< __size_
, "extents access: index must be less than rank");
222 _LIBCPP_HIDE_FROM_ABI
static constexpr size_t __size() { return __size_
; }
223 _LIBCPP_HIDE_FROM_ABI
static constexpr size_t __size_dynamic() { return __size_dynamic_
; }
226 // Function to check whether a value is representable as another type
227 // value must be a positive integer otherwise returns false
228 // if _From is not an integral, we just check positivity
229 template <integral _To
, class _From
>
230 requires(integral
<_From
>)
231 _LIBCPP_HIDE_FROM_ABI
constexpr bool __is_representable_as(_From __value
) {
232 using _To_u
= make_unsigned_t
<_To
>;
233 using _From_u
= make_unsigned_t
<_From
>;
234 if constexpr (is_signed_v
<_From
>) {
238 if constexpr (static_cast<_To_u
>(numeric_limits
<_To
>::max()) >= static_cast<_From_u
>(numeric_limits
<_From
>::max())) {
241 return static_cast<_To_u
>(numeric_limits
<_To
>::max()) >= static_cast<_From_u
>(__value
);
245 template <integral _To
, class _From
>
246 requires(!integral
<_From
>)
247 _LIBCPP_HIDE_FROM_ABI
constexpr bool __is_representable_as(_From __value
) {
248 if constexpr (is_signed_v
<_To
>) {
249 if (static_cast<_To
>(__value
) < 0)
255 template <integral _To
, class... _From
>
256 _LIBCPP_HIDE_FROM_ABI
constexpr bool __are_representable_as(_From
... __values
) {
257 return (__mdspan_detail::__is_representable_as
<_To
>(__values
) && ... && true);
260 template <integral _To
, class _From
, size_t _Size
>
261 _LIBCPP_HIDE_FROM_ABI
constexpr bool __are_representable_as(span
<_From
, _Size
> __values
) {
262 for (size_t __i
= 0; __i
< _Size
; __i
++)
263 if (!__mdspan_detail::__is_representable_as
<_To
>(__values
[__i
]))
268 } // namespace __mdspan_detail
270 // ------------------------------------------------------------------
271 // ------------ extents ---------------------------------------------
272 // ------------------------------------------------------------------
274 // Class to describe the extents of a multi dimensional array.
275 // Used by mdspan, mdarray and layout mappings.
276 // See ISO C++ standard [mdspan.extents]
278 template <class _IndexType
, size_t... _Extents
>
281 // typedefs for integral types used
282 using index_type
= _IndexType
;
283 using size_type
= make_unsigned_t
<index_type
>;
284 using rank_type
= size_t;
286 static_assert(__libcpp_integer
<index_type
>, "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 } // 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