xref: /freebsd-src/contrib/llvm-project/libcxx/include/__mdspan/extents.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
106c3fb27SDimitry Andric // -*- C++ -*-
206c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
306c3fb27SDimitry Andric //
406c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
506c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
606c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
706c3fb27SDimitry Andric //
806c3fb27SDimitry Andric //                        Kokkos v. 4.0
906c3fb27SDimitry Andric //       Copyright (2022) National Technology & Engineering
1006c3fb27SDimitry Andric //               Solutions of Sandia, LLC (NTESS).
1106c3fb27SDimitry Andric //
1206c3fb27SDimitry Andric // Under the terms of Contract DE-NA0003525 with NTESS,
1306c3fb27SDimitry Andric // the U.S. Government retains certain rights in this software.
1406c3fb27SDimitry Andric //
1506c3fb27SDimitry Andric //===---------------------------------------------------------------------===//
1606c3fb27SDimitry Andric 
1706c3fb27SDimitry Andric #ifndef _LIBCPP___MDSPAN_EXTENTS_H
1806c3fb27SDimitry Andric #define _LIBCPP___MDSPAN_EXTENTS_H
1906c3fb27SDimitry Andric 
2006c3fb27SDimitry Andric #include <__assert>
2106c3fb27SDimitry Andric #include <__config>
2206c3fb27SDimitry Andric #include <__type_traits/common_type.h>
2306c3fb27SDimitry Andric #include <__type_traits/is_convertible.h>
2406c3fb27SDimitry Andric #include <__type_traits/is_nothrow_constructible.h>
2506c3fb27SDimitry Andric #include <__type_traits/is_same.h>
2606c3fb27SDimitry Andric #include <__type_traits/make_unsigned.h>
2706c3fb27SDimitry Andric #include <__utility/integer_sequence.h>
2806c3fb27SDimitry Andric #include <__utility/unreachable.h>
2906c3fb27SDimitry Andric #include <array>
3006c3fb27SDimitry Andric #include <cinttypes>
3106c3fb27SDimitry Andric #include <concepts>
3206c3fb27SDimitry Andric #include <cstddef>
3306c3fb27SDimitry Andric #include <limits>
3406c3fb27SDimitry Andric #include <span>
3506c3fb27SDimitry Andric 
3606c3fb27SDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
3706c3fb27SDimitry Andric #  pragma GCC system_header
3806c3fb27SDimitry Andric #endif
3906c3fb27SDimitry Andric 
4006c3fb27SDimitry Andric _LIBCPP_PUSH_MACROS
4106c3fb27SDimitry Andric #include <__undef_macros>
4206c3fb27SDimitry Andric 
4306c3fb27SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
4406c3fb27SDimitry Andric 
4506c3fb27SDimitry Andric #if _LIBCPP_STD_VER >= 23
4606c3fb27SDimitry Andric 
4706c3fb27SDimitry Andric namespace __mdspan_detail {
4806c3fb27SDimitry Andric 
4906c3fb27SDimitry Andric // ------------------------------------------------------------------
5006c3fb27SDimitry Andric // ------------ __static_array --------------------------------------
5106c3fb27SDimitry Andric // ------------------------------------------------------------------
5206c3fb27SDimitry Andric // array like class which provides an array of static values with get
5306c3fb27SDimitry Andric template <class _Tp, _Tp... _Values>
5406c3fb27SDimitry Andric struct __static_array {
5506c3fb27SDimitry Andric   static constexpr array<_Tp, sizeof...(_Values)> __array = {_Values...};
5606c3fb27SDimitry Andric 
5706c3fb27SDimitry Andric public:
5806c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI static constexpr size_t __size() { return sizeof...(_Values); }
5906c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI static constexpr _Tp __get(size_t __index) noexcept { return __array[__index]; }
6006c3fb27SDimitry Andric 
6106c3fb27SDimitry Andric   template <size_t _Index>
6206c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI static constexpr _Tp __get() {
6306c3fb27SDimitry Andric     return __get(_Index);
6406c3fb27SDimitry Andric   }
6506c3fb27SDimitry Andric };
6606c3fb27SDimitry Andric 
6706c3fb27SDimitry Andric // ------------------------------------------------------------------
6806c3fb27SDimitry Andric // ------------ __possibly_empty_array  -----------------------------
6906c3fb27SDimitry Andric // ------------------------------------------------------------------
7006c3fb27SDimitry Andric 
7106c3fb27SDimitry Andric // array like class which provides get function and operator [], and
7206c3fb27SDimitry Andric // has a specialization for the size 0 case.
7306c3fb27SDimitry Andric // This is needed to make the __maybe_static_array be truly empty, for
7406c3fb27SDimitry Andric // all static values.
7506c3fb27SDimitry Andric 
7606c3fb27SDimitry Andric template <class _Tp, size_t _Size>
7706c3fb27SDimitry Andric struct __possibly_empty_array {
7806c3fb27SDimitry Andric   _Tp __vals_[_Size];
7906c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator[](size_t __index) { return __vals_[__index]; }
8006c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator[](size_t __index) const { return __vals_[__index]; }
8106c3fb27SDimitry Andric };
8206c3fb27SDimitry Andric 
8306c3fb27SDimitry Andric template <class _Tp>
8406c3fb27SDimitry Andric struct __possibly_empty_array<_Tp, 0> {
8506c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator[](size_t) { __libcpp_unreachable(); }
8606c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator[](size_t) const { __libcpp_unreachable(); }
8706c3fb27SDimitry Andric };
8806c3fb27SDimitry Andric 
8906c3fb27SDimitry Andric // ------------------------------------------------------------------
9006c3fb27SDimitry Andric // ------------ static_partial_sums ---------------------------------
9106c3fb27SDimitry Andric // ------------------------------------------------------------------
9206c3fb27SDimitry Andric 
9306c3fb27SDimitry Andric // Provides a compile time partial sum one can index into
9406c3fb27SDimitry Andric 
9506c3fb27SDimitry Andric template <size_t... _Values>
9606c3fb27SDimitry Andric struct __static_partial_sums {
9706c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI static constexpr array<size_t, sizeof...(_Values)> __static_partial_sums_impl() {
9806c3fb27SDimitry Andric     array<size_t, sizeof...(_Values)> __values{_Values...};
9906c3fb27SDimitry Andric     array<size_t, sizeof...(_Values)> __partial_sums{{}};
10006c3fb27SDimitry Andric     size_t __running_sum = 0;
10106c3fb27SDimitry Andric     for (int __i = 0; __i != sizeof...(_Values); ++__i) {
10206c3fb27SDimitry Andric       __partial_sums[__i] = __running_sum;
10306c3fb27SDimitry Andric       __running_sum += __values[__i];
10406c3fb27SDimitry Andric     }
10506c3fb27SDimitry Andric     return __partial_sums;
10606c3fb27SDimitry Andric   }
10706c3fb27SDimitry Andric   static constexpr array<size_t, sizeof...(_Values)> __result{__static_partial_sums_impl()};
10806c3fb27SDimitry Andric 
10906c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI static constexpr size_t __get(size_t __index) { return __result[__index]; }
11006c3fb27SDimitry Andric };
11106c3fb27SDimitry Andric 
11206c3fb27SDimitry Andric // ------------------------------------------------------------------
11306c3fb27SDimitry Andric // ------------ __maybe_static_array --------------------------------
11406c3fb27SDimitry Andric // ------------------------------------------------------------------
11506c3fb27SDimitry Andric 
11606c3fb27SDimitry Andric // array like class which has a mix of static and runtime values but
11706c3fb27SDimitry Andric // only stores the runtime values.
11806c3fb27SDimitry Andric // The type of the static and the runtime values can be different.
11906c3fb27SDimitry Andric // The position of a dynamic value is indicated through a tag value.
12006c3fb27SDimitry Andric template <class _TDynamic, class _TStatic, _TStatic _DynTag, _TStatic... _Values>
12106c3fb27SDimitry Andric struct __maybe_static_array {
12206c3fb27SDimitry Andric   static_assert(is_convertible<_TStatic, _TDynamic>::value,
12306c3fb27SDimitry Andric                 "__maybe_static_array: _TStatic must be convertible to _TDynamic");
12406c3fb27SDimitry Andric   static_assert(is_convertible<_TDynamic, _TStatic>::value,
12506c3fb27SDimitry Andric                 "__maybe_static_array: _TDynamic must be convertible to _TStatic");
12606c3fb27SDimitry Andric 
12706c3fb27SDimitry Andric private:
12806c3fb27SDimitry Andric   // Static values member
12906c3fb27SDimitry Andric   static constexpr size_t __size_         = sizeof...(_Values);
13006c3fb27SDimitry Andric   static constexpr size_t __size_dynamic_ = ((_Values == _DynTag) + ... + 0);
13106c3fb27SDimitry Andric   using _StaticValues                     = __static_array<_TStatic, _Values...>;
13206c3fb27SDimitry Andric   using _DynamicValues                    = __possibly_empty_array<_TDynamic, __size_dynamic_>;
13306c3fb27SDimitry Andric 
13406c3fb27SDimitry Andric   // Dynamic values member
13506c3fb27SDimitry Andric   _LIBCPP_NO_UNIQUE_ADDRESS _DynamicValues __dyn_vals_;
13606c3fb27SDimitry Andric 
13706c3fb27SDimitry Andric   // static mapping of indices to the position in the dynamic values array
13806c3fb27SDimitry Andric   using _DynamicIdxMap = __static_partial_sums<static_cast<size_t>(_Values == _DynTag)...>;
13906c3fb27SDimitry Andric 
140*0fca6ea1SDimitry Andric   template <size_t... _Indices>
141*0fca6ea1SDimitry Andric   _LIBCPP_HIDE_FROM_ABI static constexpr _DynamicValues __zeros(index_sequence<_Indices...>) noexcept {
142*0fca6ea1SDimitry Andric     return _DynamicValues{((void)_Indices, 0)...};
14306c3fb27SDimitry Andric   }
14406c3fb27SDimitry Andric 
14506c3fb27SDimitry Andric public:
14606c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr __maybe_static_array() noexcept
14706c3fb27SDimitry Andric       : __dyn_vals_{__zeros(make_index_sequence<__size_dynamic_>())} {}
14806c3fb27SDimitry Andric 
14906c3fb27SDimitry Andric   // constructors from dynamic values only -- this covers the case for rank() == 0
15006c3fb27SDimitry Andric   template <class... _DynVals>
15106c3fb27SDimitry Andric     requires(sizeof...(_DynVals) == __size_dynamic_)
15206c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr __maybe_static_array(_DynVals... __vals)
15306c3fb27SDimitry Andric       : __dyn_vals_{static_cast<_TDynamic>(__vals)...} {}
15406c3fb27SDimitry Andric 
15506c3fb27SDimitry Andric   template <class _Tp, size_t _Size >
15606c3fb27SDimitry Andric     requires(_Size == __size_dynamic_)
15706c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr __maybe_static_array([[maybe_unused]] const span<_Tp, _Size>& __vals) {
15806c3fb27SDimitry Andric     if constexpr (_Size > 0) {
15906c3fb27SDimitry Andric       for (size_t __i = 0; __i < _Size; __i++)
16006c3fb27SDimitry Andric         __dyn_vals_[__i] = static_cast<_TDynamic>(__vals[__i]);
16106c3fb27SDimitry Andric     }
16206c3fb27SDimitry Andric   }
16306c3fb27SDimitry Andric 
16406c3fb27SDimitry Andric   // constructors from all values -- here rank will be greater than 0
16506c3fb27SDimitry Andric   template <class... _DynVals>
16606c3fb27SDimitry Andric     requires(sizeof...(_DynVals) != __size_dynamic_)
16706c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr __maybe_static_array(_DynVals... __vals) {
168*0fca6ea1SDimitry Andric     static_assert(sizeof...(_DynVals) == __size_, "Invalid number of values.");
16906c3fb27SDimitry Andric     _TDynamic __values[__size_] = {static_cast<_TDynamic>(__vals)...};
17006c3fb27SDimitry Andric     for (size_t __i = 0; __i < __size_; __i++) {
17106c3fb27SDimitry Andric       _TStatic __static_val = _StaticValues::__get(__i);
17206c3fb27SDimitry Andric       if (__static_val == _DynTag) {
17306c3fb27SDimitry Andric         __dyn_vals_[_DynamicIdxMap::__get(__i)] = __values[__i];
1748a4dda33SDimitry Andric       } else
1758a4dda33SDimitry Andric         // Not catching this could lead to out of bounds errors later
1768a4dda33SDimitry Andric         // e.g. using my_mdspan_t = mdspan<int, extents<int, 10>>; my_mdspan_t = m(new int[5], 5);
1778a4dda33SDimitry Andric         // Right-hand-side construction looks ok with allocation and size matching,
1788a4dda33SDimitry Andric         // but since (potentially elsewhere defined) my_mdspan_t has static size m now thinks its range is 10 not 5
1798a4dda33SDimitry Andric         _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
1808a4dda33SDimitry Andric             __values[__i] == static_cast<_TDynamic>(__static_val),
18106c3fb27SDimitry Andric             "extents construction: mismatch of provided arguments with static extents.");
18206c3fb27SDimitry Andric     }
18306c3fb27SDimitry Andric   }
18406c3fb27SDimitry Andric 
18506c3fb27SDimitry Andric   template <class _Tp, size_t _Size>
18606c3fb27SDimitry Andric     requires(_Size != __size_dynamic_)
18706c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr __maybe_static_array(const span<_Tp, _Size>& __vals) {
188*0fca6ea1SDimitry Andric     static_assert(_Size == __size_ || __size_ == dynamic_extent);
18906c3fb27SDimitry Andric     for (size_t __i = 0; __i < __size_; __i++) {
19006c3fb27SDimitry Andric       _TStatic __static_val = _StaticValues::__get(__i);
19106c3fb27SDimitry Andric       if (__static_val == _DynTag) {
19206c3fb27SDimitry Andric         __dyn_vals_[_DynamicIdxMap::__get(__i)] = static_cast<_TDynamic>(__vals[__i]);
1938a4dda33SDimitry Andric       } else
1948a4dda33SDimitry Andric         // Not catching this could lead to out of bounds errors later
1958a4dda33SDimitry Andric         // e.g. using my_mdspan_t = mdspan<int, extents<int, 10>>; my_mdspan_t = m(new int[N], span<int,1>(&N));
1968a4dda33SDimitry Andric         // Right-hand-side construction looks ok with allocation and size matching,
1978a4dda33SDimitry Andric         // but since (potentially elsewhere defined) my_mdspan_t has static size m now thinks its range is 10 not N
1988a4dda33SDimitry Andric         _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
1998a4dda33SDimitry Andric             static_cast<_TDynamic>(__vals[__i]) == static_cast<_TDynamic>(__static_val),
20006c3fb27SDimitry Andric             "extents construction: mismatch of provided arguments with static extents.");
20106c3fb27SDimitry Andric     }
20206c3fb27SDimitry Andric   }
20306c3fb27SDimitry Andric 
20406c3fb27SDimitry Andric   // access functions
20506c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI static constexpr _TStatic __static_value(size_t __i) noexcept {
20606c3fb27SDimitry Andric     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__i < __size_, "extents access: index must be less than rank");
20706c3fb27SDimitry Andric     return _StaticValues::__get(__i);
20806c3fb27SDimitry Andric   }
20906c3fb27SDimitry Andric 
21006c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr _TDynamic __value(size_t __i) const {
21106c3fb27SDimitry Andric     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__i < __size_, "extents access: index must be less than rank");
21206c3fb27SDimitry Andric     _TStatic __static_val = _StaticValues::__get(__i);
21306c3fb27SDimitry Andric     return __static_val == _DynTag ? __dyn_vals_[_DynamicIdxMap::__get(__i)] : static_cast<_TDynamic>(__static_val);
21406c3fb27SDimitry Andric   }
21506c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr _TDynamic operator[](size_t __i) const {
21606c3fb27SDimitry Andric     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__i < __size_, "extents access: index must be less than rank");
21706c3fb27SDimitry Andric     return __value(__i);
21806c3fb27SDimitry Andric   }
21906c3fb27SDimitry Andric 
22006c3fb27SDimitry Andric   // observers
22106c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI static constexpr size_t __size() { return __size_; }
22206c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI static constexpr size_t __size_dynamic() { return __size_dynamic_; }
22306c3fb27SDimitry Andric };
22406c3fb27SDimitry Andric 
22506c3fb27SDimitry Andric // Function to check whether a value is representable as another type
22606c3fb27SDimitry Andric // value must be a positive integer otherwise returns false
22706c3fb27SDimitry Andric // if _From is not an integral, we just check positivity
22806c3fb27SDimitry Andric template <integral _To, class _From>
22906c3fb27SDimitry Andric   requires(integral<_From>)
23006c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr bool __is_representable_as(_From __value) {
23106c3fb27SDimitry Andric   using _To_u   = make_unsigned_t<_To>;
23206c3fb27SDimitry Andric   using _From_u = make_unsigned_t<_From>;
23306c3fb27SDimitry Andric   if constexpr (is_signed_v<_From>) {
23406c3fb27SDimitry Andric     if (__value < 0)
23506c3fb27SDimitry Andric       return false;
23606c3fb27SDimitry Andric   }
23706c3fb27SDimitry Andric   if constexpr (static_cast<_To_u>(numeric_limits<_To>::max()) >= static_cast<_From_u>(numeric_limits<_From>::max())) {
23806c3fb27SDimitry Andric     return true;
23906c3fb27SDimitry Andric   } else {
24006c3fb27SDimitry Andric     return static_cast<_To_u>(numeric_limits<_To>::max()) >= static_cast<_From_u>(__value);
24106c3fb27SDimitry Andric   }
24206c3fb27SDimitry Andric }
24306c3fb27SDimitry Andric 
24406c3fb27SDimitry Andric template <integral _To, class _From>
24506c3fb27SDimitry Andric   requires(!integral<_From>)
24606c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr bool __is_representable_as(_From __value) {
24706c3fb27SDimitry Andric   if constexpr (is_signed_v<_To>) {
24806c3fb27SDimitry Andric     if (static_cast<_To>(__value) < 0)
24906c3fb27SDimitry Andric       return false;
25006c3fb27SDimitry Andric   }
25106c3fb27SDimitry Andric   return true;
25206c3fb27SDimitry Andric }
25306c3fb27SDimitry Andric 
25406c3fb27SDimitry Andric template <integral _To, class... _From>
25506c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr bool __are_representable_as(_From... __values) {
25606c3fb27SDimitry Andric   return (__mdspan_detail::__is_representable_as<_To>(__values) && ... && true);
25706c3fb27SDimitry Andric }
25806c3fb27SDimitry Andric 
25906c3fb27SDimitry Andric template <integral _To, class _From, size_t _Size>
26006c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr bool __are_representable_as(span<_From, _Size> __values) {
26106c3fb27SDimitry Andric   for (size_t __i = 0; __i < _Size; __i++)
26206c3fb27SDimitry Andric     if (!__mdspan_detail::__is_representable_as<_To>(__values[__i]))
26306c3fb27SDimitry Andric       return false;
26406c3fb27SDimitry Andric   return true;
26506c3fb27SDimitry Andric }
26606c3fb27SDimitry Andric 
26706c3fb27SDimitry Andric } // namespace __mdspan_detail
26806c3fb27SDimitry Andric 
26906c3fb27SDimitry Andric // ------------------------------------------------------------------
27006c3fb27SDimitry Andric // ------------ extents ---------------------------------------------
27106c3fb27SDimitry Andric // ------------------------------------------------------------------
27206c3fb27SDimitry Andric 
27306c3fb27SDimitry Andric // Class to describe the extents of a multi dimensional array.
27406c3fb27SDimitry Andric // Used by mdspan, mdarray and layout mappings.
27506c3fb27SDimitry Andric // See ISO C++ standard [mdspan.extents]
27606c3fb27SDimitry Andric 
27706c3fb27SDimitry Andric template <class _IndexType, size_t... _Extents>
27806c3fb27SDimitry Andric class extents {
27906c3fb27SDimitry Andric public:
28006c3fb27SDimitry Andric   // typedefs for integral types used
28106c3fb27SDimitry Andric   using index_type = _IndexType;
28206c3fb27SDimitry Andric   using size_type  = make_unsigned_t<index_type>;
28306c3fb27SDimitry Andric   using rank_type  = size_t;
28406c3fb27SDimitry Andric 
28506c3fb27SDimitry Andric   static_assert(is_integral<index_type>::value && !is_same<index_type, bool>::value,
28606c3fb27SDimitry Andric                 "extents::index_type must be a signed or unsigned integer type");
28706c3fb27SDimitry Andric   static_assert(((__mdspan_detail::__is_representable_as<index_type>(_Extents) || (_Extents == dynamic_extent)) && ...),
28806c3fb27SDimitry Andric                 "extents ctor: arguments must be representable as index_type and nonnegative");
28906c3fb27SDimitry Andric 
29006c3fb27SDimitry Andric private:
29106c3fb27SDimitry Andric   static constexpr rank_type __rank_         = sizeof...(_Extents);
29206c3fb27SDimitry Andric   static constexpr rank_type __rank_dynamic_ = ((_Extents == dynamic_extent) + ... + 0);
29306c3fb27SDimitry Andric 
29406c3fb27SDimitry Andric   // internal storage type using __maybe_static_array
29506c3fb27SDimitry Andric   using _Values = __mdspan_detail::__maybe_static_array<_IndexType, size_t, dynamic_extent, _Extents...>;
29606c3fb27SDimitry Andric   [[no_unique_address]] _Values __vals_;
29706c3fb27SDimitry Andric 
29806c3fb27SDimitry Andric public:
29906c3fb27SDimitry Andric   // [mdspan.extents.obs], observers of multidimensional index space
30006c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI static constexpr rank_type rank() noexcept { return __rank_; }
30106c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI static constexpr rank_type rank_dynamic() noexcept { return __rank_dynamic_; }
30206c3fb27SDimitry Andric 
30306c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr index_type extent(rank_type __r) const noexcept { return __vals_.__value(__r); }
30406c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI static constexpr size_t static_extent(rank_type __r) noexcept {
30506c3fb27SDimitry Andric     return _Values::__static_value(__r);
30606c3fb27SDimitry Andric   }
30706c3fb27SDimitry Andric 
30806c3fb27SDimitry Andric   // [mdspan.extents.cons], constructors
30906c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr extents() noexcept = default;
31006c3fb27SDimitry Andric 
31106c3fb27SDimitry Andric   // Construction from just dynamic or all values.
31206c3fb27SDimitry Andric   // Precondition check is deferred to __maybe_static_array constructor
31306c3fb27SDimitry Andric   template <class... _OtherIndexTypes>
31406c3fb27SDimitry Andric     requires((is_convertible_v<_OtherIndexTypes, index_type> && ...) &&
31506c3fb27SDimitry Andric              (is_nothrow_constructible_v<index_type, _OtherIndexTypes> && ...) &&
31606c3fb27SDimitry Andric              (sizeof...(_OtherIndexTypes) == __rank_ || sizeof...(_OtherIndexTypes) == __rank_dynamic_))
31706c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr explicit extents(_OtherIndexTypes... __dynvals) noexcept
31806c3fb27SDimitry Andric       : __vals_(static_cast<index_type>(__dynvals)...) {
3198a4dda33SDimitry Andric     // Not catching this could lead to out of bounds errors later
3208a4dda33SDimitry Andric     // e.g. mdspan m(ptr, dextents<char, 1>(200u)); leads to an extent of -56 on m
3218a4dda33SDimitry Andric     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__mdspan_detail::__are_representable_as<index_type>(__dynvals...),
32206c3fb27SDimitry Andric                                         "extents ctor: arguments must be representable as index_type and nonnegative");
32306c3fb27SDimitry Andric   }
32406c3fb27SDimitry Andric 
32506c3fb27SDimitry Andric   template <class _OtherIndexType, size_t _Size>
3268a4dda33SDimitry Andric     requires(is_convertible_v<const _OtherIndexType&, index_type> &&
3278a4dda33SDimitry Andric              is_nothrow_constructible_v<index_type, const _OtherIndexType&> &&
32806c3fb27SDimitry Andric              (_Size == __rank_ || _Size == __rank_dynamic_))
32906c3fb27SDimitry Andric   explicit(_Size != __rank_dynamic_)
33006c3fb27SDimitry Andric       _LIBCPP_HIDE_FROM_ABI constexpr extents(const array<_OtherIndexType, _Size>& __exts) noexcept
33106c3fb27SDimitry Andric       : __vals_(span(__exts)) {
3328a4dda33SDimitry Andric     // Not catching this could lead to out of bounds errors later
3338a4dda33SDimitry Andric     // e.g. mdspan m(ptr, dextents<char, 1>(array<unsigned,1>(200))); leads to an extent of -56 on m
3348a4dda33SDimitry Andric     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__mdspan_detail::__are_representable_as<index_type>(span(__exts)),
33506c3fb27SDimitry Andric                                         "extents ctor: arguments must be representable as index_type and nonnegative");
33606c3fb27SDimitry Andric   }
33706c3fb27SDimitry Andric 
33806c3fb27SDimitry Andric   template <class _OtherIndexType, size_t _Size>
3398a4dda33SDimitry Andric     requires(is_convertible_v<const _OtherIndexType&, index_type> &&
3408a4dda33SDimitry Andric              is_nothrow_constructible_v<index_type, const _OtherIndexType&> &&
34106c3fb27SDimitry Andric              (_Size == __rank_ || _Size == __rank_dynamic_))
34206c3fb27SDimitry Andric   explicit(_Size != __rank_dynamic_)
34306c3fb27SDimitry Andric       _LIBCPP_HIDE_FROM_ABI constexpr extents(const span<_OtherIndexType, _Size>& __exts) noexcept
34406c3fb27SDimitry Andric       : __vals_(__exts) {
3458a4dda33SDimitry Andric     // Not catching this could lead to out of bounds errors later
3468a4dda33SDimitry Andric     // e.g. array a{200u}; mdspan<int, dextents<char,1>> m(ptr, extents(span<unsigned,1>(a))); leads to an extent of -56
3478a4dda33SDimitry Andric     // on m
3488a4dda33SDimitry Andric     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__mdspan_detail::__are_representable_as<index_type>(__exts),
34906c3fb27SDimitry Andric                                         "extents ctor: arguments must be representable as index_type and nonnegative");
35006c3fb27SDimitry Andric   }
35106c3fb27SDimitry Andric 
35206c3fb27SDimitry Andric private:
35306c3fb27SDimitry Andric   // Function to construct extents storage from other extents.
35406c3fb27SDimitry Andric   template <size_t _DynCount, size_t _Idx, class _OtherExtents, class... _DynamicValues>
35506c3fb27SDimitry Andric     requires(_Idx < __rank_)
35606c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr _Values __construct_vals_from_extents(
35706c3fb27SDimitry Andric       integral_constant<size_t, _DynCount>,
35806c3fb27SDimitry Andric       integral_constant<size_t, _Idx>,
35906c3fb27SDimitry Andric       const _OtherExtents& __exts,
36006c3fb27SDimitry Andric       _DynamicValues... __dynamic_values) noexcept {
36106c3fb27SDimitry Andric     if constexpr (static_extent(_Idx) == dynamic_extent)
36206c3fb27SDimitry Andric       return __construct_vals_from_extents(
36306c3fb27SDimitry Andric           integral_constant<size_t, _DynCount + 1>(),
36406c3fb27SDimitry Andric           integral_constant<size_t, _Idx + 1>(),
36506c3fb27SDimitry Andric           __exts,
36606c3fb27SDimitry Andric           __dynamic_values...,
36706c3fb27SDimitry Andric           __exts.extent(_Idx));
36806c3fb27SDimitry Andric     else
36906c3fb27SDimitry Andric       return __construct_vals_from_extents(
37006c3fb27SDimitry Andric           integral_constant<size_t, _DynCount>(), integral_constant<size_t, _Idx + 1>(), __exts, __dynamic_values...);
37106c3fb27SDimitry Andric   }
37206c3fb27SDimitry Andric 
37306c3fb27SDimitry Andric   template <size_t _DynCount, size_t _Idx, class _OtherExtents, class... _DynamicValues>
37406c3fb27SDimitry Andric     requires((_Idx == __rank_) && (_DynCount == __rank_dynamic_))
37506c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr _Values __construct_vals_from_extents(
37606c3fb27SDimitry Andric       integral_constant<size_t, _DynCount>,
37706c3fb27SDimitry Andric       integral_constant<size_t, _Idx>,
37806c3fb27SDimitry Andric       const _OtherExtents&,
37906c3fb27SDimitry Andric       _DynamicValues... __dynamic_values) noexcept {
38006c3fb27SDimitry Andric     return _Values{static_cast<index_type>(__dynamic_values)...};
38106c3fb27SDimitry Andric   }
38206c3fb27SDimitry Andric 
38306c3fb27SDimitry Andric public:
38406c3fb27SDimitry Andric   // Converting constructor from other extents specializations
38506c3fb27SDimitry Andric   template <class _OtherIndexType, size_t... _OtherExtents>
38606c3fb27SDimitry Andric     requires((sizeof...(_OtherExtents) == sizeof...(_Extents)) &&
38706c3fb27SDimitry Andric              ((_OtherExtents == dynamic_extent || _Extents == dynamic_extent || _OtherExtents == _Extents) && ...))
38806c3fb27SDimitry Andric   explicit((((_Extents != dynamic_extent) && (_OtherExtents == dynamic_extent)) || ...) ||
38906c3fb27SDimitry Andric            (static_cast<make_unsigned_t<index_type>>(numeric_limits<index_type>::max()) <
39006c3fb27SDimitry Andric             static_cast<make_unsigned_t<_OtherIndexType>>(numeric_limits<_OtherIndexType>::max())))
39106c3fb27SDimitry Andric       _LIBCPP_HIDE_FROM_ABI constexpr extents(const extents<_OtherIndexType, _OtherExtents...>& __other) noexcept
39206c3fb27SDimitry Andric       : __vals_(
39306c3fb27SDimitry Andric             __construct_vals_from_extents(integral_constant<size_t, 0>(), integral_constant<size_t, 0>(), __other)) {
39406c3fb27SDimitry Andric     if constexpr (rank() > 0) {
39506c3fb27SDimitry Andric       for (size_t __r = 0; __r < rank(); __r++) {
39606c3fb27SDimitry Andric         if constexpr (static_cast<make_unsigned_t<index_type>>(numeric_limits<index_type>::max()) <
39706c3fb27SDimitry Andric                       static_cast<make_unsigned_t<_OtherIndexType>>(numeric_limits<_OtherIndexType>::max())) {
3988a4dda33SDimitry Andric           // Not catching this could lead to out of bounds errors later
3998a4dda33SDimitry Andric           // e.g. dextents<char,1>> e(dextents<unsigned,1>(200)) leads to an extent of -56 on e
4008a4dda33SDimitry Andric           _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
4018a4dda33SDimitry Andric               __mdspan_detail::__is_representable_as<index_type>(__other.extent(__r)),
40206c3fb27SDimitry Andric               "extents ctor: arguments must be representable as index_type and nonnegative");
40306c3fb27SDimitry Andric         }
4048a4dda33SDimitry Andric         // Not catching this could lead to out of bounds errors later
4058a4dda33SDimitry Andric         // e.g. mdspan<int, extents<int, 10>> m = mdspan<int, dextents<int, 1>>(new int[5], 5);
4068a4dda33SDimitry Andric         // Right-hand-side construction was ok, but m now thinks its range is 10 not 5
4078a4dda33SDimitry Andric         _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
40806c3fb27SDimitry Andric             (_Values::__static_value(__r) == dynamic_extent) ||
40906c3fb27SDimitry Andric                 (static_cast<index_type>(__other.extent(__r)) == static_cast<index_type>(_Values::__static_value(__r))),
41006c3fb27SDimitry Andric             "extents construction: mismatch of provided arguments with static extents.");
41106c3fb27SDimitry Andric       }
41206c3fb27SDimitry Andric     }
41306c3fb27SDimitry Andric   }
41406c3fb27SDimitry Andric 
41506c3fb27SDimitry Andric   // Comparison operator
41606c3fb27SDimitry Andric   template <class _OtherIndexType, size_t... _OtherExtents>
41706c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI friend constexpr bool
41806c3fb27SDimitry Andric   operator==(const extents& __lhs, const extents<_OtherIndexType, _OtherExtents...>& __rhs) noexcept {
41906c3fb27SDimitry Andric     if constexpr (rank() != sizeof...(_OtherExtents)) {
42006c3fb27SDimitry Andric       return false;
42106c3fb27SDimitry Andric     } else {
42206c3fb27SDimitry Andric       for (rank_type __r = 0; __r < __rank_; __r++) {
42306c3fb27SDimitry Andric         // avoid warning when comparing signed and unsigner integers and pick the wider of two types
42406c3fb27SDimitry Andric         using _CommonType = common_type_t<index_type, _OtherIndexType>;
42506c3fb27SDimitry Andric         if (static_cast<_CommonType>(__lhs.extent(__r)) != static_cast<_CommonType>(__rhs.extent(__r))) {
42606c3fb27SDimitry Andric           return false;
42706c3fb27SDimitry Andric         }
42806c3fb27SDimitry Andric       }
42906c3fb27SDimitry Andric     }
43006c3fb27SDimitry Andric     return true;
43106c3fb27SDimitry Andric   }
43206c3fb27SDimitry Andric };
43306c3fb27SDimitry Andric 
43406c3fb27SDimitry Andric // Recursive helper classes to implement dextents alias for extents
43506c3fb27SDimitry Andric namespace __mdspan_detail {
43606c3fb27SDimitry Andric 
43706c3fb27SDimitry Andric template <class _IndexType, size_t _Rank, class _Extents = extents<_IndexType>>
43806c3fb27SDimitry Andric struct __make_dextents;
43906c3fb27SDimitry Andric 
44006c3fb27SDimitry Andric template <class _IndexType, size_t _Rank, size_t... _ExtentsPack>
44106c3fb27SDimitry Andric struct __make_dextents< _IndexType, _Rank, extents<_IndexType, _ExtentsPack...>> {
44206c3fb27SDimitry Andric   using type =
44306c3fb27SDimitry Andric       typename __make_dextents< _IndexType, _Rank - 1, extents<_IndexType, dynamic_extent, _ExtentsPack...>>::type;
44406c3fb27SDimitry Andric };
44506c3fb27SDimitry Andric 
44606c3fb27SDimitry Andric template <class _IndexType, size_t... _ExtentsPack>
44706c3fb27SDimitry Andric struct __make_dextents< _IndexType, 0, extents<_IndexType, _ExtentsPack...>> {
44806c3fb27SDimitry Andric   using type = extents<_IndexType, _ExtentsPack...>;
44906c3fb27SDimitry Andric };
45006c3fb27SDimitry Andric 
45106c3fb27SDimitry Andric } // end namespace __mdspan_detail
45206c3fb27SDimitry Andric 
45306c3fb27SDimitry Andric // [mdspan.extents.dextents], alias template
45406c3fb27SDimitry Andric template <class _IndexType, size_t _Rank>
45506c3fb27SDimitry Andric using dextents = typename __mdspan_detail::__make_dextents<_IndexType, _Rank>::type;
45606c3fb27SDimitry Andric 
457*0fca6ea1SDimitry Andric #  if _LIBCPP_STD_VER >= 26
458*0fca6ea1SDimitry Andric // [mdspan.extents.dims], alias template `dims`
459*0fca6ea1SDimitry Andric template <size_t _Rank, class _IndexType = size_t>
460*0fca6ea1SDimitry Andric using dims = dextents<_IndexType, _Rank>;
461*0fca6ea1SDimitry Andric #  endif
462*0fca6ea1SDimitry Andric 
46306c3fb27SDimitry Andric // Deduction guide for extents
464*0fca6ea1SDimitry Andric #  if _LIBCPP_STD_VER >= 26
46506c3fb27SDimitry Andric template <class... _IndexTypes>
466*0fca6ea1SDimitry Andric   requires(is_convertible_v<_IndexTypes, size_t> && ...)
467*0fca6ea1SDimitry Andric explicit extents(_IndexTypes...) -> extents<size_t, __maybe_static_ext<_IndexTypes>...>;
468*0fca6ea1SDimitry Andric #  else
469*0fca6ea1SDimitry Andric template <class... _IndexTypes>
470*0fca6ea1SDimitry Andric   requires(is_convertible_v<_IndexTypes, size_t> && ...)
471*0fca6ea1SDimitry Andric explicit extents(_IndexTypes...) -> extents<size_t, size_t(((void)sizeof(_IndexTypes), dynamic_extent))...>;
472*0fca6ea1SDimitry Andric #  endif
47306c3fb27SDimitry Andric 
47406c3fb27SDimitry Andric namespace __mdspan_detail {
47506c3fb27SDimitry Andric 
47606c3fb27SDimitry Andric // Helper type traits for identifying a class as extents.
47706c3fb27SDimitry Andric template <class _Tp>
47806c3fb27SDimitry Andric struct __is_extents : false_type {};
47906c3fb27SDimitry Andric 
48006c3fb27SDimitry Andric template <class _IndexType, size_t... _ExtentsPack>
48106c3fb27SDimitry Andric struct __is_extents<extents<_IndexType, _ExtentsPack...>> : true_type {};
48206c3fb27SDimitry Andric 
48306c3fb27SDimitry Andric template <class _Tp>
48406c3fb27SDimitry Andric inline constexpr bool __is_extents_v = __is_extents<_Tp>::value;
48506c3fb27SDimitry Andric 
48606c3fb27SDimitry Andric // Function to check whether a set of indices are a multidimensional
48706c3fb27SDimitry Andric // index into extents. This is a word of power in the C++ standard
48806c3fb27SDimitry Andric // requiring that the indices are larger than 0 and smaller than
48906c3fb27SDimitry Andric // the respective extents.
49006c3fb27SDimitry Andric 
49106c3fb27SDimitry Andric template <integral _IndexType, class _From>
49206c3fb27SDimitry Andric   requires(integral<_From>)
49306c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr bool __is_index_in_extent(_IndexType __extent, _From __value) {
49406c3fb27SDimitry Andric   if constexpr (is_signed_v<_From>) {
49506c3fb27SDimitry Andric     if (__value < 0)
49606c3fb27SDimitry Andric       return false;
49706c3fb27SDimitry Andric   }
49806c3fb27SDimitry Andric   using _Tp = common_type_t<_IndexType, _From>;
49906c3fb27SDimitry Andric   return static_cast<_Tp>(__value) < static_cast<_Tp>(__extent);
50006c3fb27SDimitry Andric }
50106c3fb27SDimitry Andric 
50206c3fb27SDimitry Andric template <integral _IndexType, class _From>
50306c3fb27SDimitry Andric   requires(!integral<_From>)
50406c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr bool __is_index_in_extent(_IndexType __extent, _From __value) {
50506c3fb27SDimitry Andric   if constexpr (is_signed_v<_IndexType>) {
50606c3fb27SDimitry Andric     if (static_cast<_IndexType>(__value) < 0)
50706c3fb27SDimitry Andric       return false;
50806c3fb27SDimitry Andric   }
50906c3fb27SDimitry Andric   return static_cast<_IndexType>(__value) < __extent;
51006c3fb27SDimitry Andric }
51106c3fb27SDimitry Andric 
51206c3fb27SDimitry Andric template <size_t... _Idxs, class _Extents, class... _From>
51306c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr bool
51406c3fb27SDimitry Andric __is_multidimensional_index_in_impl(index_sequence<_Idxs...>, const _Extents& __ext, _From... __values) {
51506c3fb27SDimitry Andric   return (__mdspan_detail::__is_index_in_extent(__ext.extent(_Idxs), __values) && ...);
51606c3fb27SDimitry Andric }
51706c3fb27SDimitry Andric 
51806c3fb27SDimitry Andric template <class _Extents, class... _From>
51906c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr bool __is_multidimensional_index_in(const _Extents& __ext, _From... __values) {
52006c3fb27SDimitry Andric   return __mdspan_detail::__is_multidimensional_index_in_impl(
52106c3fb27SDimitry Andric       make_index_sequence<_Extents::rank()>(), __ext, __values...);
52206c3fb27SDimitry Andric }
52306c3fb27SDimitry Andric 
52406c3fb27SDimitry Andric } // namespace __mdspan_detail
52506c3fb27SDimitry Andric 
52606c3fb27SDimitry Andric #endif // _LIBCPP_STD_VER >= 23
52706c3fb27SDimitry Andric 
52806c3fb27SDimitry Andric _LIBCPP_END_NAMESPACE_STD
52906c3fb27SDimitry Andric 
53006c3fb27SDimitry Andric _LIBCPP_POP_MACROS
53106c3fb27SDimitry Andric 
53206c3fb27SDimitry Andric #endif // _LIBCPP___MDSPAN_EXTENTS_H
533