15f757f3fSDimitry Andric // -*- C++ -*- 25f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 35f757f3fSDimitry Andric // 45f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 55f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 65f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 75f757f3fSDimitry Andric // 85f757f3fSDimitry Andric // Kokkos v. 4.0 95f757f3fSDimitry Andric // Copyright (2022) National Technology & Engineering 105f757f3fSDimitry Andric // Solutions of Sandia, LLC (NTESS). 115f757f3fSDimitry Andric // 125f757f3fSDimitry Andric // Under the terms of Contract DE-NA0003525 with NTESS, 135f757f3fSDimitry Andric // the U.S. Government retains certain rights in this software. 145f757f3fSDimitry Andric // 155f757f3fSDimitry Andric //===---------------------------------------------------------------------===// 165f757f3fSDimitry Andric 175f757f3fSDimitry Andric #ifndef _LIBCPP___MDSPAN_LAYOUT_STRIDE_H 185f757f3fSDimitry Andric #define _LIBCPP___MDSPAN_LAYOUT_STRIDE_H 195f757f3fSDimitry Andric 205f757f3fSDimitry Andric #include <__assert> 215f757f3fSDimitry Andric #include <__config> 225f757f3fSDimitry Andric #include <__fwd/mdspan.h> 235f757f3fSDimitry Andric #include <__mdspan/extents.h> 245f757f3fSDimitry Andric #include <__type_traits/is_constructible.h> 255f757f3fSDimitry Andric #include <__type_traits/is_convertible.h> 265f757f3fSDimitry Andric #include <__type_traits/is_nothrow_constructible.h> 275f757f3fSDimitry Andric #include <__utility/as_const.h> 285f757f3fSDimitry Andric #include <__utility/integer_sequence.h> 295f757f3fSDimitry Andric #include <__utility/swap.h> 305f757f3fSDimitry Andric #include <array> 315f757f3fSDimitry Andric #include <cinttypes> 325f757f3fSDimitry Andric #include <cstddef> 335f757f3fSDimitry Andric #include <limits> 345f757f3fSDimitry Andric 355f757f3fSDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 365f757f3fSDimitry Andric # pragma GCC system_header 375f757f3fSDimitry Andric #endif 385f757f3fSDimitry Andric 395f757f3fSDimitry Andric _LIBCPP_PUSH_MACROS 405f757f3fSDimitry Andric #include <__undef_macros> 415f757f3fSDimitry Andric 425f757f3fSDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD 435f757f3fSDimitry Andric 445f757f3fSDimitry Andric #if _LIBCPP_STD_VER >= 23 455f757f3fSDimitry Andric 465f757f3fSDimitry Andric namespace __mdspan_detail { 475f757f3fSDimitry Andric template <class _Layout, class _Mapping> 485f757f3fSDimitry Andric constexpr bool __is_mapping_of = 495f757f3fSDimitry Andric is_same_v<typename _Layout::template mapping<typename _Mapping::extents_type>, _Mapping>; 505f757f3fSDimitry Andric 515f757f3fSDimitry Andric template <class _Mapping> 525f757f3fSDimitry Andric concept __layout_mapping_alike = requires { 535f757f3fSDimitry Andric requires __is_mapping_of<typename _Mapping::layout_type, _Mapping>; 545f757f3fSDimitry Andric requires __is_extents_v<typename _Mapping::extents_type>; 555f757f3fSDimitry Andric { _Mapping::is_always_strided() } -> same_as<bool>; 565f757f3fSDimitry Andric { _Mapping::is_always_exhaustive() } -> same_as<bool>; 575f757f3fSDimitry Andric { _Mapping::is_always_unique() } -> same_as<bool>; 585f757f3fSDimitry Andric bool_constant<_Mapping::is_always_strided()>::value; 595f757f3fSDimitry Andric bool_constant<_Mapping::is_always_exhaustive()>::value; 605f757f3fSDimitry Andric bool_constant<_Mapping::is_always_unique()>::value; 615f757f3fSDimitry Andric }; 625f757f3fSDimitry Andric } // namespace __mdspan_detail 635f757f3fSDimitry Andric 645f757f3fSDimitry Andric template <class _Extents> 655f757f3fSDimitry Andric class layout_stride::mapping { 665f757f3fSDimitry Andric public: 675f757f3fSDimitry Andric static_assert(__mdspan_detail::__is_extents<_Extents>::value, 685f757f3fSDimitry Andric "layout_stride::mapping template argument must be a specialization of extents."); 695f757f3fSDimitry Andric 705f757f3fSDimitry Andric using extents_type = _Extents; 715f757f3fSDimitry Andric using index_type = typename extents_type::index_type; 725f757f3fSDimitry Andric using size_type = typename extents_type::size_type; 735f757f3fSDimitry Andric using rank_type = typename extents_type::rank_type; 745f757f3fSDimitry Andric using layout_type = layout_stride; 755f757f3fSDimitry Andric 765f757f3fSDimitry Andric private: 775f757f3fSDimitry Andric static constexpr rank_type __rank_ = extents_type::rank(); 785f757f3fSDimitry Andric 795f757f3fSDimitry Andric // Used for default construction check and mandates 805f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI static constexpr bool __required_span_size_is_representable(const extents_type& __ext) { 815f757f3fSDimitry Andric if constexpr (__rank_ == 0) 825f757f3fSDimitry Andric return true; 835f757f3fSDimitry Andric 845f757f3fSDimitry Andric index_type __prod = __ext.extent(0); 855f757f3fSDimitry Andric for (rank_type __r = 1; __r < __rank_; __r++) { 865f757f3fSDimitry Andric bool __overflowed = __builtin_mul_overflow(__prod, __ext.extent(__r), &__prod); 875f757f3fSDimitry Andric if (__overflowed) 885f757f3fSDimitry Andric return false; 895f757f3fSDimitry Andric } 905f757f3fSDimitry Andric return true; 915f757f3fSDimitry Andric } 925f757f3fSDimitry Andric 935f757f3fSDimitry Andric template <class _OtherIndexType> 945f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI static constexpr bool 955f757f3fSDimitry Andric __required_span_size_is_representable(const extents_type& __ext, span<_OtherIndexType, __rank_> __strides) { 965f757f3fSDimitry Andric if constexpr (__rank_ == 0) 975f757f3fSDimitry Andric return true; 985f757f3fSDimitry Andric 995f757f3fSDimitry Andric index_type __size = 1; 1005f757f3fSDimitry Andric for (rank_type __r = 0; __r < __rank_; __r++) { 1015f757f3fSDimitry Andric // We can only check correct conversion of _OtherIndexType if it is an integral 1025f757f3fSDimitry Andric if constexpr (is_integral_v<_OtherIndexType>) { 1035f757f3fSDimitry Andric using _CommonType = common_type_t<index_type, _OtherIndexType>; 1045f757f3fSDimitry Andric if (static_cast<_CommonType>(__strides[__r]) > static_cast<_CommonType>(numeric_limits<index_type>::max())) 1055f757f3fSDimitry Andric return false; 1065f757f3fSDimitry Andric } 1075f757f3fSDimitry Andric if (__ext.extent(__r) == static_cast<index_type>(0)) 1085f757f3fSDimitry Andric return true; 1095f757f3fSDimitry Andric index_type __prod = (__ext.extent(__r) - 1); 1105f757f3fSDimitry Andric bool __overflowed_mul = __builtin_mul_overflow(__prod, static_cast<index_type>(__strides[__r]), &__prod); 1115f757f3fSDimitry Andric if (__overflowed_mul) 1125f757f3fSDimitry Andric return false; 1135f757f3fSDimitry Andric bool __overflowed_add = __builtin_add_overflow(__size, __prod, &__size); 1145f757f3fSDimitry Andric if (__overflowed_add) 1155f757f3fSDimitry Andric return false; 1165f757f3fSDimitry Andric } 1175f757f3fSDimitry Andric return true; 1185f757f3fSDimitry Andric } 1195f757f3fSDimitry Andric 1205f757f3fSDimitry Andric // compute offset of a strided layout mapping 1215f757f3fSDimitry Andric template <class _StridedMapping> 1225f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI static constexpr index_type __offset(const _StridedMapping& __mapping) { 1235f757f3fSDimitry Andric if constexpr (_StridedMapping::extents_type::rank() == 0) { 1245f757f3fSDimitry Andric return static_cast<index_type>(__mapping()); 1255f757f3fSDimitry Andric } else if (__mapping.required_span_size() == static_cast<typename _StridedMapping::index_type>(0)) { 1265f757f3fSDimitry Andric return static_cast<index_type>(0); 1275f757f3fSDimitry Andric } else { 1285f757f3fSDimitry Andric return [&]<size_t... _Pos>(index_sequence<_Pos...>) { 1295f757f3fSDimitry Andric return static_cast<index_type>(__mapping((_Pos ? 0 : 0)...)); 1305f757f3fSDimitry Andric }(make_index_sequence<__rank_>()); 1315f757f3fSDimitry Andric } 1325f757f3fSDimitry Andric } 1335f757f3fSDimitry Andric 1345f757f3fSDimitry Andric // compute the permutation for sorting the stride array 1355f757f3fSDimitry Andric // we never actually sort the stride array 1365f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr void __bubble_sort_by_strides(array<rank_type, __rank_>& __permute) const { 1375f757f3fSDimitry Andric for (rank_type __i = __rank_ - 1; __i > 0; __i--) { 1385f757f3fSDimitry Andric for (rank_type __r = 0; __r < __i; __r++) { 1395f757f3fSDimitry Andric if (__strides_[__permute[__r]] > __strides_[__permute[__r + 1]]) { 1405f757f3fSDimitry Andric swap(__permute[__r], __permute[__r + 1]); 1415f757f3fSDimitry Andric } else { 1425f757f3fSDimitry Andric // if two strides are the same then one of the associated extents must be 1 or 0 1435f757f3fSDimitry Andric // both could be, but you can't have one larger than 1 come first 1445f757f3fSDimitry Andric if ((__strides_[__permute[__r]] == __strides_[__permute[__r + 1]]) && 1455f757f3fSDimitry Andric (__extents_.extent(__permute[__r]) > static_cast<index_type>(1))) 1465f757f3fSDimitry Andric swap(__permute[__r], __permute[__r + 1]); 1475f757f3fSDimitry Andric } 1485f757f3fSDimitry Andric } 1495f757f3fSDimitry Andric } 1505f757f3fSDimitry Andric } 1515f757f3fSDimitry Andric 152*0fca6ea1SDimitry Andric static_assert(extents_type::rank_dynamic() > 0 || __required_span_size_is_representable(extents_type()), 1535f757f3fSDimitry Andric "layout_stride::mapping product of static extents must be representable as index_type."); 1545f757f3fSDimitry Andric 1555f757f3fSDimitry Andric public: 1565f757f3fSDimitry Andric // [mdspan.layout.stride.cons], constructors 1575f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr mapping() noexcept : __extents_(extents_type()) { 1585f757f3fSDimitry Andric // Note the nominal precondition is covered by above static assert since 1595f757f3fSDimitry Andric // if rank_dynamic is != 0 required_span_size is zero for default construction 1605f757f3fSDimitry Andric if constexpr (__rank_ > 0) { 1615f757f3fSDimitry Andric index_type __stride = 1; 1625f757f3fSDimitry Andric for (rank_type __r = __rank_ - 1; __r > static_cast<rank_type>(0); __r--) { 1635f757f3fSDimitry Andric __strides_[__r] = __stride; 1645f757f3fSDimitry Andric __stride *= __extents_.extent(__r); 1655f757f3fSDimitry Andric } 1665f757f3fSDimitry Andric __strides_[0] = __stride; 1675f757f3fSDimitry Andric } 1685f757f3fSDimitry Andric } 1695f757f3fSDimitry Andric 1705f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr mapping(const mapping&) noexcept = default; 1715f757f3fSDimitry Andric 1725f757f3fSDimitry Andric template <class _OtherIndexType> 1735f757f3fSDimitry Andric requires(is_convertible_v<const _OtherIndexType&, index_type> && 1745f757f3fSDimitry Andric is_nothrow_constructible_v<index_type, const _OtherIndexType&>) 1755f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr mapping(const extents_type& __ext, span<_OtherIndexType, __rank_> __strides) noexcept 1765f757f3fSDimitry Andric : __extents_(__ext), __strides_([&]<size_t... _Pos>(index_sequence<_Pos...>) { 1775f757f3fSDimitry Andric return __mdspan_detail::__possibly_empty_array<index_type, __rank_>{ 1785f757f3fSDimitry Andric static_cast<index_type>(std::as_const(__strides[_Pos]))...}; 1795f757f3fSDimitry Andric }(make_index_sequence<__rank_>())) { 1805f757f3fSDimitry Andric _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( 1815f757f3fSDimitry Andric ([&]<size_t... _Pos>(index_sequence<_Pos...>) { 1825f757f3fSDimitry Andric // For integrals we can do a pre-conversion check, for other types not 1835f757f3fSDimitry Andric if constexpr (is_integral_v<_OtherIndexType>) { 1845f757f3fSDimitry Andric return ((__strides[_Pos] > static_cast<_OtherIndexType>(0)) && ... && true); 1855f757f3fSDimitry Andric } else { 1865f757f3fSDimitry Andric return ((static_cast<index_type>(__strides[_Pos]) > static_cast<index_type>(0)) && ... && true); 1875f757f3fSDimitry Andric } 1885f757f3fSDimitry Andric }(make_index_sequence<__rank_>())), 1895f757f3fSDimitry Andric "layout_stride::mapping ctor: all strides must be greater than 0"); 1905f757f3fSDimitry Andric _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( 1915f757f3fSDimitry Andric __required_span_size_is_representable(__ext, __strides), 1925f757f3fSDimitry Andric "layout_stride::mapping ctor: required span size is not representable as index_type."); 1935f757f3fSDimitry Andric if constexpr (__rank_ > 1) { 1945f757f3fSDimitry Andric _LIBCPP_ASSERT_UNCATEGORIZED( 1955f757f3fSDimitry Andric ([&]<size_t... _Pos>(index_sequence<_Pos...>) { 1965f757f3fSDimitry Andric // basically sort the dimensions based on strides and extents, sorting is represented in permute array 1975f757f3fSDimitry Andric array<rank_type, __rank_> __permute{_Pos...}; 1985f757f3fSDimitry Andric __bubble_sort_by_strides(__permute); 1995f757f3fSDimitry Andric 2005f757f3fSDimitry Andric // check that this permutations represents a growing set 2015f757f3fSDimitry Andric for (rank_type __i = 1; __i < __rank_; __i++) 2025f757f3fSDimitry Andric if (static_cast<index_type>(__strides[__permute[__i]]) < 2035f757f3fSDimitry Andric static_cast<index_type>(__strides[__permute[__i - 1]]) * __extents_.extent(__permute[__i - 1])) 2045f757f3fSDimitry Andric return false; 2055f757f3fSDimitry Andric return true; 2065f757f3fSDimitry Andric }(make_index_sequence<__rank_>())), 2075f757f3fSDimitry Andric "layout_stride::mapping ctor: the provided extents and strides lead to a non-unique mapping"); 2085f757f3fSDimitry Andric } 2095f757f3fSDimitry Andric } 2105f757f3fSDimitry Andric 2115f757f3fSDimitry Andric template <class _OtherIndexType> 2125f757f3fSDimitry Andric requires(is_convertible_v<const _OtherIndexType&, index_type> && 2135f757f3fSDimitry Andric is_nothrow_constructible_v<index_type, const _OtherIndexType&>) 2145f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr mapping(const extents_type& __ext, 2155f757f3fSDimitry Andric const array<_OtherIndexType, __rank_>& __strides) noexcept 2165f757f3fSDimitry Andric : mapping(__ext, span(__strides)) {} 2175f757f3fSDimitry Andric 2185f757f3fSDimitry Andric template <class _StridedLayoutMapping> 2195f757f3fSDimitry Andric requires(__mdspan_detail::__layout_mapping_alike<_StridedLayoutMapping> && 2205f757f3fSDimitry Andric is_constructible_v<extents_type, typename _StridedLayoutMapping::extents_type> && 2215f757f3fSDimitry Andric _StridedLayoutMapping::is_always_unique() && _StridedLayoutMapping::is_always_strided()) 2225f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr explicit( 2235f757f3fSDimitry Andric !(is_convertible_v<typename _StridedLayoutMapping::extents_type, extents_type> && 2245f757f3fSDimitry Andric (__mdspan_detail::__is_mapping_of<layout_left, _StridedLayoutMapping> || 2255f757f3fSDimitry Andric __mdspan_detail::__is_mapping_of<layout_right, _StridedLayoutMapping> || 2265f757f3fSDimitry Andric __mdspan_detail::__is_mapping_of<layout_stride, _StridedLayoutMapping>))) 2275f757f3fSDimitry Andric mapping(const _StridedLayoutMapping& __other) noexcept 2285f757f3fSDimitry Andric : __extents_(__other.extents()), __strides_([&]<size_t... _Pos>(index_sequence<_Pos...>) { 2295f757f3fSDimitry Andric // stride() only compiles for rank > 0 2305f757f3fSDimitry Andric if constexpr (__rank_ > 0) { 2315f757f3fSDimitry Andric return __mdspan_detail::__possibly_empty_array<index_type, __rank_>{ 2325f757f3fSDimitry Andric static_cast<index_type>(__other.stride(_Pos))...}; 2335f757f3fSDimitry Andric } else { 2345f757f3fSDimitry Andric return __mdspan_detail::__possibly_empty_array<index_type, 0>{}; 2355f757f3fSDimitry Andric } 2365f757f3fSDimitry Andric }(make_index_sequence<__rank_>())) { 2375f757f3fSDimitry Andric // stride() only compiles for rank > 0 2385f757f3fSDimitry Andric if constexpr (__rank_ > 0) { 2395f757f3fSDimitry Andric _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( 2405f757f3fSDimitry Andric ([&]<size_t... _Pos>(index_sequence<_Pos...>) { 2415f757f3fSDimitry Andric return ((static_cast<index_type>(__other.stride(_Pos)) > static_cast<index_type>(0)) && ... && true); 2425f757f3fSDimitry Andric }(make_index_sequence<__rank_>())), 2435f757f3fSDimitry Andric "layout_stride::mapping converting ctor: all strides must be greater than 0"); 2445f757f3fSDimitry Andric } 2455f757f3fSDimitry Andric _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( 2465f757f3fSDimitry Andric __mdspan_detail::__is_representable_as<index_type>(__other.required_span_size()), 2475f757f3fSDimitry Andric "layout_stride::mapping converting ctor: other.required_span_size() must be representable as index_type."); 2485f757f3fSDimitry Andric _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(static_cast<index_type>(0) == __offset(__other), 2495f757f3fSDimitry Andric "layout_stride::mapping converting ctor: base offset of mapping must be zero."); 2505f757f3fSDimitry Andric } 2515f757f3fSDimitry Andric 2525f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr mapping& operator=(const mapping&) noexcept = default; 2535f757f3fSDimitry Andric 2545f757f3fSDimitry Andric // [mdspan.layout.stride.obs], observers 2555f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr const extents_type& extents() const noexcept { return __extents_; } 2565f757f3fSDimitry Andric 2575f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr array<index_type, __rank_> strides() const noexcept { 2585f757f3fSDimitry Andric return [&]<size_t... _Pos>(index_sequence<_Pos...>) { 2595f757f3fSDimitry Andric return array<index_type, __rank_>{__strides_[_Pos]...}; 2605f757f3fSDimitry Andric }(make_index_sequence<__rank_>()); 2615f757f3fSDimitry Andric } 2625f757f3fSDimitry Andric 2635f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr index_type required_span_size() const noexcept { 2645f757f3fSDimitry Andric if constexpr (__rank_ == 0) { 2655f757f3fSDimitry Andric return static_cast<index_type>(1); 2665f757f3fSDimitry Andric } else { 2675f757f3fSDimitry Andric return [&]<size_t... _Pos>(index_sequence<_Pos...>) { 2685f757f3fSDimitry Andric if ((__extents_.extent(_Pos) * ... * 1) == 0) 2695f757f3fSDimitry Andric return static_cast<index_type>(0); 2705f757f3fSDimitry Andric else 2715f757f3fSDimitry Andric return static_cast<index_type>( 2725f757f3fSDimitry Andric static_cast<index_type>(1) + 2735f757f3fSDimitry Andric (((__extents_.extent(_Pos) - static_cast<index_type>(1)) * __strides_[_Pos]) + ... + 2745f757f3fSDimitry Andric static_cast<index_type>(0))); 2755f757f3fSDimitry Andric }(make_index_sequence<__rank_>()); 2765f757f3fSDimitry Andric } 2775f757f3fSDimitry Andric } 2785f757f3fSDimitry Andric 2795f757f3fSDimitry Andric template <class... _Indices> 2805f757f3fSDimitry Andric requires((sizeof...(_Indices) == __rank_) && (is_convertible_v<_Indices, index_type> && ...) && 2815f757f3fSDimitry Andric (is_nothrow_constructible_v<index_type, _Indices> && ...)) 2825f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr index_type operator()(_Indices... __idx) const noexcept { 2835f757f3fSDimitry Andric // Mappings are generally meant to be used for accessing allocations and are meant to guarantee to never 2845f757f3fSDimitry Andric // return a value exceeding required_span_size(), which is used to know how large an allocation one needs 2855f757f3fSDimitry Andric // Thus, this is a canonical point in multi-dimensional data structures to make invalid element access checks 2865f757f3fSDimitry Andric // However, mdspan does check this on its own, so for now we avoid double checking in hardened mode 2875f757f3fSDimitry Andric _LIBCPP_ASSERT_UNCATEGORIZED(__mdspan_detail::__is_multidimensional_index_in(__extents_, __idx...), 2885f757f3fSDimitry Andric "layout_stride::mapping: out of bounds indexing"); 2895f757f3fSDimitry Andric return [&]<size_t... _Pos>(index_sequence<_Pos...>) { 2905f757f3fSDimitry Andric return ((static_cast<index_type>(__idx) * __strides_[_Pos]) + ... + index_type(0)); 2915f757f3fSDimitry Andric }(make_index_sequence<sizeof...(_Indices)>()); 2925f757f3fSDimitry Andric } 2935f757f3fSDimitry Andric 2945f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_unique() noexcept { return true; } 2955f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_exhaustive() noexcept { return false; } 2965f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_strided() noexcept { return true; } 2975f757f3fSDimitry Andric 2985f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI static constexpr bool is_unique() noexcept { return true; } 2995f757f3fSDimitry Andric // The answer of this function is fairly complex in the case where one or more 3005f757f3fSDimitry Andric // extents are zero. 3015f757f3fSDimitry Andric // Technically it is meaningless to query is_exhaustive() in that case, but unfortunately 3025f757f3fSDimitry Andric // the way the standard defines this function, we can't give a simple true or false then. 3035f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr bool is_exhaustive() const noexcept { 3045f757f3fSDimitry Andric if constexpr (__rank_ == 0) 3055f757f3fSDimitry Andric return true; 3065f757f3fSDimitry Andric else { 3075f757f3fSDimitry Andric index_type __span_size = required_span_size(); 3085f757f3fSDimitry Andric if (__span_size == static_cast<index_type>(0)) { 3095f757f3fSDimitry Andric if constexpr (__rank_ == 1) 3105f757f3fSDimitry Andric return __strides_[0] == 1; 3115f757f3fSDimitry Andric else { 3125f757f3fSDimitry Andric rank_type __r_largest = 0; 3135f757f3fSDimitry Andric for (rank_type __r = 1; __r < __rank_; __r++) 3145f757f3fSDimitry Andric if (__strides_[__r] > __strides_[__r_largest]) 3155f757f3fSDimitry Andric __r_largest = __r; 3165f757f3fSDimitry Andric for (rank_type __r = 0; __r < __rank_; __r++) 3175f757f3fSDimitry Andric if (__extents_.extent(__r) == 0 && __r != __r_largest) 3185f757f3fSDimitry Andric return false; 3195f757f3fSDimitry Andric return true; 3205f757f3fSDimitry Andric } 3215f757f3fSDimitry Andric } else { 3225f757f3fSDimitry Andric return required_span_size() == [&]<size_t... _Pos>(index_sequence<_Pos...>) { 3235f757f3fSDimitry Andric return (__extents_.extent(_Pos) * ... * static_cast<index_type>(1)); 3245f757f3fSDimitry Andric }(make_index_sequence<__rank_>()); 3255f757f3fSDimitry Andric } 3265f757f3fSDimitry Andric } 3275f757f3fSDimitry Andric } 3285f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI static constexpr bool is_strided() noexcept { return true; } 3295f757f3fSDimitry Andric 3305f757f3fSDimitry Andric // according to the standard layout_stride does not have a constraint on stride(r) for rank>0 3315f757f3fSDimitry Andric // it still has the precondition though 3325f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr index_type stride(rank_type __r) const noexcept { 3335f757f3fSDimitry Andric _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__r < __rank_, "layout_stride::mapping::stride(): invalid rank index"); 3345f757f3fSDimitry Andric return __strides_[__r]; 3355f757f3fSDimitry Andric } 3365f757f3fSDimitry Andric 3375f757f3fSDimitry Andric template <class _OtherMapping> 3385f757f3fSDimitry Andric requires(__mdspan_detail::__layout_mapping_alike<_OtherMapping> && 3395f757f3fSDimitry Andric (_OtherMapping::extents_type::rank() == __rank_) && _OtherMapping::is_always_strided()) 3405f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const mapping& __lhs, const _OtherMapping& __rhs) noexcept { 3415f757f3fSDimitry Andric if (__offset(__rhs)) 3425f757f3fSDimitry Andric return false; 3435f757f3fSDimitry Andric if constexpr (__rank_ == 0) 3445f757f3fSDimitry Andric return true; 3455f757f3fSDimitry Andric else { 3465f757f3fSDimitry Andric return __lhs.extents() == __rhs.extents() && [&]<size_t... _Pos>(index_sequence<_Pos...>) { 3475f757f3fSDimitry Andric // avoid warning when comparing signed and unsigner integers and pick the wider of two types 3485f757f3fSDimitry Andric using _CommonType = common_type_t<index_type, typename _OtherMapping::index_type>; 3495f757f3fSDimitry Andric return ((static_cast<_CommonType>(__lhs.stride(_Pos)) == static_cast<_CommonType>(__rhs.stride(_Pos))) && ... && 3505f757f3fSDimitry Andric true); 3515f757f3fSDimitry Andric }(make_index_sequence<__rank_>()); 3525f757f3fSDimitry Andric } 3535f757f3fSDimitry Andric } 3545f757f3fSDimitry Andric 3555f757f3fSDimitry Andric private: 3565f757f3fSDimitry Andric _LIBCPP_NO_UNIQUE_ADDRESS extents_type __extents_{}; 3575f757f3fSDimitry Andric _LIBCPP_NO_UNIQUE_ADDRESS __mdspan_detail::__possibly_empty_array<index_type, __rank_> __strides_{}; 3585f757f3fSDimitry Andric }; 3595f757f3fSDimitry Andric 3605f757f3fSDimitry Andric #endif // _LIBCPP_STD_VER >= 23 3615f757f3fSDimitry Andric 3625f757f3fSDimitry Andric _LIBCPP_END_NAMESPACE_STD 3635f757f3fSDimitry Andric 3645f757f3fSDimitry Andric _LIBCPP_POP_MACROS 3655f757f3fSDimitry Andric 3665f757f3fSDimitry Andric #endif // _LIBCPP___MDSPAN_LAYOUT_STRIDE_H 367