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