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