Warning: This file is not a C or C++ file. It does not have highlighting.
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/make_unsigned.h> |
29 | #include <__utility/integer_sequence.h> |
30 | #include <__utility/unreachable.h> |
31 | #include <array> |
32 | #include <concepts> |
33 | #include <limits> |
34 | #include <span> |
35 | |
36 | #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) |
37 | # pragma GCC system_header |
38 | #endif |
39 | |
40 | _LIBCPP_PUSH_MACROS |
41 | #include <__undef_macros> |
42 | |
43 | _LIBCPP_BEGIN_NAMESPACE_STD |
44 | |
45 | #if _LIBCPP_STD_VER >= 23 |
46 | |
47 | namespace __mdspan_detail { |
48 | |
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...}; |
56 | |
57 | public: |
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]; } |
60 | |
61 | template <size_t _Index> |
62 | _LIBCPP_HIDE_FROM_ABI static constexpr _Tp __get() { |
63 | return __get(_Index); |
64 | } |
65 | }; |
66 | |
67 | // ------------------------------------------------------------------ |
68 | // ------------ __possibly_empty_array ----------------------------- |
69 | // ------------------------------------------------------------------ |
70 | |
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 |
74 | // all static values. |
75 | |
76 | template <class _Tp, size_t _Size> |
77 | struct __possibly_empty_array { |
78 | _Tp __vals_[_Size]; |
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]; } |
81 | }; |
82 | |
83 | template <class _Tp> |
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(); } |
87 | }; |
88 | |
89 | // ------------------------------------------------------------------ |
90 | // ------------ static_partial_sums --------------------------------- |
91 | // ------------------------------------------------------------------ |
92 | |
93 | // Provides a compile time partial sum one can index into |
94 | |
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]; |
104 | } |
105 | return __partial_sums; |
106 | } |
107 | static constexpr array<size_t, sizeof...(_Values)> __result{__static_partial_sums_impl()}; |
108 | |
109 | _LIBCPP_HIDE_FROM_ABI static constexpr size_t __get(size_t __index) { return __result[__index]; } |
110 | }; |
111 | |
112 | // ------------------------------------------------------------------ |
113 | // ------------ __maybe_static_array -------------------------------- |
114 | // ------------------------------------------------------------------ |
115 | |
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"); |
126 | |
127 | private: |
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 _LIBCPP_NODEBUG = __static_array<_TStatic, _Values...>; |
132 | using _DynamicValues _LIBCPP_NODEBUG = __possibly_empty_array<_TDynamic, __size_dynamic_>; |
133 | |
134 | // Dynamic values member |
135 | _LIBCPP_NO_UNIQUE_ADDRESS _DynamicValues __dyn_vals_; |
136 | |
137 | // static mapping of indices to the position in the dynamic values array |
138 | using _DynamicIdxMap _LIBCPP_NODEBUG = __static_partial_sums<static_cast<size_t>(_Values == _DynTag)...>; |
139 | |
140 | template <size_t... _Indices> |
141 | _LIBCPP_HIDE_FROM_ABI static constexpr _DynamicValues __zeros(index_sequence<_Indices...>) noexcept { |
142 | return _DynamicValues{((void)_Indices, 0)...}; |
143 | } |
144 | |
145 | public: |
146 | _LIBCPP_HIDE_FROM_ABI constexpr __maybe_static_array() noexcept |
147 | : __dyn_vals_{__zeros(make_index_sequence<__size_dynamic_>())} {} |
148 | |
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)...} {} |
154 | |
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]); |
161 | } |
162 | } |
163 | |
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]; |
174 | } else |
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."); |
182 | } |
183 | } |
184 | |
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]); |
193 | } else |
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."); |
201 | } |
202 | } |
203 | |
204 | // access functions |
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); |
208 | } |
209 | |
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); |
214 | } |
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"); |
217 | return __value(__i); |
218 | } |
219 | |
220 | // observers |
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_; } |
223 | }; |
224 | |
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>) { |
234 | if (__value < 0) |
235 | return false; |
236 | } |
237 | if constexpr (static_cast<_To_u>(numeric_limits<_To>::max()) >= static_cast<_From_u>(numeric_limits<_From>::max())) { |
238 | return true; |
239 | } else { |
240 | return static_cast<_To_u>(numeric_limits<_To>::max()) >= static_cast<_From_u>(__value); |
241 | } |
242 | } |
243 | |
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) |
249 | return false; |
250 | } |
251 | return true; |
252 | } |
253 | |
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); |
257 | } |
258 | |
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])) |
263 | return false; |
264 | return true; |
265 | } |
266 | |
267 | } // namespace __mdspan_detail |
268 | |
269 | // ------------------------------------------------------------------ |
270 | // ------------ extents --------------------------------------------- |
271 | // ------------------------------------------------------------------ |
272 | |
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] |
276 | |
277 | template <class _IndexType, size_t... _Extents> |
278 | class extents { |
279 | public: |
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; |
284 | |
285 | static_assert(__signed_or_unsigned_integer<index_type>, |
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"); |
289 | |
290 | private: |
291 | static constexpr rank_type __rank_ = sizeof...(_Extents); |
292 | static constexpr rank_type __rank_dynamic_ = ((_Extents == dynamic_extent) + ... + 0); |
293 | |
294 | // internal storage type using __maybe_static_array |
295 | using _Values _LIBCPP_NODEBUG = |
296 | __mdspan_detail::__maybe_static_array<_IndexType, size_t, dynamic_extent, _Extents...>; |
297 | [[no_unique_address]] _Values __vals_; |
298 | |
299 | public: |
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)...) { |
320 | // 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"); |
324 | } |
325 | |
326 | template <class _OtherIndexType, size_t _Size> |
327 | requires(is_convertible_v<const _OtherIndexType&, index_type> && |
328 | is_nothrow_constructible_v<index_type, const _OtherIndexType&> && |
329 | (_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)) { |
333 | // 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"); |
337 | } |
338 | |
339 | template <class _OtherIndexType, size_t _Size> |
340 | requires(is_convertible_v<const _OtherIndexType&, index_type> && |
341 | is_nothrow_constructible_v<index_type, const _OtherIndexType&> && |
342 | (_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) { |
346 | // 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"); |
351 | } |
352 | |
353 | private: |
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 | |
384 | public: |
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())) { |
399 | // 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"); |
404 | } |
405 | // 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( |
409 | (_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 |
436 | namespace __mdspan_detail { |
437 | |
438 | template <class _IndexType, size_t _Rank, class _Extents = extents<_IndexType>> |
439 | struct __make_dextents; |
440 | |
441 | template <class _IndexType, size_t _Rank, size_t... _ExtentsPack> |
442 | struct __make_dextents< _IndexType, _Rank, extents<_IndexType, _ExtentsPack...>> { |
443 | using type _LIBCPP_NODEBUG = |
444 | typename __make_dextents< _IndexType, _Rank - 1, extents<_IndexType, dynamic_extent, _ExtentsPack...>>::type; |
445 | }; |
446 | |
447 | template <class _IndexType, size_t... _ExtentsPack> |
448 | struct __make_dextents< _IndexType, 0, extents<_IndexType, _ExtentsPack...>> { |
449 | using type _LIBCPP_NODEBUG = extents<_IndexType, _ExtentsPack...>; |
450 | }; |
451 | |
452 | } // namespace __mdspan_detail |
453 | |
454 | // [mdspan.extents.dextents], alias template |
455 | template <class _IndexType, size_t _Rank> |
456 | using dextents = typename __mdspan_detail::__make_dextents<_IndexType, _Rank>::type; |
457 | |
458 | # if _LIBCPP_STD_VER >= 26 |
459 | // [mdspan.extents.dims], alias template `dims` |
460 | template <size_t _Rank, class _IndexType = size_t> |
461 | using dims = dextents<_IndexType, _Rank>; |
462 | # endif |
463 | |
464 | // Deduction guide for extents |
465 | # if _LIBCPP_STD_VER >= 26 |
466 | template <class... _IndexTypes> |
467 | requires(is_convertible_v<_IndexTypes, size_t> && ...) |
468 | explicit extents(_IndexTypes...) -> extents<size_t, __maybe_static_ext<_IndexTypes>...>; |
469 | # else |
470 | template <class... _IndexTypes> |
471 | requires(is_convertible_v<_IndexTypes, size_t> && ...) |
472 | explicit extents(_IndexTypes...) -> extents<size_t, size_t(((void)sizeof(_IndexTypes), dynamic_extent))...>; |
473 | # endif |
474 | |
475 | namespace __mdspan_detail { |
476 | |
477 | // Helper type traits for identifying a class as extents. |
478 | template <class _Tp> |
479 | struct __is_extents : false_type {}; |
480 | |
481 | template <class _IndexType, size_t... _ExtentsPack> |
482 | struct __is_extents<extents<_IndexType, _ExtentsPack...>> : true_type {}; |
483 | |
484 | template <class _Tp> |
485 | inline constexpr bool __is_extents_v = __is_extents<_Tp>::value; |
486 | |
487 | // 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 | |
492 | template <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 | |
503 | template <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 | |
513 | template <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 | |
519 | template <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 | |
525 | } // 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 |
534 |
Warning: This file is not a C or C++ file. It does not have highlighting.