extents.h 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  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. #ifndef _LIBCPP___MDSPAN_EXTENTS_H
  17. #define _LIBCPP___MDSPAN_EXTENTS_H
  18. #include <__assert>
  19. #include <__config>
  20. #include <__type_traits/common_type.h>
  21. #include <__type_traits/is_convertible.h>
  22. #include <__type_traits/is_nothrow_constructible.h>
  23. #include <__type_traits/is_same.h>
  24. #include <__type_traits/make_unsigned.h>
  25. #include <__utility/integer_sequence.h>
  26. #include <__utility/unreachable.h>
  27. #include <array>
  28. #include <cinttypes>
  29. #include <concepts>
  30. #include <cstddef>
  31. #include <limits>
  32. #include <span>
  33. #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
  34. # pragma GCC system_header
  35. #endif
  36. _LIBCPP_PUSH_MACROS
  37. #include <__undef_macros>
  38. _LIBCPP_BEGIN_NAMESPACE_STD
  39. #if _LIBCPP_STD_VER >= 23
  40. namespace __mdspan_detail {
  41. // ------------------------------------------------------------------
  42. // ------------ __static_array --------------------------------------
  43. // ------------------------------------------------------------------
  44. // array like class which provides an array of static values with get
  45. template <class _Tp, _Tp... _Values>
  46. struct __static_array {
  47. static constexpr array<_Tp, sizeof...(_Values)> __array = {_Values...};
  48. public:
  49. _LIBCPP_HIDE_FROM_ABI static constexpr size_t __size() { return sizeof...(_Values); }
  50. _LIBCPP_HIDE_FROM_ABI static constexpr _Tp __get(size_t __index) noexcept { return __array[__index]; }
  51. template <size_t _Index>
  52. _LIBCPP_HIDE_FROM_ABI static constexpr _Tp __get() {
  53. return __get(_Index);
  54. }
  55. };
  56. // ------------------------------------------------------------------
  57. // ------------ __possibly_empty_array -----------------------------
  58. // ------------------------------------------------------------------
  59. // array like class which provides get function and operator [], and
  60. // has a specialization for the size 0 case.
  61. // This is needed to make the __maybe_static_array be truly empty, for
  62. // all static values.
  63. template <class _Tp, size_t _Size>
  64. struct __possibly_empty_array {
  65. _Tp __vals_[_Size];
  66. _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator[](size_t __index) { return __vals_[__index]; }
  67. _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator[](size_t __index) const { return __vals_[__index]; }
  68. };
  69. template <class _Tp>
  70. struct __possibly_empty_array<_Tp, 0> {
  71. _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator[](size_t) { __libcpp_unreachable(); }
  72. _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator[](size_t) const { __libcpp_unreachable(); }
  73. };
  74. // ------------------------------------------------------------------
  75. // ------------ static_partial_sums ---------------------------------
  76. // ------------------------------------------------------------------
  77. // Provides a compile time partial sum one can index into
  78. template <size_t... _Values>
  79. struct __static_partial_sums {
  80. _LIBCPP_HIDE_FROM_ABI static constexpr array<size_t, sizeof...(_Values)> __static_partial_sums_impl() {
  81. array<size_t, sizeof...(_Values)> __values{_Values...};
  82. array<size_t, sizeof...(_Values)> __partial_sums{{}};
  83. size_t __running_sum = 0;
  84. for (int __i = 0; __i != sizeof...(_Values); ++__i) {
  85. __partial_sums[__i] = __running_sum;
  86. __running_sum += __values[__i];
  87. }
  88. return __partial_sums;
  89. }
  90. static constexpr array<size_t, sizeof...(_Values)> __result{__static_partial_sums_impl()};
  91. _LIBCPP_HIDE_FROM_ABI static constexpr size_t __get(size_t __index) { return __result[__index]; }
  92. };
  93. // ------------------------------------------------------------------
  94. // ------------ __maybe_static_array --------------------------------
  95. // ------------------------------------------------------------------
  96. // array like class which has a mix of static and runtime values but
  97. // only stores the runtime values.
  98. // The type of the static and the runtime values can be different.
  99. // The position of a dynamic value is indicated through a tag value.
  100. template <class _TDynamic, class _TStatic, _TStatic _DynTag, _TStatic... _Values>
  101. struct __maybe_static_array {
  102. static_assert(is_convertible<_TStatic, _TDynamic>::value,
  103. "__maybe_static_array: _TStatic must be convertible to _TDynamic");
  104. static_assert(is_convertible<_TDynamic, _TStatic>::value,
  105. "__maybe_static_array: _TDynamic must be convertible to _TStatic");
  106. private:
  107. // Static values member
  108. static constexpr size_t __size_ = sizeof...(_Values);
  109. static constexpr size_t __size_dynamic_ = ((_Values == _DynTag) + ... + 0);
  110. using _StaticValues = __static_array<_TStatic, _Values...>;
  111. using _DynamicValues = __possibly_empty_array<_TDynamic, __size_dynamic_>;
  112. // Dynamic values member
  113. _LIBCPP_NO_UNIQUE_ADDRESS _DynamicValues __dyn_vals_;
  114. // static mapping of indices to the position in the dynamic values array
  115. using _DynamicIdxMap = __static_partial_sums<static_cast<size_t>(_Values == _DynTag)...>;
  116. template <size_t... Indices>
  117. _LIBCPP_HIDE_FROM_ABI static constexpr _DynamicValues __zeros(index_sequence<Indices...>) noexcept {
  118. return _DynamicValues{((void)Indices, 0)...};
  119. }
  120. public:
  121. _LIBCPP_HIDE_FROM_ABI constexpr __maybe_static_array() noexcept
  122. : __dyn_vals_{__zeros(make_index_sequence<__size_dynamic_>())} {}
  123. // constructors from dynamic values only -- this covers the case for rank() == 0
  124. template <class... _DynVals>
  125. requires(sizeof...(_DynVals) == __size_dynamic_)
  126. _LIBCPP_HIDE_FROM_ABI constexpr __maybe_static_array(_DynVals... __vals)
  127. : __dyn_vals_{static_cast<_TDynamic>(__vals)...} {}
  128. template <class _Tp, size_t _Size >
  129. requires(_Size == __size_dynamic_)
  130. _LIBCPP_HIDE_FROM_ABI constexpr __maybe_static_array([[maybe_unused]] const span<_Tp, _Size>& __vals) {
  131. if constexpr (_Size > 0) {
  132. for (size_t __i = 0; __i < _Size; __i++)
  133. __dyn_vals_[__i] = static_cast<_TDynamic>(__vals[__i]);
  134. }
  135. }
  136. // constructors from all values -- here rank will be greater than 0
  137. template <class... _DynVals>
  138. requires(sizeof...(_DynVals) != __size_dynamic_)
  139. _LIBCPP_HIDE_FROM_ABI constexpr __maybe_static_array(_DynVals... __vals) {
  140. static_assert((sizeof...(_DynVals) == __size_), "Invalid number of values.");
  141. _TDynamic __values[__size_] = {static_cast<_TDynamic>(__vals)...};
  142. for (size_t __i = 0; __i < __size_; __i++) {
  143. _TStatic __static_val = _StaticValues::__get(__i);
  144. if (__static_val == _DynTag) {
  145. __dyn_vals_[_DynamicIdxMap::__get(__i)] = __values[__i];
  146. } else
  147. // Not catching this could lead to out of bounds errors later
  148. // e.g. using my_mdspan_t = mdspan<int, extents<int, 10>>; my_mdspan_t = m(new int[5], 5);
  149. // Right-hand-side construction looks ok with allocation and size matching,
  150. // but since (potentially elsewhere defined) my_mdspan_t has static size m now thinks its range is 10 not 5
  151. _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
  152. __values[__i] == static_cast<_TDynamic>(__static_val),
  153. "extents construction: mismatch of provided arguments with static extents.");
  154. }
  155. }
  156. template <class _Tp, size_t _Size>
  157. requires(_Size != __size_dynamic_)
  158. _LIBCPP_HIDE_FROM_ABI constexpr __maybe_static_array(const span<_Tp, _Size>& __vals) {
  159. static_assert((_Size == __size_) || (__size_ == dynamic_extent));
  160. for (size_t __i = 0; __i < __size_; __i++) {
  161. _TStatic __static_val = _StaticValues::__get(__i);
  162. if (__static_val == _DynTag) {
  163. __dyn_vals_[_DynamicIdxMap::__get(__i)] = static_cast<_TDynamic>(__vals[__i]);
  164. } else
  165. // Not catching this could lead to out of bounds errors later
  166. // e.g. using my_mdspan_t = mdspan<int, extents<int, 10>>; my_mdspan_t = m(new int[N], span<int,1>(&N));
  167. // Right-hand-side construction looks ok with allocation and size matching,
  168. // but since (potentially elsewhere defined) my_mdspan_t has static size m now thinks its range is 10 not N
  169. _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
  170. static_cast<_TDynamic>(__vals[__i]) == static_cast<_TDynamic>(__static_val),
  171. "extents construction: mismatch of provided arguments with static extents.");
  172. }
  173. }
  174. // access functions
  175. _LIBCPP_HIDE_FROM_ABI static constexpr _TStatic __static_value(size_t __i) noexcept {
  176. _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__i < __size_, "extents access: index must be less than rank");
  177. return _StaticValues::__get(__i);
  178. }
  179. _LIBCPP_HIDE_FROM_ABI constexpr _TDynamic __value(size_t __i) const {
  180. _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__i < __size_, "extents access: index must be less than rank");
  181. _TStatic __static_val = _StaticValues::__get(__i);
  182. return __static_val == _DynTag ? __dyn_vals_[_DynamicIdxMap::__get(__i)] : static_cast<_TDynamic>(__static_val);
  183. }
  184. _LIBCPP_HIDE_FROM_ABI constexpr _TDynamic operator[](size_t __i) const {
  185. _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__i < __size_, "extents access: index must be less than rank");
  186. return __value(__i);
  187. }
  188. // observers
  189. _LIBCPP_HIDE_FROM_ABI static constexpr size_t __size() { return __size_; }
  190. _LIBCPP_HIDE_FROM_ABI static constexpr size_t __size_dynamic() { return __size_dynamic_; }
  191. };
  192. // Function to check whether a value is representable as another type
  193. // value must be a positive integer otherwise returns false
  194. // if _From is not an integral, we just check positivity
  195. template <integral _To, class _From>
  196. requires(integral<_From>)
  197. _LIBCPP_HIDE_FROM_ABI constexpr bool __is_representable_as(_From __value) {
  198. using _To_u = make_unsigned_t<_To>;
  199. using _From_u = make_unsigned_t<_From>;
  200. if constexpr (is_signed_v<_From>) {
  201. if (__value < 0)
  202. return false;
  203. }
  204. if constexpr (static_cast<_To_u>(numeric_limits<_To>::max()) >= static_cast<_From_u>(numeric_limits<_From>::max())) {
  205. return true;
  206. } else {
  207. return static_cast<_To_u>(numeric_limits<_To>::max()) >= static_cast<_From_u>(__value);
  208. }
  209. }
  210. template <integral _To, class _From>
  211. requires(!integral<_From>)
  212. _LIBCPP_HIDE_FROM_ABI constexpr bool __is_representable_as(_From __value) {
  213. if constexpr (is_signed_v<_To>) {
  214. if (static_cast<_To>(__value) < 0)
  215. return false;
  216. }
  217. return true;
  218. }
  219. template <integral _To, class... _From>
  220. _LIBCPP_HIDE_FROM_ABI constexpr bool __are_representable_as(_From... __values) {
  221. return (__mdspan_detail::__is_representable_as<_To>(__values) && ... && true);
  222. }
  223. template <integral _To, class _From, size_t _Size>
  224. _LIBCPP_HIDE_FROM_ABI constexpr bool __are_representable_as(span<_From, _Size> __values) {
  225. for (size_t __i = 0; __i < _Size; __i++)
  226. if (!__mdspan_detail::__is_representable_as<_To>(__values[__i]))
  227. return false;
  228. return true;
  229. }
  230. } // namespace __mdspan_detail
  231. // ------------------------------------------------------------------
  232. // ------------ extents ---------------------------------------------
  233. // ------------------------------------------------------------------
  234. // Class to describe the extents of a multi dimensional array.
  235. // Used by mdspan, mdarray and layout mappings.
  236. // See ISO C++ standard [mdspan.extents]
  237. template <class _IndexType, size_t... _Extents>
  238. class extents {
  239. public:
  240. // typedefs for integral types used
  241. using index_type = _IndexType;
  242. using size_type = make_unsigned_t<index_type>;
  243. using rank_type = size_t;
  244. static_assert(is_integral<index_type>::value && !is_same<index_type, bool>::value,
  245. "extents::index_type must be a signed or unsigned integer type");
  246. static_assert(((__mdspan_detail::__is_representable_as<index_type>(_Extents) || (_Extents == dynamic_extent)) && ...),
  247. "extents ctor: arguments must be representable as index_type and nonnegative");
  248. private:
  249. static constexpr rank_type __rank_ = sizeof...(_Extents);
  250. static constexpr rank_type __rank_dynamic_ = ((_Extents == dynamic_extent) + ... + 0);
  251. // internal storage type using __maybe_static_array
  252. using _Values = __mdspan_detail::__maybe_static_array<_IndexType, size_t, dynamic_extent, _Extents...>;
  253. [[no_unique_address]] _Values __vals_;
  254. public:
  255. // [mdspan.extents.obs], observers of multidimensional index space
  256. _LIBCPP_HIDE_FROM_ABI static constexpr rank_type rank() noexcept { return __rank_; }
  257. _LIBCPP_HIDE_FROM_ABI static constexpr rank_type rank_dynamic() noexcept { return __rank_dynamic_; }
  258. _LIBCPP_HIDE_FROM_ABI constexpr index_type extent(rank_type __r) const noexcept { return __vals_.__value(__r); }
  259. _LIBCPP_HIDE_FROM_ABI static constexpr size_t static_extent(rank_type __r) noexcept {
  260. return _Values::__static_value(__r);
  261. }
  262. // [mdspan.extents.cons], constructors
  263. _LIBCPP_HIDE_FROM_ABI constexpr extents() noexcept = default;
  264. // Construction from just dynamic or all values.
  265. // Precondition check is deferred to __maybe_static_array constructor
  266. template <class... _OtherIndexTypes>
  267. requires((is_convertible_v<_OtherIndexTypes, index_type> && ...) &&
  268. (is_nothrow_constructible_v<index_type, _OtherIndexTypes> && ...) &&
  269. (sizeof...(_OtherIndexTypes) == __rank_ || sizeof...(_OtherIndexTypes) == __rank_dynamic_))
  270. _LIBCPP_HIDE_FROM_ABI constexpr explicit extents(_OtherIndexTypes... __dynvals) noexcept
  271. : __vals_(static_cast<index_type>(__dynvals)...) {
  272. // Not catching this could lead to out of bounds errors later
  273. // e.g. mdspan m(ptr, dextents<char, 1>(200u)); leads to an extent of -56 on m
  274. _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__mdspan_detail::__are_representable_as<index_type>(__dynvals...),
  275. "extents ctor: arguments must be representable as index_type and nonnegative");
  276. }
  277. template <class _OtherIndexType, size_t _Size>
  278. requires(is_convertible_v<const _OtherIndexType&, index_type> &&
  279. is_nothrow_constructible_v<index_type, const _OtherIndexType&> &&
  280. (_Size == __rank_ || _Size == __rank_dynamic_))
  281. explicit(_Size != __rank_dynamic_)
  282. _LIBCPP_HIDE_FROM_ABI constexpr extents(const array<_OtherIndexType, _Size>& __exts) noexcept
  283. : __vals_(span(__exts)) {
  284. // Not catching this could lead to out of bounds errors later
  285. // e.g. mdspan m(ptr, dextents<char, 1>(array<unsigned,1>(200))); leads to an extent of -56 on m
  286. _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__mdspan_detail::__are_representable_as<index_type>(span(__exts)),
  287. "extents ctor: arguments must be representable as index_type and nonnegative");
  288. }
  289. template <class _OtherIndexType, size_t _Size>
  290. requires(is_convertible_v<const _OtherIndexType&, index_type> &&
  291. is_nothrow_constructible_v<index_type, const _OtherIndexType&> &&
  292. (_Size == __rank_ || _Size == __rank_dynamic_))
  293. explicit(_Size != __rank_dynamic_)
  294. _LIBCPP_HIDE_FROM_ABI constexpr extents(const span<_OtherIndexType, _Size>& __exts) noexcept
  295. : __vals_(__exts) {
  296. // Not catching this could lead to out of bounds errors later
  297. // e.g. array a{200u}; mdspan<int, dextents<char,1>> m(ptr, extents(span<unsigned,1>(a))); leads to an extent of -56
  298. // on m
  299. _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__mdspan_detail::__are_representable_as<index_type>(__exts),
  300. "extents ctor: arguments must be representable as index_type and nonnegative");
  301. }
  302. private:
  303. // Function to construct extents storage from other extents.
  304. template <size_t _DynCount, size_t _Idx, class _OtherExtents, class... _DynamicValues>
  305. requires(_Idx < __rank_)
  306. _LIBCPP_HIDE_FROM_ABI constexpr _Values __construct_vals_from_extents(
  307. integral_constant<size_t, _DynCount>,
  308. integral_constant<size_t, _Idx>,
  309. const _OtherExtents& __exts,
  310. _DynamicValues... __dynamic_values) noexcept {
  311. if constexpr (static_extent(_Idx) == dynamic_extent)
  312. return __construct_vals_from_extents(
  313. integral_constant<size_t, _DynCount + 1>(),
  314. integral_constant<size_t, _Idx + 1>(),
  315. __exts,
  316. __dynamic_values...,
  317. __exts.extent(_Idx));
  318. else
  319. return __construct_vals_from_extents(
  320. integral_constant<size_t, _DynCount>(), integral_constant<size_t, _Idx + 1>(), __exts, __dynamic_values...);
  321. }
  322. template <size_t _DynCount, size_t _Idx, class _OtherExtents, class... _DynamicValues>
  323. requires((_Idx == __rank_) && (_DynCount == __rank_dynamic_))
  324. _LIBCPP_HIDE_FROM_ABI constexpr _Values __construct_vals_from_extents(
  325. integral_constant<size_t, _DynCount>,
  326. integral_constant<size_t, _Idx>,
  327. const _OtherExtents&,
  328. _DynamicValues... __dynamic_values) noexcept {
  329. return _Values{static_cast<index_type>(__dynamic_values)...};
  330. }
  331. public:
  332. // Converting constructor from other extents specializations
  333. template <class _OtherIndexType, size_t... _OtherExtents>
  334. requires((sizeof...(_OtherExtents) == sizeof...(_Extents)) &&
  335. ((_OtherExtents == dynamic_extent || _Extents == dynamic_extent || _OtherExtents == _Extents) && ...))
  336. explicit((((_Extents != dynamic_extent) && (_OtherExtents == dynamic_extent)) || ...) ||
  337. (static_cast<make_unsigned_t<index_type>>(numeric_limits<index_type>::max()) <
  338. static_cast<make_unsigned_t<_OtherIndexType>>(numeric_limits<_OtherIndexType>::max())))
  339. _LIBCPP_HIDE_FROM_ABI constexpr extents(const extents<_OtherIndexType, _OtherExtents...>& __other) noexcept
  340. : __vals_(
  341. __construct_vals_from_extents(integral_constant<size_t, 0>(), integral_constant<size_t, 0>(), __other)) {
  342. if constexpr (rank() > 0) {
  343. for (size_t __r = 0; __r < rank(); __r++) {
  344. if constexpr (static_cast<make_unsigned_t<index_type>>(numeric_limits<index_type>::max()) <
  345. static_cast<make_unsigned_t<_OtherIndexType>>(numeric_limits<_OtherIndexType>::max())) {
  346. // Not catching this could lead to out of bounds errors later
  347. // e.g. dextents<char,1>> e(dextents<unsigned,1>(200)) leads to an extent of -56 on e
  348. _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
  349. __mdspan_detail::__is_representable_as<index_type>(__other.extent(__r)),
  350. "extents ctor: arguments must be representable as index_type and nonnegative");
  351. }
  352. // Not catching this could lead to out of bounds errors later
  353. // e.g. mdspan<int, extents<int, 10>> m = mdspan<int, dextents<int, 1>>(new int[5], 5);
  354. // Right-hand-side construction was ok, but m now thinks its range is 10 not 5
  355. _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
  356. (_Values::__static_value(__r) == dynamic_extent) ||
  357. (static_cast<index_type>(__other.extent(__r)) == static_cast<index_type>(_Values::__static_value(__r))),
  358. "extents construction: mismatch of provided arguments with static extents.");
  359. }
  360. }
  361. }
  362. // Comparison operator
  363. template <class _OtherIndexType, size_t... _OtherExtents>
  364. _LIBCPP_HIDE_FROM_ABI friend constexpr bool
  365. operator==(const extents& __lhs, const extents<_OtherIndexType, _OtherExtents...>& __rhs) noexcept {
  366. if constexpr (rank() != sizeof...(_OtherExtents)) {
  367. return false;
  368. } else {
  369. for (rank_type __r = 0; __r < __rank_; __r++) {
  370. // avoid warning when comparing signed and unsigner integers and pick the wider of two types
  371. using _CommonType = common_type_t<index_type, _OtherIndexType>;
  372. if (static_cast<_CommonType>(__lhs.extent(__r)) != static_cast<_CommonType>(__rhs.extent(__r))) {
  373. return false;
  374. }
  375. }
  376. }
  377. return true;
  378. }
  379. };
  380. // Recursive helper classes to implement dextents alias for extents
  381. namespace __mdspan_detail {
  382. template <class _IndexType, size_t _Rank, class _Extents = extents<_IndexType>>
  383. struct __make_dextents;
  384. template <class _IndexType, size_t _Rank, size_t... _ExtentsPack>
  385. struct __make_dextents< _IndexType, _Rank, extents<_IndexType, _ExtentsPack...>> {
  386. using type =
  387. typename __make_dextents< _IndexType, _Rank - 1, extents<_IndexType, dynamic_extent, _ExtentsPack...>>::type;
  388. };
  389. template <class _IndexType, size_t... _ExtentsPack>
  390. struct __make_dextents< _IndexType, 0, extents<_IndexType, _ExtentsPack...>> {
  391. using type = extents<_IndexType, _ExtentsPack...>;
  392. };
  393. } // end namespace __mdspan_detail
  394. // [mdspan.extents.dextents], alias template
  395. template <class _IndexType, size_t _Rank>
  396. using dextents = typename __mdspan_detail::__make_dextents<_IndexType, _Rank>::type;
  397. // Deduction guide for extents
  398. template <class... _IndexTypes>
  399. extents(_IndexTypes...) -> extents<size_t, size_t(((void)sizeof(_IndexTypes), dynamic_extent))...>;
  400. namespace __mdspan_detail {
  401. // Helper type traits for identifying a class as extents.
  402. template <class _Tp>
  403. struct __is_extents : false_type {};
  404. template <class _IndexType, size_t... _ExtentsPack>
  405. struct __is_extents<extents<_IndexType, _ExtentsPack...>> : true_type {};
  406. template <class _Tp>
  407. inline constexpr bool __is_extents_v = __is_extents<_Tp>::value;
  408. // Function to check whether a set of indices are a multidimensional
  409. // index into extents. This is a word of power in the C++ standard
  410. // requiring that the indices are larger than 0 and smaller than
  411. // the respective extents.
  412. template <integral _IndexType, class _From>
  413. requires(integral<_From>)
  414. _LIBCPP_HIDE_FROM_ABI constexpr bool __is_index_in_extent(_IndexType __extent, _From __value) {
  415. if constexpr (is_signed_v<_From>) {
  416. if (__value < 0)
  417. return false;
  418. }
  419. using _Tp = common_type_t<_IndexType, _From>;
  420. return static_cast<_Tp>(__value) < static_cast<_Tp>(__extent);
  421. }
  422. template <integral _IndexType, class _From>
  423. requires(!integral<_From>)
  424. _LIBCPP_HIDE_FROM_ABI constexpr bool __is_index_in_extent(_IndexType __extent, _From __value) {
  425. if constexpr (is_signed_v<_IndexType>) {
  426. if (static_cast<_IndexType>(__value) < 0)
  427. return false;
  428. }
  429. return static_cast<_IndexType>(__value) < __extent;
  430. }
  431. template <size_t... _Idxs, class _Extents, class... _From>
  432. _LIBCPP_HIDE_FROM_ABI constexpr bool
  433. __is_multidimensional_index_in_impl(index_sequence<_Idxs...>, const _Extents& __ext, _From... __values) {
  434. return (__mdspan_detail::__is_index_in_extent(__ext.extent(_Idxs), __values) && ...);
  435. }
  436. template <class _Extents, class... _From>
  437. _LIBCPP_HIDE_FROM_ABI constexpr bool __is_multidimensional_index_in(const _Extents& __ext, _From... __values) {
  438. return __mdspan_detail::__is_multidimensional_index_in_impl(
  439. make_index_sequence<_Extents::rank()>(), __ext, __values...);
  440. }
  441. } // namespace __mdspan_detail
  442. #endif // _LIBCPP_STD_VER >= 23
  443. _LIBCPP_END_NAMESPACE_STD
  444. _LIBCPP_POP_MACROS
  445. #endif // _LIBCPP___MDSPAN_EXTENTS_H