1// -*- C++ -*-
2//===----------------------------------------------------------------------===//
3//
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
7//
8// Kokkos v. 4.0
9// Copyright (2022) National Technology & Engineering
10// Solutions of Sandia, LLC (NTESS).
11//
12// Under the terms of Contract DE-NA0003525 with NTESS,
13// the U.S. Government retains certain rights in this software.
14//
15//===---------------------------------------------------------------------===//
16
17#ifndef _LIBCPP___MDSPAN_EXTENTS_H
18#define _LIBCPP___MDSPAN_EXTENTS_H
19
20#include <__assert>
21#include <__config>
22
23#include <__concepts/arithmetic.h>
24#include <__type_traits/common_type.h>
25#include <__type_traits/integer_traits.h>
26#include <__type_traits/is_convertible.h>
27#include <__type_traits/is_nothrow_constructible.h>
28#include <__type_traits/is_signed.h>
29#include <__type_traits/make_unsigned.h>
30#include <__utility/integer_sequence.h>
31#include <__utility/unreachable.h>
32#include <array>
33#include <concepts>
34#include <limits>
35#include <span>
36
37#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
38# pragma GCC system_header
39#endif
40
41_LIBCPP_PUSH_MACROS
42#include <__undef_macros>
43
44_LIBCPP_BEGIN_NAMESPACE_STD
45
46#if _LIBCPP_STD_VER >= 23
47
48namespace __mdspan_detail {
49
50// ------------------------------------------------------------------
51// ------------ __static_array --------------------------------------
52// ------------------------------------------------------------------
53// array like class which provides an array of static values with get
54template <class _Tp, _Tp... _Values>
55struct __static_array {
56 static constexpr array<_Tp, sizeof...(_Values)> __array = {_Values...};
57
58public:
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]; }
61
62 template <size_t _Index>
63 _LIBCPP_HIDE_FROM_ABI static constexpr _Tp __get() {
64 return __get(_Index);
65 }
66};
67
68// ------------------------------------------------------------------
69// ------------ __possibly_empty_array -----------------------------
70// ------------------------------------------------------------------
71
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
75// all static values.
76
77template <class _Tp, size_t _Size>
78struct __possibly_empty_array {
79 _Tp __vals_[_Size];
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]; }
82};
83
84template <class _Tp>
85struct __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(); }
88};
89
90// ------------------------------------------------------------------
91// ------------ static_partial_sums ---------------------------------
92// ------------------------------------------------------------------
93
94// Provides a compile time partial sum one can index into
95
96template <size_t... _Values>
97struct __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];
105 }
106 return __partial_sums;
107 }
108 static constexpr array<size_t, sizeof...(_Values)> __result{__static_partial_sums_impl()};
109
110 _LIBCPP_HIDE_FROM_ABI static constexpr size_t __get(size_t __index) { return __result[__index]; }
111};
112
113// ------------------------------------------------------------------
114// ------------ __maybe_static_array --------------------------------
115// ------------------------------------------------------------------
116
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.
121template <class _TDynamic, class _TStatic, _TStatic _DynTag, _TStatic... _Values>
122struct __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");
127
128private:
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 _LIBCPP_NODEBUG = __static_array<_TStatic, _Values...>;
133 using _DynamicValues _LIBCPP_NODEBUG = __possibly_empty_array<_TDynamic, __size_dynamic_>;
134
135 // Dynamic values member
136 _LIBCPP_NO_UNIQUE_ADDRESS _DynamicValues __dyn_vals_;
137
138 // static mapping of indices to the position in the dynamic values array
139 using _DynamicIdxMap _LIBCPP_NODEBUG = __static_partial_sums<static_cast<size_t>(_Values == _DynTag)...>;
140
141 template <size_t... _Indices>
142 _LIBCPP_HIDE_FROM_ABI static constexpr _DynamicValues __zeros(index_sequence<_Indices...>) noexcept {
143 return _DynamicValues{((void)_Indices, 0)...};
144 }
145
146public:
147 _LIBCPP_HIDE_FROM_ABI constexpr __maybe_static_array() noexcept
148 : __dyn_vals_{__zeros(make_index_sequence<__size_dynamic_>())} {}
149
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)...} {}
155
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]);
162 }
163 }
164
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];
175 } else
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.");
183 }
184 }
185
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]);
194 } else
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.");
202 }
203 }
204
205 // access functions
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);
209 }
210
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);
215 }
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");
218 return __value(__i);
219 }
220
221 // observers
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_; }
224};
225
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
229template <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>) {
235 if (__value < 0)
236 return false;
237 }
238 if constexpr (static_cast<_To_u>(numeric_limits<_To>::max()) >= static_cast<_From_u>(numeric_limits<_From>::max())) {
239 return true;
240 } else {
241 return static_cast<_To_u>(numeric_limits<_To>::max()) >= static_cast<_From_u>(__value);
242 }
243}
244
245template <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)
250 return false;
251 }
252 return true;
253}
254
255template <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);
258}
259
260template <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]))
264 return false;
265 return true;
266}
267
268} // namespace __mdspan_detail
269
270// ------------------------------------------------------------------
271// ------------ extents ---------------------------------------------
272// ------------------------------------------------------------------
273
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]
277
278template <class _IndexType, size_t... _Extents>
279class extents {
280public:
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;
285
286 static_assert(__signed_or_unsigned_integer<index_type>,
287 "extents::index_type must be a signed or unsigned integer type");
288 static_assert(((__mdspan_detail::__is_representable_as<index_type>(_Extents) || (_Extents == dynamic_extent)) && ...),
289 "extents ctor: arguments must be representable as index_type and nonnegative");
290
291private:
292 static constexpr rank_type __rank_ = sizeof...(_Extents);
293 static constexpr rank_type __rank_dynamic_ = ((_Extents == dynamic_extent) + ... + 0);
294
295 // internal storage type using __maybe_static_array
296 using _Values _LIBCPP_NODEBUG =
297 __mdspan_detail::__maybe_static_array<_IndexType, size_t, dynamic_extent, _Extents...>;
298 [[no_unique_address]] _Values __vals_;
299
300public:
301 // [mdspan.extents.obs], observers of multidimensional index space
302 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr rank_type rank() noexcept { return __rank_; }
303 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr rank_type rank_dynamic() noexcept { return __rank_dynamic_; }
304
305 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr index_type extent(rank_type __r) const noexcept {
306 return __vals_.__value(__r);
307 }
308 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr size_t static_extent(rank_type __r) noexcept {
309 return _Values::__static_value(__r);
310 }
311
312 // [mdspan.extents.cons], constructors
313 _LIBCPP_HIDE_FROM_ABI constexpr extents() noexcept = default;
314
315 // Construction from just dynamic or all values.
316 // Precondition check is deferred to __maybe_static_array constructor
317 template <class... _OtherIndexTypes>
318 requires((is_convertible_v<_OtherIndexTypes, index_type> && ...) &&
319 (is_nothrow_constructible_v<index_type, _OtherIndexTypes> && ...) &&
320 (sizeof...(_OtherIndexTypes) == __rank_ || sizeof...(_OtherIndexTypes) == __rank_dynamic_))
321 _LIBCPP_HIDE_FROM_ABI constexpr explicit extents(_OtherIndexTypes... __dynvals) noexcept
322 : __vals_(static_cast<index_type>(__dynvals)...) {
323 // Not catching this could lead to out of bounds errors later
324 // e.g. mdspan m(ptr, dextents<char, 1>(200u)); leads to an extent of -56 on m
325 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__mdspan_detail::__are_representable_as<index_type>(__dynvals...),
326 "extents ctor: arguments must be representable as index_type and nonnegative");
327 }
328
329 template <class _OtherIndexType, size_t _Size>
330 requires(is_convertible_v<const _OtherIndexType&, index_type> &&
331 is_nothrow_constructible_v<index_type, const _OtherIndexType&> &&
332 (_Size == __rank_ || _Size == __rank_dynamic_))
333 explicit(_Size != __rank_dynamic_)
334 _LIBCPP_HIDE_FROM_ABI constexpr extents(const array<_OtherIndexType, _Size>& __exts) noexcept
335 : __vals_(span(__exts)) {
336 // Not catching this could lead to out of bounds errors later
337 // e.g. mdspan m(ptr, dextents<char, 1>(array<unsigned,1>(200))); leads to an extent of -56 on m
338 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__mdspan_detail::__are_representable_as<index_type>(span(__exts)),
339 "extents ctor: arguments must be representable as index_type and nonnegative");
340 }
341
342 template <class _OtherIndexType, size_t _Size>
343 requires(is_convertible_v<const _OtherIndexType&, index_type> &&
344 is_nothrow_constructible_v<index_type, const _OtherIndexType&> &&
345 (_Size == __rank_ || _Size == __rank_dynamic_))
346 explicit(_Size != __rank_dynamic_)
347 _LIBCPP_HIDE_FROM_ABI constexpr extents(const span<_OtherIndexType, _Size>& __exts) noexcept
348 : __vals_(__exts) {
349 // Not catching this could lead to out of bounds errors later
350 // e.g. array a{200u}; mdspan<int, dextents<char,1>> m(ptr, extents(span<unsigned,1>(a))); leads to an extent of -56
351 // on m
352 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__mdspan_detail::__are_representable_as<index_type>(__exts),
353 "extents ctor: arguments must be representable as index_type and nonnegative");
354 }
355
356private:
357 // Function to construct extents storage from other extents.
358 template <size_t _DynCount, size_t _Idx, class _OtherExtents, class... _DynamicValues>
359 requires(_Idx < __rank_)
360 _LIBCPP_HIDE_FROM_ABI constexpr _Values __construct_vals_from_extents(
361 integral_constant<size_t, _DynCount>,
362 integral_constant<size_t, _Idx>,
363 const _OtherExtents& __exts,
364 _DynamicValues... __dynamic_values) noexcept {
365 if constexpr (static_extent(_Idx) == dynamic_extent)
366 return __construct_vals_from_extents(
367 integral_constant<size_t, _DynCount + 1>(),
368 integral_constant<size_t, _Idx + 1>(),
369 __exts,
370 __dynamic_values...,
371 __exts.extent(_Idx));
372 else
373 return __construct_vals_from_extents(
374 integral_constant<size_t, _DynCount>(), integral_constant<size_t, _Idx + 1>(), __exts, __dynamic_values...);
375 }
376
377 template <size_t _DynCount, size_t _Idx, class _OtherExtents, class... _DynamicValues>
378 requires((_Idx == __rank_) && (_DynCount == __rank_dynamic_))
379 _LIBCPP_HIDE_FROM_ABI constexpr _Values __construct_vals_from_extents(
380 integral_constant<size_t, _DynCount>,
381 integral_constant<size_t, _Idx>,
382 const _OtherExtents&,
383 _DynamicValues... __dynamic_values) noexcept {
384 return _Values{static_cast<index_type>(__dynamic_values)...};
385 }
386
387public:
388 // Converting constructor from other extents specializations
389 template <class _OtherIndexType, size_t... _OtherExtents>
390 requires((sizeof...(_OtherExtents) == sizeof...(_Extents)) &&
391 ((_OtherExtents == dynamic_extent || _Extents == dynamic_extent || _OtherExtents == _Extents) && ...))
392 explicit((((_Extents != dynamic_extent) && (_OtherExtents == dynamic_extent)) || ...) ||
393 (static_cast<make_unsigned_t<index_type>>(numeric_limits<index_type>::max()) <
394 static_cast<make_unsigned_t<_OtherIndexType>>(numeric_limits<_OtherIndexType>::max())))
395 _LIBCPP_HIDE_FROM_ABI constexpr extents(const extents<_OtherIndexType, _OtherExtents...>& __other) noexcept
396 : __vals_(
397 __construct_vals_from_extents(integral_constant<size_t, 0>(), integral_constant<size_t, 0>(), __other)) {
398 if constexpr (rank() > 0) {
399 for (size_t __r = 0; __r < rank(); __r++) {
400 if constexpr (static_cast<make_unsigned_t<index_type>>(numeric_limits<index_type>::max()) <
401 static_cast<make_unsigned_t<_OtherIndexType>>(numeric_limits<_OtherIndexType>::max())) {
402 // Not catching this could lead to out of bounds errors later
403 // e.g. dextents<char,1>> e(dextents<unsigned,1>(200)) leads to an extent of -56 on e
404 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
405 __mdspan_detail::__is_representable_as<index_type>(__other.extent(__r)),
406 "extents ctor: arguments must be representable as index_type and nonnegative");
407 }
408 // Not catching this could lead to out of bounds errors later
409 // e.g. mdspan<int, extents<int, 10>> m = mdspan<int, dextents<int, 1>>(new int[5], 5);
410 // Right-hand-side construction was ok, but m now thinks its range is 10 not 5
411 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
412 (_Values::__static_value(__r) == dynamic_extent) ||
413 (static_cast<index_type>(__other.extent(__r)) == static_cast<index_type>(_Values::__static_value(__r))),
414 "extents construction: mismatch of provided arguments with static extents.");
415 }
416 }
417 }
418
419 // Comparison operator
420 template <class _OtherIndexType, size_t... _OtherExtents>
421 _LIBCPP_HIDE_FROM_ABI friend constexpr bool
422 operator==(const extents& __lhs, const extents<_OtherIndexType, _OtherExtents...>& __rhs) noexcept {
423 if constexpr (rank() != sizeof...(_OtherExtents)) {
424 return false;
425 } else {
426 for (rank_type __r = 0; __r < __rank_; __r++) {
427 // avoid warning when comparing signed and unsigner integers and pick the wider of two types
428 using _CommonType = common_type_t<index_type, _OtherIndexType>;
429 if (static_cast<_CommonType>(__lhs.extent(__r)) != static_cast<_CommonType>(__rhs.extent(__r))) {
430 return false;
431 }
432 }
433 }
434 return true;
435 }
436};
437
438// Recursive helper classes to implement dextents alias for extents
439namespace __mdspan_detail {
440
441template <class _IndexType, size_t _Rank, class _Extents = extents<_IndexType>>
442struct __make_dextents;
443
444template <class _IndexType, size_t _Rank, size_t... _ExtentsPack>
445struct __make_dextents< _IndexType, _Rank, extents<_IndexType, _ExtentsPack...>> {
446 using type _LIBCPP_NODEBUG =
447 typename __make_dextents< _IndexType, _Rank - 1, extents<_IndexType, dynamic_extent, _ExtentsPack...>>::type;
448};
449
450template <class _IndexType, size_t... _ExtentsPack>
451struct __make_dextents< _IndexType, 0, extents<_IndexType, _ExtentsPack...>> {
452 using type _LIBCPP_NODEBUG = extents<_IndexType, _ExtentsPack...>;
453};
454
455} // namespace __mdspan_detail
456
457// [mdspan.extents.dextents], alias template
458template <class _IndexType, size_t _Rank>
459using dextents = typename __mdspan_detail::__make_dextents<_IndexType, _Rank>::type;
460
461# if _LIBCPP_STD_VER >= 26
462// [mdspan.extents.dims], alias template `dims`
463template <size_t _Rank, class _IndexType = size_t>
464using dims = dextents<_IndexType, _Rank>;
465# endif
466
467// Deduction guide for extents
468# if _LIBCPP_STD_VER >= 26
469template <class... _IndexTypes>
470 requires(is_convertible_v<_IndexTypes, size_t> && ...)
471explicit extents(_IndexTypes...) -> extents<size_t, __maybe_static_ext<_IndexTypes>...>;
472# else
473template <class... _IndexTypes>
474 requires(is_convertible_v<_IndexTypes, size_t> && ...)
475explicit extents(_IndexTypes...) -> extents<size_t, size_t(((void)sizeof(_IndexTypes), dynamic_extent))...>;
476# endif
477
478namespace __mdspan_detail {
479
480// Helper type traits for identifying a class as extents.
481template <class _Tp>
482struct __is_extents : false_type {};
483
484template <class _IndexType, size_t... _ExtentsPack>
485struct __is_extents<extents<_IndexType, _ExtentsPack...>> : true_type {};
486
487template <class _Tp>
488inline constexpr bool __is_extents_v = __is_extents<_Tp>::value;
489
490// Function to check whether a set of indices are a multidimensional
491// index into extents. This is a word of power in the C++ standard
492// requiring that the indices are larger than 0 and smaller than
493// the respective extents.
494
495template <integral _IndexType, class _From>
496 requires(integral<_From>)
497_LIBCPP_HIDE_FROM_ABI constexpr bool __is_index_in_extent(_IndexType __extent, _From __value) {
498 if constexpr (is_signed_v<_From>) {
499 if (__value < 0)
500 return false;
501 }
502 using _Tp = common_type_t<_IndexType, _From>;
503 return static_cast<_Tp>(__value) < static_cast<_Tp>(__extent);
504}
505
506template <integral _IndexType, class _From>
507 requires(!integral<_From>)
508_LIBCPP_HIDE_FROM_ABI constexpr bool __is_index_in_extent(_IndexType __extent, _From __value) {
509 if constexpr (is_signed_v<_IndexType>) {
510 if (static_cast<_IndexType>(__value) < 0)
511 return false;
512 }
513 return static_cast<_IndexType>(__value) < __extent;
514}
515
516template <size_t... _Idxs, class _Extents, class... _From>
517_LIBCPP_HIDE_FROM_ABI constexpr bool
518__is_multidimensional_index_in_impl(index_sequence<_Idxs...>, const _Extents& __ext, _From... __values) {
519 return (__mdspan_detail::__is_index_in_extent(__ext.extent(_Idxs), __values) && ...);
520}
521
522template <class _Extents, class... _From>
523_LIBCPP_HIDE_FROM_ABI constexpr bool __is_multidimensional_index_in(const _Extents& __ext, _From... __values) {
524 return __mdspan_detail::__is_multidimensional_index_in_impl(
525 make_index_sequence<_Extents::rank()>(), __ext, __values...);
526}
527
528} // namespace __mdspan_detail
529
530#endif // _LIBCPP_STD_VER >= 23
531
532_LIBCPP_END_NAMESPACE_STD
533
534_LIBCPP_POP_MACROS
535
536#endif // _LIBCPP___MDSPAN_EXTENTS_H