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