1639a0986SChristian Trott // -*- C++ -*- 2639a0986SChristian Trott //===----------------------------------------------------------------------===// 3639a0986SChristian Trott // 4639a0986SChristian Trott // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5639a0986SChristian Trott // See https://llvm.org/LICENSE.txt for license information. 6639a0986SChristian Trott // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7639a0986SChristian Trott // 8639a0986SChristian Trott // Kokkos v. 4.0 9639a0986SChristian Trott // Copyright (2022) National Technology & Engineering 10639a0986SChristian Trott // Solutions of Sandia, LLC (NTESS). 11639a0986SChristian Trott // 12639a0986SChristian Trott // Under the terms of Contract DE-NA0003525 with NTESS, 13639a0986SChristian Trott // the U.S. Government retains certain rights in this software. 14639a0986SChristian Trott // 15639a0986SChristian Trott //===---------------------------------------------------------------------===// 16639a0986SChristian Trott 17639a0986SChristian Trott #ifndef _LIBCPP___MDSPAN_LAYOUT_STRIDE_H 18639a0986SChristian Trott #define _LIBCPP___MDSPAN_LAYOUT_STRIDE_H 19639a0986SChristian Trott 20639a0986SChristian Trott #include <__assert> 215e19fd17SLouis Dionne #include <__concepts/same_as.h> 22639a0986SChristian Trott #include <__config> 23639a0986SChristian Trott #include <__fwd/mdspan.h> 24639a0986SChristian Trott #include <__mdspan/extents.h> 255e19fd17SLouis Dionne #include <__type_traits/common_type.h> 26639a0986SChristian Trott #include <__type_traits/is_constructible.h> 27639a0986SChristian Trott #include <__type_traits/is_convertible.h> 28*d6832a61SLouis Dionne #include <__type_traits/is_integral.h> 29639a0986SChristian Trott #include <__type_traits/is_nothrow_constructible.h> 305e19fd17SLouis Dionne #include <__type_traits/is_same.h> 31639a0986SChristian Trott #include <__utility/as_const.h> 32639a0986SChristian Trott #include <__utility/integer_sequence.h> 33639a0986SChristian Trott #include <__utility/swap.h> 34639a0986SChristian Trott #include <array> 35639a0986SChristian Trott #include <limits> 365e19fd17SLouis Dionne #include <span> 37639a0986SChristian Trott 38639a0986SChristian Trott #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 39639a0986SChristian Trott # pragma GCC system_header 40639a0986SChristian Trott #endif 41639a0986SChristian Trott 42639a0986SChristian Trott _LIBCPP_PUSH_MACROS 43639a0986SChristian Trott #include <__undef_macros> 44639a0986SChristian Trott 45639a0986SChristian Trott _LIBCPP_BEGIN_NAMESPACE_STD 46639a0986SChristian Trott 47639a0986SChristian Trott #if _LIBCPP_STD_VER >= 23 48639a0986SChristian Trott 49639a0986SChristian Trott namespace __mdspan_detail { 50639a0986SChristian Trott template <class _Layout, class _Mapping> 51639a0986SChristian Trott constexpr bool __is_mapping_of = 52639a0986SChristian Trott is_same_v<typename _Layout::template mapping<typename _Mapping::extents_type>, _Mapping>; 53639a0986SChristian Trott 54639a0986SChristian Trott template <class _Mapping> 55639a0986SChristian Trott concept __layout_mapping_alike = requires { 56639a0986SChristian Trott requires __is_mapping_of<typename _Mapping::layout_type, _Mapping>; 57639a0986SChristian Trott requires __is_extents_v<typename _Mapping::extents_type>; 58639a0986SChristian Trott { _Mapping::is_always_strided() } -> same_as<bool>; 59639a0986SChristian Trott { _Mapping::is_always_exhaustive() } -> same_as<bool>; 60639a0986SChristian Trott { _Mapping::is_always_unique() } -> same_as<bool>; 61639a0986SChristian Trott bool_constant<_Mapping::is_always_strided()>::value; 62639a0986SChristian Trott bool_constant<_Mapping::is_always_exhaustive()>::value; 63639a0986SChristian Trott bool_constant<_Mapping::is_always_unique()>::value; 64639a0986SChristian Trott }; 65639a0986SChristian Trott } // namespace __mdspan_detail 66639a0986SChristian Trott 67639a0986SChristian Trott template <class _Extents> 68639a0986SChristian Trott class layout_stride::mapping { 69639a0986SChristian Trott public: 70639a0986SChristian Trott static_assert(__mdspan_detail::__is_extents<_Extents>::value, 71639a0986SChristian Trott "layout_stride::mapping template argument must be a specialization of extents."); 72639a0986SChristian Trott 73639a0986SChristian Trott using extents_type = _Extents; 74639a0986SChristian Trott using index_type = typename extents_type::index_type; 75639a0986SChristian Trott using size_type = typename extents_type::size_type; 76639a0986SChristian Trott using rank_type = typename extents_type::rank_type; 77639a0986SChristian Trott using layout_type = layout_stride; 78639a0986SChristian Trott 79639a0986SChristian Trott private: 80639a0986SChristian Trott static constexpr rank_type __rank_ = extents_type::rank(); 81639a0986SChristian Trott 82639a0986SChristian Trott // Used for default construction check and mandates 83639a0986SChristian Trott _LIBCPP_HIDE_FROM_ABI static constexpr bool __required_span_size_is_representable(const extents_type& __ext) { 84639a0986SChristian Trott if constexpr (__rank_ == 0) 85639a0986SChristian Trott return true; 86639a0986SChristian Trott 87639a0986SChristian Trott index_type __prod = __ext.extent(0); 88639a0986SChristian Trott for (rank_type __r = 1; __r < __rank_; __r++) { 89639a0986SChristian Trott bool __overflowed = __builtin_mul_overflow(__prod, __ext.extent(__r), &__prod); 90639a0986SChristian Trott if (__overflowed) 91639a0986SChristian Trott return false; 92639a0986SChristian Trott } 93639a0986SChristian Trott return true; 94639a0986SChristian Trott } 95639a0986SChristian Trott 96639a0986SChristian Trott template <class _OtherIndexType> 97639a0986SChristian Trott _LIBCPP_HIDE_FROM_ABI static constexpr bool 98639a0986SChristian Trott __required_span_size_is_representable(const extents_type& __ext, span<_OtherIndexType, __rank_> __strides) { 99639a0986SChristian Trott if constexpr (__rank_ == 0) 100639a0986SChristian Trott return true; 101639a0986SChristian Trott 102639a0986SChristian Trott index_type __size = 1; 103639a0986SChristian Trott for (rank_type __r = 0; __r < __rank_; __r++) { 104639a0986SChristian Trott // We can only check correct conversion of _OtherIndexType if it is an integral 105639a0986SChristian Trott if constexpr (is_integral_v<_OtherIndexType>) { 106639a0986SChristian Trott using _CommonType = common_type_t<index_type, _OtherIndexType>; 107639a0986SChristian Trott if (static_cast<_CommonType>(__strides[__r]) > static_cast<_CommonType>(numeric_limits<index_type>::max())) 108639a0986SChristian Trott return false; 109639a0986SChristian Trott } 110639a0986SChristian Trott if (__ext.extent(__r) == static_cast<index_type>(0)) 111639a0986SChristian Trott return true; 112639a0986SChristian Trott index_type __prod = (__ext.extent(__r) - 1); 113639a0986SChristian Trott bool __overflowed_mul = __builtin_mul_overflow(__prod, static_cast<index_type>(__strides[__r]), &__prod); 114639a0986SChristian Trott if (__overflowed_mul) 115639a0986SChristian Trott return false; 116639a0986SChristian Trott bool __overflowed_add = __builtin_add_overflow(__size, __prod, &__size); 117639a0986SChristian Trott if (__overflowed_add) 118639a0986SChristian Trott return false; 119639a0986SChristian Trott } 120639a0986SChristian Trott return true; 121639a0986SChristian Trott } 122639a0986SChristian Trott 123639a0986SChristian Trott // compute offset of a strided layout mapping 124639a0986SChristian Trott template <class _StridedMapping> 125639a0986SChristian Trott _LIBCPP_HIDE_FROM_ABI static constexpr index_type __offset(const _StridedMapping& __mapping) { 126639a0986SChristian Trott if constexpr (_StridedMapping::extents_type::rank() == 0) { 127639a0986SChristian Trott return static_cast<index_type>(__mapping()); 128639a0986SChristian Trott } else if (__mapping.required_span_size() == static_cast<typename _StridedMapping::index_type>(0)) { 129639a0986SChristian Trott return static_cast<index_type>(0); 130639a0986SChristian Trott } else { 131639a0986SChristian Trott return [&]<size_t... _Pos>(index_sequence<_Pos...>) { 132639a0986SChristian Trott return static_cast<index_type>(__mapping((_Pos ? 0 : 0)...)); 133639a0986SChristian Trott }(make_index_sequence<__rank_>()); 134639a0986SChristian Trott } 135639a0986SChristian Trott } 136639a0986SChristian Trott 137639a0986SChristian Trott // compute the permutation for sorting the stride array 138639a0986SChristian Trott // we never actually sort the stride array 139639a0986SChristian Trott _LIBCPP_HIDE_FROM_ABI constexpr void __bubble_sort_by_strides(array<rank_type, __rank_>& __permute) const { 140639a0986SChristian Trott for (rank_type __i = __rank_ - 1; __i > 0; __i--) { 141639a0986SChristian Trott for (rank_type __r = 0; __r < __i; __r++) { 142639a0986SChristian Trott if (__strides_[__permute[__r]] > __strides_[__permute[__r + 1]]) { 143639a0986SChristian Trott swap(__permute[__r], __permute[__r + 1]); 144639a0986SChristian Trott } else { 145639a0986SChristian Trott // if two strides are the same then one of the associated extents must be 1 or 0 146639a0986SChristian Trott // both could be, but you can't have one larger than 1 come first 147639a0986SChristian Trott if ((__strides_[__permute[__r]] == __strides_[__permute[__r + 1]]) && 148639a0986SChristian Trott (__extents_.extent(__permute[__r]) > static_cast<index_type>(1))) 149639a0986SChristian Trott swap(__permute[__r], __permute[__r + 1]); 150639a0986SChristian Trott } 151639a0986SChristian Trott } 152639a0986SChristian Trott } 153639a0986SChristian Trott } 154639a0986SChristian Trott 1556b4b29f8SNikolas Klauser static_assert(extents_type::rank_dynamic() > 0 || __required_span_size_is_representable(extents_type()), 156639a0986SChristian Trott "layout_stride::mapping product of static extents must be representable as index_type."); 157639a0986SChristian Trott 158639a0986SChristian Trott public: 159639a0986SChristian Trott // [mdspan.layout.stride.cons], constructors 160639a0986SChristian Trott _LIBCPP_HIDE_FROM_ABI constexpr mapping() noexcept : __extents_(extents_type()) { 161639a0986SChristian Trott // Note the nominal precondition is covered by above static assert since 162639a0986SChristian Trott // if rank_dynamic is != 0 required_span_size is zero for default construction 163639a0986SChristian Trott if constexpr (__rank_ > 0) { 164639a0986SChristian Trott index_type __stride = 1; 165639a0986SChristian Trott for (rank_type __r = __rank_ - 1; __r > static_cast<rank_type>(0); __r--) { 166639a0986SChristian Trott __strides_[__r] = __stride; 167639a0986SChristian Trott __stride *= __extents_.extent(__r); 168639a0986SChristian Trott } 169639a0986SChristian Trott __strides_[0] = __stride; 170639a0986SChristian Trott } 171639a0986SChristian Trott } 172639a0986SChristian Trott 173639a0986SChristian Trott _LIBCPP_HIDE_FROM_ABI constexpr mapping(const mapping&) noexcept = default; 174639a0986SChristian Trott 175639a0986SChristian Trott template <class _OtherIndexType> 176639a0986SChristian Trott requires(is_convertible_v<const _OtherIndexType&, index_type> && 177639a0986SChristian Trott is_nothrow_constructible_v<index_type, const _OtherIndexType&>) 178639a0986SChristian Trott _LIBCPP_HIDE_FROM_ABI constexpr mapping(const extents_type& __ext, span<_OtherIndexType, __rank_> __strides) noexcept 179639a0986SChristian Trott : __extents_(__ext), __strides_([&]<size_t... _Pos>(index_sequence<_Pos...>) { 180639a0986SChristian Trott return __mdspan_detail::__possibly_empty_array<index_type, __rank_>{ 181639a0986SChristian Trott static_cast<index_type>(std::as_const(__strides[_Pos]))...}; 182639a0986SChristian Trott }(make_index_sequence<__rank_>())) { 183639a0986SChristian Trott _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( 184639a0986SChristian Trott ([&]<size_t... _Pos>(index_sequence<_Pos...>) { 185639a0986SChristian Trott // For integrals we can do a pre-conversion check, for other types not 186639a0986SChristian Trott if constexpr (is_integral_v<_OtherIndexType>) { 187639a0986SChristian Trott return ((__strides[_Pos] > static_cast<_OtherIndexType>(0)) && ... && true); 188639a0986SChristian Trott } else { 189639a0986SChristian Trott return ((static_cast<index_type>(__strides[_Pos]) > static_cast<index_type>(0)) && ... && true); 190639a0986SChristian Trott } 191639a0986SChristian Trott }(make_index_sequence<__rank_>())), 192639a0986SChristian Trott "layout_stride::mapping ctor: all strides must be greater than 0"); 193639a0986SChristian Trott _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( 194639a0986SChristian Trott __required_span_size_is_representable(__ext, __strides), 195639a0986SChristian Trott "layout_stride::mapping ctor: required span size is not representable as index_type."); 196639a0986SChristian Trott if constexpr (__rank_ > 1) { 197639a0986SChristian Trott _LIBCPP_ASSERT_UNCATEGORIZED( 198639a0986SChristian Trott ([&]<size_t... _Pos>(index_sequence<_Pos...>) { 199639a0986SChristian Trott // basically sort the dimensions based on strides and extents, sorting is represented in permute array 200639a0986SChristian Trott array<rank_type, __rank_> __permute{_Pos...}; 201639a0986SChristian Trott __bubble_sort_by_strides(__permute); 202639a0986SChristian Trott 203639a0986SChristian Trott // check that this permutations represents a growing set 204639a0986SChristian Trott for (rank_type __i = 1; __i < __rank_; __i++) 205639a0986SChristian Trott if (static_cast<index_type>(__strides[__permute[__i]]) < 206639a0986SChristian Trott static_cast<index_type>(__strides[__permute[__i - 1]]) * __extents_.extent(__permute[__i - 1])) 207639a0986SChristian Trott return false; 208639a0986SChristian Trott return true; 209639a0986SChristian Trott }(make_index_sequence<__rank_>())), 210639a0986SChristian Trott "layout_stride::mapping ctor: the provided extents and strides lead to a non-unique mapping"); 211639a0986SChristian Trott } 212639a0986SChristian Trott } 213639a0986SChristian Trott 214639a0986SChristian Trott template <class _OtherIndexType> 215639a0986SChristian Trott requires(is_convertible_v<const _OtherIndexType&, index_type> && 216639a0986SChristian Trott is_nothrow_constructible_v<index_type, const _OtherIndexType&>) 217639a0986SChristian Trott _LIBCPP_HIDE_FROM_ABI constexpr mapping(const extents_type& __ext, 218639a0986SChristian Trott const array<_OtherIndexType, __rank_>& __strides) noexcept 219639a0986SChristian Trott : mapping(__ext, span(__strides)) {} 220639a0986SChristian Trott 221639a0986SChristian Trott template <class _StridedLayoutMapping> 222639a0986SChristian Trott requires(__mdspan_detail::__layout_mapping_alike<_StridedLayoutMapping> && 223639a0986SChristian Trott is_constructible_v<extents_type, typename _StridedLayoutMapping::extents_type> && 224639a0986SChristian Trott _StridedLayoutMapping::is_always_unique() && _StridedLayoutMapping::is_always_strided()) 225639a0986SChristian Trott _LIBCPP_HIDE_FROM_ABI constexpr explicit( 226639a0986SChristian Trott !(is_convertible_v<typename _StridedLayoutMapping::extents_type, extents_type> && 227639a0986SChristian Trott (__mdspan_detail::__is_mapping_of<layout_left, _StridedLayoutMapping> || 228639a0986SChristian Trott __mdspan_detail::__is_mapping_of<layout_right, _StridedLayoutMapping> || 229639a0986SChristian Trott __mdspan_detail::__is_mapping_of<layout_stride, _StridedLayoutMapping>))) 230639a0986SChristian Trott mapping(const _StridedLayoutMapping& __other) noexcept 231639a0986SChristian Trott : __extents_(__other.extents()), __strides_([&]<size_t... _Pos>(index_sequence<_Pos...>) { 232639a0986SChristian Trott // stride() only compiles for rank > 0 233639a0986SChristian Trott if constexpr (__rank_ > 0) { 234639a0986SChristian Trott return __mdspan_detail::__possibly_empty_array<index_type, __rank_>{ 235639a0986SChristian Trott static_cast<index_type>(__other.stride(_Pos))...}; 236639a0986SChristian Trott } else { 237639a0986SChristian Trott return __mdspan_detail::__possibly_empty_array<index_type, 0>{}; 238639a0986SChristian Trott } 239639a0986SChristian Trott }(make_index_sequence<__rank_>())) { 240639a0986SChristian Trott // stride() only compiles for rank > 0 241639a0986SChristian Trott if constexpr (__rank_ > 0) { 242639a0986SChristian Trott _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( 243639a0986SChristian Trott ([&]<size_t... _Pos>(index_sequence<_Pos...>) { 244639a0986SChristian Trott return ((static_cast<index_type>(__other.stride(_Pos)) > static_cast<index_type>(0)) && ... && true); 245639a0986SChristian Trott }(make_index_sequence<__rank_>())), 246639a0986SChristian Trott "layout_stride::mapping converting ctor: all strides must be greater than 0"); 247639a0986SChristian Trott } 248639a0986SChristian Trott _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( 249639a0986SChristian Trott __mdspan_detail::__is_representable_as<index_type>(__other.required_span_size()), 250639a0986SChristian Trott "layout_stride::mapping converting ctor: other.required_span_size() must be representable as index_type."); 251639a0986SChristian Trott _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(static_cast<index_type>(0) == __offset(__other), 252639a0986SChristian Trott "layout_stride::mapping converting ctor: base offset of mapping must be zero."); 253639a0986SChristian Trott } 254639a0986SChristian Trott 255639a0986SChristian Trott _LIBCPP_HIDE_FROM_ABI constexpr mapping& operator=(const mapping&) noexcept = default; 256639a0986SChristian Trott 257639a0986SChristian Trott // [mdspan.layout.stride.obs], observers 258639a0986SChristian Trott _LIBCPP_HIDE_FROM_ABI constexpr const extents_type& extents() const noexcept { return __extents_; } 259639a0986SChristian Trott 260639a0986SChristian Trott _LIBCPP_HIDE_FROM_ABI constexpr array<index_type, __rank_> strides() const noexcept { 261639a0986SChristian Trott return [&]<size_t... _Pos>(index_sequence<_Pos...>) { 262639a0986SChristian Trott return array<index_type, __rank_>{__strides_[_Pos]...}; 263639a0986SChristian Trott }(make_index_sequence<__rank_>()); 264639a0986SChristian Trott } 265639a0986SChristian Trott 266639a0986SChristian Trott _LIBCPP_HIDE_FROM_ABI constexpr index_type required_span_size() const noexcept { 267639a0986SChristian Trott if constexpr (__rank_ == 0) { 268639a0986SChristian Trott return static_cast<index_type>(1); 269639a0986SChristian Trott } else { 270639a0986SChristian Trott return [&]<size_t... _Pos>(index_sequence<_Pos...>) { 271639a0986SChristian Trott if ((__extents_.extent(_Pos) * ... * 1) == 0) 272639a0986SChristian Trott return static_cast<index_type>(0); 273639a0986SChristian Trott else 274639a0986SChristian Trott return static_cast<index_type>( 275639a0986SChristian Trott static_cast<index_type>(1) + 276639a0986SChristian Trott (((__extents_.extent(_Pos) - static_cast<index_type>(1)) * __strides_[_Pos]) + ... + 277639a0986SChristian Trott static_cast<index_type>(0))); 278639a0986SChristian Trott }(make_index_sequence<__rank_>()); 279639a0986SChristian Trott } 280639a0986SChristian Trott } 281639a0986SChristian Trott 282639a0986SChristian Trott template <class... _Indices> 283639a0986SChristian Trott requires((sizeof...(_Indices) == __rank_) && (is_convertible_v<_Indices, index_type> && ...) && 284639a0986SChristian Trott (is_nothrow_constructible_v<index_type, _Indices> && ...)) 285639a0986SChristian Trott _LIBCPP_HIDE_FROM_ABI constexpr index_type operator()(_Indices... __idx) const noexcept { 286639a0986SChristian Trott // Mappings are generally meant to be used for accessing allocations and are meant to guarantee to never 287639a0986SChristian Trott // return a value exceeding required_span_size(), which is used to know how large an allocation one needs 288639a0986SChristian Trott // Thus, this is a canonical point in multi-dimensional data structures to make invalid element access checks 289639a0986SChristian Trott // However, mdspan does check this on its own, so for now we avoid double checking in hardened mode 290639a0986SChristian Trott _LIBCPP_ASSERT_UNCATEGORIZED(__mdspan_detail::__is_multidimensional_index_in(__extents_, __idx...), 291639a0986SChristian Trott "layout_stride::mapping: out of bounds indexing"); 292639a0986SChristian Trott return [&]<size_t... _Pos>(index_sequence<_Pos...>) { 293639a0986SChristian Trott return ((static_cast<index_type>(__idx) * __strides_[_Pos]) + ... + index_type(0)); 294639a0986SChristian Trott }(make_index_sequence<sizeof...(_Indices)>()); 295639a0986SChristian Trott } 296639a0986SChristian Trott 297639a0986SChristian Trott _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_unique() noexcept { return true; } 298639a0986SChristian Trott _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_exhaustive() noexcept { return false; } 299639a0986SChristian Trott _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_strided() noexcept { return true; } 300639a0986SChristian Trott 301639a0986SChristian Trott _LIBCPP_HIDE_FROM_ABI static constexpr bool is_unique() noexcept { return true; } 302639a0986SChristian Trott // The answer of this function is fairly complex in the case where one or more 303639a0986SChristian Trott // extents are zero. 304639a0986SChristian Trott // Technically it is meaningless to query is_exhaustive() in that case, but unfortunately 305639a0986SChristian Trott // the way the standard defines this function, we can't give a simple true or false then. 306639a0986SChristian Trott _LIBCPP_HIDE_FROM_ABI constexpr bool is_exhaustive() const noexcept { 307639a0986SChristian Trott if constexpr (__rank_ == 0) 308639a0986SChristian Trott return true; 309639a0986SChristian Trott else { 310639a0986SChristian Trott index_type __span_size = required_span_size(); 311639a0986SChristian Trott if (__span_size == static_cast<index_type>(0)) { 312639a0986SChristian Trott if constexpr (__rank_ == 1) 313639a0986SChristian Trott return __strides_[0] == 1; 314639a0986SChristian Trott else { 315639a0986SChristian Trott rank_type __r_largest = 0; 316639a0986SChristian Trott for (rank_type __r = 1; __r < __rank_; __r++) 317639a0986SChristian Trott if (__strides_[__r] > __strides_[__r_largest]) 318639a0986SChristian Trott __r_largest = __r; 319639a0986SChristian Trott for (rank_type __r = 0; __r < __rank_; __r++) 320639a0986SChristian Trott if (__extents_.extent(__r) == 0 && __r != __r_largest) 321639a0986SChristian Trott return false; 322639a0986SChristian Trott return true; 323639a0986SChristian Trott } 324639a0986SChristian Trott } else { 325639a0986SChristian Trott return required_span_size() == [&]<size_t... _Pos>(index_sequence<_Pos...>) { 326639a0986SChristian Trott return (__extents_.extent(_Pos) * ... * static_cast<index_type>(1)); 327639a0986SChristian Trott }(make_index_sequence<__rank_>()); 328639a0986SChristian Trott } 329639a0986SChristian Trott } 330639a0986SChristian Trott } 331639a0986SChristian Trott _LIBCPP_HIDE_FROM_ABI static constexpr bool is_strided() noexcept { return true; } 332639a0986SChristian Trott 333639a0986SChristian Trott // according to the standard layout_stride does not have a constraint on stride(r) for rank>0 334639a0986SChristian Trott // it still has the precondition though 335639a0986SChristian Trott _LIBCPP_HIDE_FROM_ABI constexpr index_type stride(rank_type __r) const noexcept { 336639a0986SChristian Trott _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__r < __rank_, "layout_stride::mapping::stride(): invalid rank index"); 337639a0986SChristian Trott return __strides_[__r]; 338639a0986SChristian Trott } 339639a0986SChristian Trott 340639a0986SChristian Trott template <class _OtherMapping> 341639a0986SChristian Trott requires(__mdspan_detail::__layout_mapping_alike<_OtherMapping> && 342639a0986SChristian Trott (_OtherMapping::extents_type::rank() == __rank_) && _OtherMapping::is_always_strided()) 343639a0986SChristian Trott _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const mapping& __lhs, const _OtherMapping& __rhs) noexcept { 344639a0986SChristian Trott if (__offset(__rhs)) 345639a0986SChristian Trott return false; 346639a0986SChristian Trott if constexpr (__rank_ == 0) 347639a0986SChristian Trott return true; 348639a0986SChristian Trott else { 349639a0986SChristian Trott return __lhs.extents() == __rhs.extents() && [&]<size_t... _Pos>(index_sequence<_Pos...>) { 350639a0986SChristian Trott // avoid warning when comparing signed and unsigner integers and pick the wider of two types 351639a0986SChristian Trott using _CommonType = common_type_t<index_type, typename _OtherMapping::index_type>; 352639a0986SChristian Trott return ((static_cast<_CommonType>(__lhs.stride(_Pos)) == static_cast<_CommonType>(__rhs.stride(_Pos))) && ... && 353639a0986SChristian Trott true); 354639a0986SChristian Trott }(make_index_sequence<__rank_>()); 355639a0986SChristian Trott } 356639a0986SChristian Trott } 357639a0986SChristian Trott 358639a0986SChristian Trott private: 359639a0986SChristian Trott _LIBCPP_NO_UNIQUE_ADDRESS extents_type __extents_{}; 360639a0986SChristian Trott _LIBCPP_NO_UNIQUE_ADDRESS __mdspan_detail::__possibly_empty_array<index_type, __rank_> __strides_{}; 361639a0986SChristian Trott }; 362639a0986SChristian Trott 363639a0986SChristian Trott #endif // _LIBCPP_STD_VER >= 23 364639a0986SChristian Trott 365639a0986SChristian Trott _LIBCPP_END_NAMESPACE_STD 366639a0986SChristian Trott 367639a0986SChristian Trott _LIBCPP_POP_MACROS 368639a0986SChristian Trott 369639a0986SChristian Trott #endif // _LIBCPP___MDSPAN_LAYOUT_STRIDE_H 370