blob: 3d2c2771a834b4a04cbf2fc9e2b7be5215da5477 [file] [log] [blame]
Christian Trottfcaccf82023-05-16 19:38:111// -*- 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>
A. Jiang74e70ba2024-08-27 20:41:5522
23#include <__concepts/arithmetic.h>
Christian Trottfcaccf82023-05-16 19:38:1124#include <__type_traits/common_type.h>
25#include <__type_traits/is_convertible.h>
26#include <__type_traits/is_nothrow_constructible.h>
27#include <__type_traits/is_same.h>
28#include <__type_traits/make_unsigned.h>
29#include <__utility/integer_sequence.h>
30#include <__utility/unreachable.h>
31#include <array>
32#include <cinttypes>
33#include <concepts>
34#include <cstddef>
35#include <limits>
36#include <span>
37
38#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
39# pragma GCC system_header
40#endif
41
42_LIBCPP_PUSH_MACROS
43#include <__undef_macros>
44
45_LIBCPP_BEGIN_NAMESPACE_STD
46
47#if _LIBCPP_STD_VER >= 23
48
49namespace __mdspan_detail {
50
51// ------------------------------------------------------------------
52// ------------ __static_array --------------------------------------
53// ------------------------------------------------------------------
54// array like class which provides an array of static values with get
55template <class _Tp, _Tp... _Values>
56struct __static_array {
57 static constexpr array<_Tp, sizeof...(_Values)> __array = {_Values...};
58
59public:
60 _LIBCPP_HIDE_FROM_ABI static constexpr size_t __size() { return sizeof...(_Values); }
61 _LIBCPP_HIDE_FROM_ABI static constexpr _Tp __get(size_t __index) noexcept { return __array[__index]; }
62
63 template <size_t _Index>
64 _LIBCPP_HIDE_FROM_ABI static constexpr _Tp __get() {
65 return __get(_Index);
66 }
67};
68
69// ------------------------------------------------------------------
70// ------------ __possibly_empty_array -----------------------------
71// ------------------------------------------------------------------
72
73// array like class which provides get function and operator [], and
74// has a specialization for the size 0 case.
75// This is needed to make the __maybe_static_array be truly empty, for
76// all static values.
77
78template <class _Tp, size_t _Size>
79struct __possibly_empty_array {
80 _Tp __vals_[_Size];
81 _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator[](size_t __index) { return __vals_[__index]; }
82 _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator[](size_t __index) const { return __vals_[__index]; }
83};
84
85template <class _Tp>
86struct __possibly_empty_array<_Tp, 0> {
87 _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator[](size_t) { __libcpp_unreachable(); }
88 _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator[](size_t) const { __libcpp_unreachable(); }
89};
90
91// ------------------------------------------------------------------
92// ------------ static_partial_sums ---------------------------------
93// ------------------------------------------------------------------
94
95// Provides a compile time partial sum one can index into
96
97template <size_t... _Values>
98struct __static_partial_sums {
99 _LIBCPP_HIDE_FROM_ABI static constexpr array<size_t, sizeof...(_Values)> __static_partial_sums_impl() {
100 array<size_t, sizeof...(_Values)> __values{_Values...};
101 array<size_t, sizeof...(_Values)> __partial_sums{{}};
102 size_t __running_sum = 0;
103 for (int __i = 0; __i != sizeof...(_Values); ++__i) {
104 __partial_sums[__i] = __running_sum;
105 __running_sum += __values[__i];
106 }
107 return __partial_sums;
108 }
109 static constexpr array<size_t, sizeof...(_Values)> __result{__static_partial_sums_impl()};
110
111 _LIBCPP_HIDE_FROM_ABI static constexpr size_t __get(size_t __index) { return __result[__index]; }
112};
113
114// ------------------------------------------------------------------
115// ------------ __maybe_static_array --------------------------------
116// ------------------------------------------------------------------
117
118// array like class which has a mix of static and runtime values but
119// only stores the runtime values.
120// The type of the static and the runtime values can be different.
121// The position of a dynamic value is indicated through a tag value.
122template <class _TDynamic, class _TStatic, _TStatic _DynTag, _TStatic... _Values>
123struct __maybe_static_array {
124 static_assert(is_convertible<_TStatic, _TDynamic>::value,
125 "__maybe_static_array: _TStatic must be convertible to _TDynamic");
126 static_assert(is_convertible<_TDynamic, _TStatic>::value,
127 "__maybe_static_array: _TDynamic must be convertible to _TStatic");
128
129private:
130 // Static values member
131 static constexpr size_t __size_ = sizeof...(_Values);
132 static constexpr size_t __size_dynamic_ = ((_Values == _DynTag) + ... + 0);
133 using _StaticValues = __static_array<_TStatic, _Values...>;
134 using _DynamicValues = __possibly_empty_array<_TDynamic, __size_dynamic_>;
135
136 // Dynamic values member
137 _LIBCPP_NO_UNIQUE_ADDRESS _DynamicValues __dyn_vals_;
138
139 // static mapping of indices to the position in the dynamic values array
140 using _DynamicIdxMap = __static_partial_sums<static_cast<size_t>(_Values == _DynTag)...>;
141
Nikolas Klauserd231b502024-06-07 05:43:20142 template <size_t... _Indices>
143 _LIBCPP_HIDE_FROM_ABI static constexpr _DynamicValues __zeros(index_sequence<_Indices...>) noexcept {
144 return _DynamicValues{((void)_Indices, 0)...};
Christian Trottfcaccf82023-05-16 19:38:11145 }
146
147public:
148 _LIBCPP_HIDE_FROM_ABI constexpr __maybe_static_array() noexcept
149 : __dyn_vals_{__zeros(make_index_sequence<__size_dynamic_>())} {}
150
151 // constructors from dynamic values only -- this covers the case for rank() == 0
152 template <class... _DynVals>
153 requires(sizeof...(_DynVals) == __size_dynamic_)
154 _LIBCPP_HIDE_FROM_ABI constexpr __maybe_static_array(_DynVals... __vals)
155 : __dyn_vals_{static_cast<_TDynamic>(__vals)...} {}
156
157 template <class _Tp, size_t _Size >
158 requires(_Size == __size_dynamic_)
159 _LIBCPP_HIDE_FROM_ABI constexpr __maybe_static_array([[maybe_unused]] const span<_Tp, _Size>& __vals) {
160 if constexpr (_Size > 0) {
161 for (size_t __i = 0; __i < _Size; __i++)
162 __dyn_vals_[__i] = static_cast<_TDynamic>(__vals[__i]);
163 }
164 }
165
166 // constructors from all values -- here rank will be greater than 0
167 template <class... _DynVals>
168 requires(sizeof...(_DynVals) != __size_dynamic_)
169 _LIBCPP_HIDE_FROM_ABI constexpr __maybe_static_array(_DynVals... __vals) {
Nikolas Klauser6b4b29f2024-06-18 08:45:30170 static_assert(sizeof...(_DynVals) == __size_, "Invalid number of values.");
Christian Trottfcaccf82023-05-16 19:38:11171 _TDynamic __values[__size_] = {static_cast<_TDynamic>(__vals)...};
172 for (size_t __i = 0; __i < __size_; __i++) {
173 _TStatic __static_val = _StaticValues::__get(__i);
174 if (__static_val == _DynTag) {
175 __dyn_vals_[_DynamicIdxMap::__get(__i)] = __values[__i];
Christian Trott488c3db2023-07-25 18:25:17176 } else
177 // Not catching this could lead to out of bounds errors later
178 // e.g. using my_mdspan_t = mdspan<int, extents<int, 10>>; my_mdspan_t = m(new int[5], 5);
179 // Right-hand-side construction looks ok with allocation and size matching,
180 // but since (potentially elsewhere defined) my_mdspan_t has static size m now thinks its range is 10 not 5
181 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
182 __values[__i] == static_cast<_TDynamic>(__static_val),
183 "extents construction: mismatch of provided arguments with static extents.");
Christian Trottfcaccf82023-05-16 19:38:11184 }
185 }
186
187 template <class _Tp, size_t _Size>
188 requires(_Size != __size_dynamic_)
189 _LIBCPP_HIDE_FROM_ABI constexpr __maybe_static_array(const span<_Tp, _Size>& __vals) {
Nikolas Klauser6b4b29f2024-06-18 08:45:30190 static_assert(_Size == __size_ || __size_ == dynamic_extent);
Christian Trottfcaccf82023-05-16 19:38:11191 for (size_t __i = 0; __i < __size_; __i++) {
192 _TStatic __static_val = _StaticValues::__get(__i);
193 if (__static_val == _DynTag) {
194 __dyn_vals_[_DynamicIdxMap::__get(__i)] = static_cast<_TDynamic>(__vals[__i]);
Christian Trott488c3db2023-07-25 18:25:17195 } else
196 // Not catching this could lead to out of bounds errors later
197 // e.g. using my_mdspan_t = mdspan<int, extents<int, 10>>; my_mdspan_t = m(new int[N], span<int,1>(&N));
198 // Right-hand-side construction looks ok with allocation and size matching,
199 // but since (potentially elsewhere defined) my_mdspan_t has static size m now thinks its range is 10 not N
200 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
201 static_cast<_TDynamic>(__vals[__i]) == static_cast<_TDynamic>(__static_val),
202 "extents construction: mismatch of provided arguments with static extents.");
Christian Trottfcaccf82023-05-16 19:38:11203 }
204 }
205
206 // access functions
207 _LIBCPP_HIDE_FROM_ABI static constexpr _TStatic __static_value(size_t __i) noexcept {
varconst4122db12023-07-20 17:13:54208 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__i < __size_, "extents access: index must be less than rank");
Christian Trottfcaccf82023-05-16 19:38:11209 return _StaticValues::__get(__i);
210 }
211
212 _LIBCPP_HIDE_FROM_ABI constexpr _TDynamic __value(size_t __i) const {
varconst4122db12023-07-20 17:13:54213 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__i < __size_, "extents access: index must be less than rank");
Christian Trottfcaccf82023-05-16 19:38:11214 _TStatic __static_val = _StaticValues::__get(__i);
215 return __static_val == _DynTag ? __dyn_vals_[_DynamicIdxMap::__get(__i)] : static_cast<_TDynamic>(__static_val);
216 }
217 _LIBCPP_HIDE_FROM_ABI constexpr _TDynamic operator[](size_t __i) const {
varconst4122db12023-07-20 17:13:54218 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__i < __size_, "extents access: index must be less than rank");
Christian Trottfcaccf82023-05-16 19:38:11219 return __value(__i);
220 }
221
222 // observers
223 _LIBCPP_HIDE_FROM_ABI static constexpr size_t __size() { return __size_; }
224 _LIBCPP_HIDE_FROM_ABI static constexpr size_t __size_dynamic() { return __size_dynamic_; }
225};
226
227// Function to check whether a value is representable as another type
228// value must be a positive integer otherwise returns false
229// if _From is not an integral, we just check positivity
230template <integral _To, class _From>
Christian Trottcfa096d2023-06-29 14:06:47231 requires(integral<_From>)
Christian Trottfcaccf82023-05-16 19:38:11232_LIBCPP_HIDE_FROM_ABI constexpr bool __is_representable_as(_From __value) {
233 using _To_u = make_unsigned_t<_To>;
234 using _From_u = make_unsigned_t<_From>;
235 if constexpr (is_signed_v<_From>) {
236 if (__value < 0)
237 return false;
238 }
239 if constexpr (static_cast<_To_u>(numeric_limits<_To>::max()) >= static_cast<_From_u>(numeric_limits<_From>::max())) {
240 return true;
241 } else {
242 return static_cast<_To_u>(numeric_limits<_To>::max()) >= static_cast<_From_u>(__value);
243 }
244}
245
246template <integral _To, class _From>
Christian Trottcfa096d2023-06-29 14:06:47247 requires(!integral<_From>)
Christian Trottfcaccf82023-05-16 19:38:11248_LIBCPP_HIDE_FROM_ABI constexpr bool __is_representable_as(_From __value) {
249 if constexpr (is_signed_v<_To>) {
250 if (static_cast<_To>(__value) < 0)
251 return false;
252 }
253 return true;
254}
255
256template <integral _To, class... _From>
257_LIBCPP_HIDE_FROM_ABI constexpr bool __are_representable_as(_From... __values) {
258 return (__mdspan_detail::__is_representable_as<_To>(__values) && ... && true);
259}
260
261template <integral _To, class _From, size_t _Size>
262_LIBCPP_HIDE_FROM_ABI constexpr bool __are_representable_as(span<_From, _Size> __values) {
263 for (size_t __i = 0; __i < _Size; __i++)
264 if (!__mdspan_detail::__is_representable_as<_To>(__values[__i]))
265 return false;
266 return true;
267}
268
269} // namespace __mdspan_detail
270
271// ------------------------------------------------------------------
272// ------------ extents ---------------------------------------------
273// ------------------------------------------------------------------
274
275// Class to describe the extents of a multi dimensional array.
276// Used by mdspan, mdarray and layout mappings.
277// See ISO C++ standard [mdspan.extents]
278
279template <class _IndexType, size_t... _Extents>
280class extents {
281public:
282 // typedefs for integral types used
283 using index_type = _IndexType;
284 using size_type = make_unsigned_t<index_type>;
285 using rank_type = size_t;
286
A. Jiang74e70ba2024-08-27 20:41:55287 static_assert(__libcpp_integer<index_type>, "extents::index_type must be a signed or unsigned integer type");
Christian Trottfcaccf82023-05-16 19:38:11288 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 = __mdspan_detail::__maybe_static_array<_IndexType, size_t, dynamic_extent, _Extents...>;
297 [[no_unique_address]] _Values __vals_;
298
299public:
300 // [mdspan.extents.obs], observers of multidimensional index space
301 _LIBCPP_HIDE_FROM_ABI static constexpr rank_type rank() noexcept { return __rank_; }
302 _LIBCPP_HIDE_FROM_ABI static constexpr rank_type rank_dynamic() noexcept { return __rank_dynamic_; }
303
304 _LIBCPP_HIDE_FROM_ABI constexpr index_type extent(rank_type __r) const noexcept { return __vals_.__value(__r); }
305 _LIBCPP_HIDE_FROM_ABI static constexpr size_t static_extent(rank_type __r) noexcept {
306 return _Values::__static_value(__r);
307 }
308
309 // [mdspan.extents.cons], constructors
310 _LIBCPP_HIDE_FROM_ABI constexpr extents() noexcept = default;
311
312 // Construction from just dynamic or all values.
313 // Precondition check is deferred to __maybe_static_array constructor
314 template <class... _OtherIndexTypes>
315 requires((is_convertible_v<_OtherIndexTypes, index_type> && ...) &&
316 (is_nothrow_constructible_v<index_type, _OtherIndexTypes> && ...) &&
317 (sizeof...(_OtherIndexTypes) == __rank_ || sizeof...(_OtherIndexTypes) == __rank_dynamic_))
318 _LIBCPP_HIDE_FROM_ABI constexpr explicit extents(_OtherIndexTypes... __dynvals) noexcept
319 : __vals_(static_cast<index_type>(__dynvals)...) {
Christian Trott488c3db2023-07-25 18:25:17320 // Not catching this could lead to out of bounds errors later
321 // e.g. mdspan m(ptr, dextents<char, 1>(200u)); leads to an extent of -56 on m
322 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__mdspan_detail::__are_representable_as<index_type>(__dynvals...),
323 "extents ctor: arguments must be representable as index_type and nonnegative");
Christian Trottfcaccf82023-05-16 19:38:11324 }
325
326 template <class _OtherIndexType, size_t _Size>
Christian Trottfc487652023-07-25 04:35:15327 requires(is_convertible_v<const _OtherIndexType&, index_type> &&
328 is_nothrow_constructible_v<index_type, const _OtherIndexType&> &&
Christian Trottfcaccf82023-05-16 19:38:11329 (_Size == __rank_ || _Size == __rank_dynamic_))
330 explicit(_Size != __rank_dynamic_)
331 _LIBCPP_HIDE_FROM_ABI constexpr extents(const array<_OtherIndexType, _Size>& __exts) noexcept
332 : __vals_(span(__exts)) {
Christian Trott488c3db2023-07-25 18:25:17333 // Not catching this could lead to out of bounds errors later
334 // e.g. mdspan m(ptr, dextents<char, 1>(array<unsigned,1>(200))); leads to an extent of -56 on m
335 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__mdspan_detail::__are_representable_as<index_type>(span(__exts)),
336 "extents ctor: arguments must be representable as index_type and nonnegative");
Christian Trottfcaccf82023-05-16 19:38:11337 }
338
339 template <class _OtherIndexType, size_t _Size>
Christian Trottfc487652023-07-25 04:35:15340 requires(is_convertible_v<const _OtherIndexType&, index_type> &&
341 is_nothrow_constructible_v<index_type, const _OtherIndexType&> &&
Christian Trottfcaccf82023-05-16 19:38:11342 (_Size == __rank_ || _Size == __rank_dynamic_))
343 explicit(_Size != __rank_dynamic_)
344 _LIBCPP_HIDE_FROM_ABI constexpr extents(const span<_OtherIndexType, _Size>& __exts) noexcept
345 : __vals_(__exts) {
Christian Trott488c3db2023-07-25 18:25:17346 // Not catching this could lead to out of bounds errors later
347 // e.g. array a{200u}; mdspan<int, dextents<char,1>> m(ptr, extents(span<unsigned,1>(a))); leads to an extent of -56
348 // on m
349 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__mdspan_detail::__are_representable_as<index_type>(__exts),
350 "extents ctor: arguments must be representable as index_type and nonnegative");
Christian Trottfcaccf82023-05-16 19:38:11351 }
352
353private:
354 // Function to construct extents storage from other extents.
355 template <size_t _DynCount, size_t _Idx, class _OtherExtents, class... _DynamicValues>
356 requires(_Idx < __rank_)
357 _LIBCPP_HIDE_FROM_ABI constexpr _Values __construct_vals_from_extents(
358 integral_constant<size_t, _DynCount>,
359 integral_constant<size_t, _Idx>,
360 const _OtherExtents& __exts,
361 _DynamicValues... __dynamic_values) noexcept {
362 if constexpr (static_extent(_Idx) == dynamic_extent)
363 return __construct_vals_from_extents(
364 integral_constant<size_t, _DynCount + 1>(),
365 integral_constant<size_t, _Idx + 1>(),
366 __exts,
367 __dynamic_values...,
368 __exts.extent(_Idx));
369 else
370 return __construct_vals_from_extents(
371 integral_constant<size_t, _DynCount>(), integral_constant<size_t, _Idx + 1>(), __exts, __dynamic_values...);
372 }
373
374 template <size_t _DynCount, size_t _Idx, class _OtherExtents, class... _DynamicValues>
375 requires((_Idx == __rank_) && (_DynCount == __rank_dynamic_))
376 _LIBCPP_HIDE_FROM_ABI constexpr _Values __construct_vals_from_extents(
377 integral_constant<size_t, _DynCount>,
378 integral_constant<size_t, _Idx>,
379 const _OtherExtents&,
380 _DynamicValues... __dynamic_values) noexcept {
381 return _Values{static_cast<index_type>(__dynamic_values)...};
382 }
383
384public:
385 // Converting constructor from other extents specializations
386 template <class _OtherIndexType, size_t... _OtherExtents>
387 requires((sizeof...(_OtherExtents) == sizeof...(_Extents)) &&
388 ((_OtherExtents == dynamic_extent || _Extents == dynamic_extent || _OtherExtents == _Extents) && ...))
389 explicit((((_Extents != dynamic_extent) && (_OtherExtents == dynamic_extent)) || ...) ||
390 (static_cast<make_unsigned_t<index_type>>(numeric_limits<index_type>::max()) <
391 static_cast<make_unsigned_t<_OtherIndexType>>(numeric_limits<_OtherIndexType>::max())))
392 _LIBCPP_HIDE_FROM_ABI constexpr extents(const extents<_OtherIndexType, _OtherExtents...>& __other) noexcept
393 : __vals_(
394 __construct_vals_from_extents(integral_constant<size_t, 0>(), integral_constant<size_t, 0>(), __other)) {
395 if constexpr (rank() > 0) {
396 for (size_t __r = 0; __r < rank(); __r++) {
397 if constexpr (static_cast<make_unsigned_t<index_type>>(numeric_limits<index_type>::max()) <
398 static_cast<make_unsigned_t<_OtherIndexType>>(numeric_limits<_OtherIndexType>::max())) {
Christian Trott488c3db2023-07-25 18:25:17399 // Not catching this could lead to out of bounds errors later
400 // e.g. dextents<char,1>> e(dextents<unsigned,1>(200)) leads to an extent of -56 on e
401 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
402 __mdspan_detail::__is_representable_as<index_type>(__other.extent(__r)),
403 "extents ctor: arguments must be representable as index_type and nonnegative");
Christian Trottfcaccf82023-05-16 19:38:11404 }
Christian Trott488c3db2023-07-25 18:25:17405 // Not catching this could lead to out of bounds errors later
406 // e.g. mdspan<int, extents<int, 10>> m = mdspan<int, dextents<int, 1>>(new int[5], 5);
407 // Right-hand-side construction was ok, but m now thinks its range is 10 not 5
408 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
Christian Trottfcaccf82023-05-16 19:38:11409 (_Values::__static_value(__r) == dynamic_extent) ||
410 (static_cast<index_type>(__other.extent(__r)) == static_cast<index_type>(_Values::__static_value(__r))),
411 "extents construction: mismatch of provided arguments with static extents.");
412 }
413 }
414 }
415
416 // Comparison operator
417 template <class _OtherIndexType, size_t... _OtherExtents>
418 _LIBCPP_HIDE_FROM_ABI friend constexpr bool
419 operator==(const extents& __lhs, const extents<_OtherIndexType, _OtherExtents...>& __rhs) noexcept {
420 if constexpr (rank() != sizeof...(_OtherExtents)) {
421 return false;
422 } else {
423 for (rank_type __r = 0; __r < __rank_; __r++) {
424 // avoid warning when comparing signed and unsigner integers and pick the wider of two types
425 using _CommonType = common_type_t<index_type, _OtherIndexType>;
426 if (static_cast<_CommonType>(__lhs.extent(__r)) != static_cast<_CommonType>(__rhs.extent(__r))) {
427 return false;
428 }
429 }
430 }
431 return true;
432 }
433};
434
435// Recursive helper classes to implement dextents alias for extents
436namespace __mdspan_detail {
437
438template <class _IndexType, size_t _Rank, class _Extents = extents<_IndexType>>
439struct __make_dextents;
440
441template <class _IndexType, size_t _Rank, size_t... _ExtentsPack>
442struct __make_dextents< _IndexType, _Rank, extents<_IndexType, _ExtentsPack...>> {
443 using type =
444 typename __make_dextents< _IndexType, _Rank - 1, extents<_IndexType, dynamic_extent, _ExtentsPack...>>::type;
445};
446
447template <class _IndexType, size_t... _ExtentsPack>
448struct __make_dextents< _IndexType, 0, extents<_IndexType, _ExtentsPack...>> {
449 using type = extents<_IndexType, _ExtentsPack...>;
450};
451
Louis Dionne953af0e2024-09-05 16:39:05452} // namespace __mdspan_detail
Christian Trottfcaccf82023-05-16 19:38:11453
454// [mdspan.extents.dextents], alias template
455template <class _IndexType, size_t _Rank>
456using dextents = typename __mdspan_detail::__make_dextents<_IndexType, _Rank>::type;
457
Xiaoyang Liu4e338dc2024-07-15 15:23:34458# if _LIBCPP_STD_VER >= 26
459// [mdspan.extents.dims], alias template `dims`
460template <size_t _Rank, class _IndexType = size_t>
461using dims = dextents<_IndexType, _Rank>;
462# endif
463
Christian Trottfcaccf82023-05-16 19:38:11464// Deduction guide for extents
Xiaoyang Liu8c11d372024-06-25 15:20:14465# if _LIBCPP_STD_VER >= 26
Christian Trottfcaccf82023-05-16 19:38:11466template <class... _IndexTypes>
Xiaoyang Liu8c11d372024-06-25 15:20:14467 requires(is_convertible_v<_IndexTypes, size_t> && ...)
468explicit extents(_IndexTypes...) -> extents<size_t, __maybe_static_ext<_IndexTypes>...>;
469# else
470template <class... _IndexTypes>
471 requires(is_convertible_v<_IndexTypes, size_t> && ...)
472explicit extents(_IndexTypes...) -> extents<size_t, size_t(((void)sizeof(_IndexTypes), dynamic_extent))...>;
473# endif
Christian Trottfcaccf82023-05-16 19:38:11474
Christian Trottfcaccf82023-05-16 19:38:11475namespace __mdspan_detail {
476
Christian Trottcfa096d2023-06-29 14:06:47477// Helper type traits for identifying a class as extents.
Christian Trottfcaccf82023-05-16 19:38:11478template <class _Tp>
479struct __is_extents : false_type {};
480
481template <class _IndexType, size_t... _ExtentsPack>
482struct __is_extents<extents<_IndexType, _ExtentsPack...>> : true_type {};
483
484template <class _Tp>
485inline constexpr bool __is_extents_v = __is_extents<_Tp>::value;
486
Christian Trottcfa096d2023-06-29 14:06:47487// Function to check whether a set of indices are a multidimensional
488// index into extents. This is a word of power in the C++ standard
489// requiring that the indices are larger than 0 and smaller than
490// the respective extents.
491
492template <integral _IndexType, class _From>
493 requires(integral<_From>)
494_LIBCPP_HIDE_FROM_ABI constexpr bool __is_index_in_extent(_IndexType __extent, _From __value) {
495 if constexpr (is_signed_v<_From>) {
496 if (__value < 0)
497 return false;
498 }
499 using _Tp = common_type_t<_IndexType, _From>;
500 return static_cast<_Tp>(__value) < static_cast<_Tp>(__extent);
501}
502
503template <integral _IndexType, class _From>
504 requires(!integral<_From>)
505_LIBCPP_HIDE_FROM_ABI constexpr bool __is_index_in_extent(_IndexType __extent, _From __value) {
506 if constexpr (is_signed_v<_IndexType>) {
507 if (static_cast<_IndexType>(__value) < 0)
508 return false;
509 }
510 return static_cast<_IndexType>(__value) < __extent;
511}
512
513template <size_t... _Idxs, class _Extents, class... _From>
514_LIBCPP_HIDE_FROM_ABI constexpr bool
515__is_multidimensional_index_in_impl(index_sequence<_Idxs...>, const _Extents& __ext, _From... __values) {
516 return (__mdspan_detail::__is_index_in_extent(__ext.extent(_Idxs), __values) && ...);
517}
518
519template <class _Extents, class... _From>
520_LIBCPP_HIDE_FROM_ABI constexpr bool __is_multidimensional_index_in(const _Extents& __ext, _From... __values) {
521 return __mdspan_detail::__is_multidimensional_index_in_impl(
522 make_index_sequence<_Extents::rank()>(), __ext, __values...);
523}
524
Christian Trottfcaccf82023-05-16 19:38:11525} // namespace __mdspan_detail
526
527#endif // _LIBCPP_STD_VER >= 23
528
529_LIBCPP_END_NAMESPACE_STD
530
531_LIBCPP_POP_MACROS
532
533#endif // _LIBCPP___MDSPAN_EXTENTS_H