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: __size__static_array58 _LIBCPP_HIDE_FROM_ABI static constexpr size_t __size() { return sizeof...(_Values); } __get__static_array59 _LIBCPP_HIDE_FROM_ABI static constexpr _Tp __get(size_t __index) noexcept { return __array[__index]; } 60 61 template <size_t _Index> __get__static_array62 _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