mdspan
Go to the documentation of this file.
// <mdspan> -*- C++ -*-
// Copyright The GNU Toolchain Authors.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.
// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
// <http://www.gnu.org/licenses/>.
/** @file mdspan
* This is a Standard C++ Library header.
*/
#ifndef _GLIBCXX_MDSPAN
#define _GLIBCXX_MDSPAN 1
#ifdef _GLIBCXX_SYSHDR
#pragma GCC system_header
#endif
#include <span>
#include <array>
#include <type_traits>
#include <utility>
#define __glibcxx_want_mdspan
#define __glibcxx_want_aligned_accessor
#define __glibcxx_want_submdspan
#include <bits/version.h>
#if __glibcxx_aligned_accessor
#include <bits/align.h>
#endif
#if __glibcxx_submdspan
#include <tuple>
#endif
#if __cplusplus > 202302L
#include <bits/stdexcept_throw.h>
#endif
#ifdef __glibcxx_mdspan
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
namespace __mdspan
{
consteval bool
__all_static(std::span<const size_t> __extents)
{
for(auto __ext : __extents)
if (__ext == dynamic_extent)
return false;
return true;
}
consteval bool
__all_dynamic(std::span<const size_t> __extents)
{
for(auto __ext : __extents)
if (__ext != dynamic_extent)
return false;
return true;
}
template<typename _IndexType, typename _OIndexTypeRef>
constexpr _IndexType
__index_type_cast(_OIndexTypeRef&& __other)
{
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 4020. extents::index-cast weirdness
using _OIndexType = std::remove_cvref_t<_OIndexTypeRef>;
if constexpr (std::is_integral_v<_OIndexType>)
{
constexpr _IndexType __index_type_max
= __gnu_cxx::__int_traits<_IndexType>::__max;
constexpr _OIndexType __oindex_type_max
= __gnu_cxx::__int_traits<_OIndexType>::__max;
if constexpr (__index_type_max < __oindex_type_max)
__glibcxx_assert(cmp_less_equal(__other, __index_type_max));
if constexpr (std::is_signed_v<_OIndexType>)
__glibcxx_assert(__other >= 0);
return static_cast<_IndexType>(__other);
}
else
{
auto __ret = static_cast<_IndexType>(std::forward<_OIndexTypeRef>(__other));
if constexpr (std::is_signed_v<_IndexType>)
__glibcxx_assert(__ret >= 0);
return __ret;
}
}
template<array _Extents>
class _StaticExtents
{
public:
static constexpr size_t _S_rank = _Extents.size();
// For __r in [0, _S_rank], _S_dynamic_index(__r) is the number
// of dynamic extents up to (and not including) __r.
//
// If __r is the index of a dynamic extent, then
// _S_dynamic_index[__r] is the index of that extent in
// _M_dyn_exts.
static constexpr size_t
_S_dynamic_index(size_t __r) noexcept
{ return _S_dynamic_index_data[__r]; }
static constexpr auto _S_dynamic_index_data = [] consteval
{
array<size_t, _S_rank+1> __ret;
size_t __dyn = 0;
for (size_t __i = 0; __i < _S_rank; ++__i)
{
__ret[__i] = __dyn;
__dyn += (_Extents[__i] == dynamic_extent);
}
__ret[_S_rank] = __dyn;
return __ret;
}();
static constexpr size_t _S_rank_dynamic = _S_dynamic_index(_S_rank);
// For __r in [0, _S_rank_dynamic), _S_dynamic_index_inv(__r) is the
// index of the __r-th dynamic extent in _Extents.
static constexpr size_t
_S_dynamic_index_inv(size_t __r) noexcept
{ return _S_dynamic_index_inv_data[__r]; }
static constexpr auto _S_dynamic_index_inv_data = [] consteval
{
array<size_t, _S_rank_dynamic> __ret;
for (size_t __i = 0, __r = 0; __i < _S_rank; ++__i)
if (_Extents[__i] == dynamic_extent)
__ret[__r++] = __i;
return __ret;
}();
static constexpr size_t
_S_static_extent(size_t __r) noexcept
{ return _Extents[__r]; }
};
template<array _Extents>
requires (__all_dynamic<_Extents>())
class _StaticExtents<_Extents>
{
public:
static constexpr size_t _S_rank = _Extents.size();
static constexpr size_t
_S_dynamic_index(size_t __r) noexcept
{ return __r; }
static constexpr size_t _S_rank_dynamic = _S_rank;
static constexpr size_t
_S_dynamic_index_inv(size_t __k) noexcept
{ return __k; }
static constexpr size_t
_S_static_extent(size_t) noexcept
{ return dynamic_extent; }
};
template<typename _IndexType, array _Extents>
class _ExtentsStorage : public _StaticExtents<_Extents>
{
private:
using _Base = _StaticExtents<_Extents>;
public:
using _Base::_S_rank;
using _Base::_S_rank_dynamic;
using _Base::_S_dynamic_index;
using _Base::_S_dynamic_index_inv;
using _Base::_S_static_extent;
static constexpr bool
_S_is_dynamic(size_t __r) noexcept
{
if constexpr (__all_static(_Extents))
return false;
else if constexpr (__all_dynamic(_Extents))
return true;
else
return _Extents[__r] == dynamic_extent;
}
template<typename _OIndexType>
static constexpr _IndexType
_S_int_cast(const _OIndexType& __other) noexcept
{ return _IndexType(__other); }
constexpr _IndexType
_M_extent(size_t __r) const noexcept
{
if (_S_is_dynamic(__r))
return _M_dyn_exts[_S_dynamic_index(__r)];
else
return _S_static_extent(__r);
}
template<size_t _OtherRank, typename _GetOtherExtent>
static constexpr bool
_S_is_compatible_extents(_GetOtherExtent __get_extent) noexcept
{
if constexpr (_OtherRank == _S_rank)
for (size_t __i = 0; __i < _S_rank; ++__i)
if (!_S_is_dynamic(__i)
&& !cmp_equal(_Extents[__i], _S_int_cast(__get_extent(__i))))
return false;
return true;
}
template<size_t _OtherRank, typename _GetOtherExtent>
constexpr void
_M_init_dynamic_extents(_GetOtherExtent __get_extent) noexcept
{
__glibcxx_assert(_S_is_compatible_extents<_OtherRank>(__get_extent));
for (size_t __i = 0; __i < _S_rank_dynamic; ++__i)
{
size_t __di = __i;
if constexpr (_OtherRank != _S_rank_dynamic)
__di = _S_dynamic_index_inv(__i);
_M_dyn_exts[__i] = _S_int_cast(__get_extent(__di));
}
}
constexpr
_ExtentsStorage() noexcept = default;
template<typename _OIndexType, array _OExtents>
constexpr
_ExtentsStorage(const _ExtentsStorage<_OIndexType, _OExtents>&
__other) noexcept
{
_M_init_dynamic_extents<_S_rank>([&__other](size_t __i)
{ return __other._M_extent(__i); });
}
template<typename _OIndexType, size_t _Nm>
constexpr
_ExtentsStorage(span<const _OIndexType, _Nm> __exts) noexcept
{
_M_init_dynamic_extents<_Nm>(
[&__exts](size_t __i) -> const _OIndexType&
{ return __exts[__i]; });
}
static constexpr const array<size_t, _S_rank>&
_S_static_extents() noexcept
{ return _Extents; }
constexpr span<const _IndexType>
_M_dynamic_extents(size_t __begin, size_t __end) const noexcept
requires (_Extents.size() > 0)
{
return {_M_dyn_exts + _S_dynamic_index(__begin),
_S_dynamic_index(__end) - _S_dynamic_index(__begin)};
}
private:
using _Storage = __array_traits<_IndexType, _S_rank_dynamic>::_Type;
[[no_unique_address]] _Storage _M_dyn_exts{};
};
template<typename _OIndexType, typename _SIndexType>
concept __valid_index_type =
is_convertible_v<_OIndexType, _SIndexType> &&
is_nothrow_constructible_v<_SIndexType, _OIndexType>;
template<size_t _Extent, typename _IndexType>
concept
__valid_static_extent = _Extent == dynamic_extent
|| _Extent <= __gnu_cxx::__int_traits<_IndexType>::__max;
template<typename _Extents>
constexpr const array<size_t, _Extents::rank()>&
__static_extents() noexcept
{ return _Extents::_Storage::_S_static_extents(); }
template<typename _Extents>
constexpr span<const size_t>
__static_extents(size_t __begin, size_t __end) noexcept
{
const auto& __sta_exts = __static_extents<_Extents>();
return span<const size_t>(__sta_exts.data() + __begin, __end - __begin);
}
// Pre-compute: \prod_{i = 0}^r _Extents[i], for r = 0,..., n (exclusive)
template<array _Extents>
constexpr auto __fwd_partial_prods = [] consteval
{
constexpr size_t __rank = _Extents.size();
std::array<size_t, __rank> __ret;
size_t __prod = 1;
for (size_t __r = 0; __r < __rank; ++__r)
{
__ret[__r] = __prod;
if (size_t __ext = _Extents[__r]; __ext != dynamic_extent)
__prod *= __ext;
}
return __ret;
}();
// Pre-compute: \prod_{i = r+1}^{n-1} _Extents[i]
template<array _Extents>
constexpr auto __rev_partial_prods = [] consteval
{
constexpr size_t __rank = _Extents.size();
std::array<size_t, __rank> __ret;
size_t __prod = 1;
for (size_t __r = __rank; __r > 0; --__r)
{
__ret[__r - 1] = __prod;
if (size_t __ext = _Extents[__r - 1]; __ext != dynamic_extent)
__prod *= __ext;
}
return __ret;
}();
template<typename _Extents>
constexpr span<const typename _Extents::index_type>
__dynamic_extents(const _Extents& __exts, size_t __begin = 0,
size_t __end = _Extents::rank()) noexcept
{ return __exts._M_exts._M_dynamic_extents(__begin, __end); }
}
#if __glibcxx_submdspan
struct full_extent_t
{
explicit full_extent_t() = default;
};
inline constexpr full_extent_t full_extent{};
template<typename _OffsetType, typename _ExtentType, typename _StrideType>
struct strided_slice
{
static_assert(__is_signed_or_unsigned_integer<_OffsetType>::value
|| __detail::__integral_constant_like<_OffsetType>);
static_assert(__is_signed_or_unsigned_integer<_ExtentType>::value
|| __detail::__integral_constant_like<_ExtentType>);
static_assert(__is_signed_or_unsigned_integer<_StrideType>::value
|| __detail::__integral_constant_like<_StrideType>);
using offset_type = _OffsetType;
using extent_type = _ExtentType;
using stride_type = _StrideType;
[[no_unique_address]] offset_type offset{};
[[no_unique_address]] extent_type extent{};
[[no_unique_address]] stride_type stride{};
};
template<typename _Mapping>
struct submdspan_mapping_result
{
[[no_unique_address]] _Mapping mapping = _Mapping();
size_t offset{};
};
template<typename _Tp>
constexpr bool __is_submdspan_mapping_result = false;
template<typename _Mapping>
constexpr bool __is_submdspan_mapping_result<submdspan_mapping_result<_Mapping>> = true;
template<typename _Mapping>
concept __submdspan_mapping_result = __is_submdspan_mapping_result<_Mapping>;
#endif // __glibcxx_submdspan
template<typename _IndexType, size_t... _Extents>
class extents
{
static_assert(__is_signed_or_unsigned_integer<_IndexType>::value,
"IndexType must be a signed or unsigned integer type");
static_assert(
(__mdspan::__valid_static_extent<_Extents, _IndexType> && ...),
"Extents must either be dynamic or representable as IndexType");
using _Storage = __mdspan::_ExtentsStorage<
_IndexType, array<size_t, sizeof...(_Extents)>{_Extents...}>;
[[no_unique_address]] _Storage _M_exts;
public:
using index_type = _IndexType;
using size_type = make_unsigned_t<index_type>;
using rank_type = size_t;
static constexpr rank_type
rank() noexcept { return _Storage::_S_rank; }
static constexpr rank_type
rank_dynamic() noexcept { return _Storage::_S_rank_dynamic; }
static constexpr size_t
static_extent(rank_type __r) noexcept
{
__glibcxx_assert(__r < rank());
if constexpr (rank() == 0)
__builtin_trap();
else
return _Storage::_S_static_extent(__r);
}
constexpr index_type
extent(rank_type __r) const noexcept
{
__glibcxx_assert(__r < rank());
if constexpr (rank() == 0)
__builtin_trap();
else
return _M_exts._M_extent(__r);
}
constexpr
extents() noexcept = default;
private:
static consteval bool
_S_is_less_dynamic(size_t __ext, size_t __oext)
{ return (__ext != dynamic_extent) && (__oext == dynamic_extent); }
template<typename _OIndexType, size_t... _OExtents>
static consteval bool
_S_ctor_explicit()
{
return (_S_is_less_dynamic(_Extents, _OExtents) || ...)
|| (__gnu_cxx::__int_traits<index_type>::__max
< __gnu_cxx::__int_traits<_OIndexType>::__max);
}
template<size_t... _OExtents>
static consteval bool
_S_is_compatible_extents()
{
if constexpr (sizeof...(_OExtents) != rank())
return false;
else
return ((_OExtents == dynamic_extent || _Extents == dynamic_extent
|| _OExtents == _Extents) && ...);
}
public:
template<typename _OIndexType, size_t... _OExtents>
requires (_S_is_compatible_extents<_OExtents...>())
constexpr explicit(_S_ctor_explicit<_OIndexType, _OExtents...>())
extents(const extents<_OIndexType, _OExtents...>& __other) noexcept
: _M_exts(__other._M_exts)
{ }
template<__mdspan::__valid_index_type<index_type>... _OIndexTypes>
requires (sizeof...(_OIndexTypes) == rank()
|| sizeof...(_OIndexTypes) == rank_dynamic())
constexpr explicit extents(_OIndexTypes... __exts) noexcept
: _M_exts(span<const _IndexType, sizeof...(_OIndexTypes)>(
initializer_list{static_cast<_IndexType>(std::move(__exts))...}))
{ }
template<typename _OIndexType, size_t _Nm>
requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
&& (_Nm == rank() || _Nm == rank_dynamic())
constexpr explicit(_Nm != rank_dynamic())
extents(span<_OIndexType, _Nm> __exts) noexcept
: _M_exts(span<const _OIndexType, _Nm>(__exts))
{ }
template<typename _OIndexType, size_t _Nm>
requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
&& (_Nm == rank() || _Nm == rank_dynamic())
constexpr explicit(_Nm != rank_dynamic())
extents(const array<_OIndexType, _Nm>& __exts) noexcept
: _M_exts(span<const _OIndexType, _Nm>(__exts))
{ }
template<typename _OIndexType, size_t... _OExtents>
friend constexpr bool
operator==(const extents& __self,
const extents<_OIndexType, _OExtents...>& __other) noexcept
{
if constexpr (!_S_is_compatible_extents<_OExtents...>())
return false;
else
{
auto __impl = [&__self, &__other]<size_t... _Counts>(
index_sequence<_Counts...>)
{ return (cmp_equal(__self.extent(_Counts),
__other.extent(_Counts)) && ...); };
return __impl(make_index_sequence<__self.rank()>());
}
}
private:
friend constexpr const array<size_t, rank()>&
__mdspan::__static_extents<extents>() noexcept;
friend constexpr span<const index_type>
__mdspan::__dynamic_extents<extents>(const extents&, size_t, size_t)
noexcept;
template<typename _OIndexType, size_t... _OExtents>
friend class extents;
};
namespace __mdspan
{
template<typename _Tp, size_t _Nm>
constexpr bool
__contains_zero(span<_Tp, _Nm> __exts) noexcept
{
for (size_t __i = 0; __i < __exts.size(); ++__i)
if (__exts[__i] == 0)
return true;
return false;
}
template<typename _Tp, size_t _Nm>
consteval bool
__contains_zero(const array<_Tp, _Nm>& __exts) noexcept
{ return __contains_zero(span<const _Tp>(__exts)); }
template<typename _Extents>
constexpr bool
__empty(const _Extents& __exts) noexcept
{
if constexpr (__contains_zero(__static_extents<_Extents>()))
return true;
else if constexpr (_Extents::rank_dynamic() > 0)
return __contains_zero(__dynamic_extents(__exts));
else
return false;
}
template<typename _Extents>
constexpr typename _Extents::index_type
__extents_prod(const _Extents& __exts, size_t __sta_prod, size_t __begin,
size_t __end) noexcept
{
if (__sta_prod == 0)
return 0;
size_t __ret = __sta_prod;
if constexpr (_Extents::rank_dynamic() > 0)
for (auto __factor : __dynamic_extents(__exts, __begin, __end))
__ret *= size_t(__factor);
return static_cast<typename _Extents::index_type>(__ret);
}
// Preconditions: _r < _Extents::rank()
template<typename _Extents>
constexpr typename _Extents::index_type
__fwd_prod(const _Extents& __exts, size_t __begin, size_t __end) noexcept
{
size_t __sta_prod = [__begin, __end] {
span<const size_t> __sta_exts
= __static_extents<_Extents>(__begin, __end);
size_t __ret = 1;
for(auto __ext : __sta_exts)
if (__ext != dynamic_extent)
__ret *= __ext;
return __ret;
}();
return __extents_prod(__exts, __sta_prod, __begin, __end);
}
template<typename _Extents>
constexpr typename _Extents::index_type
__fwd_prod(const _Extents& __exts, size_t __r) noexcept
{
constexpr size_t __rank = _Extents::rank();
constexpr auto& __sta_exts = __static_extents<_Extents>();
if constexpr (__rank == 1)
return 1;
else if constexpr (__rank == 2)
return __r == 0 ? 1 : __exts.extent(0);
else if constexpr (__all_dynamic(std::span(__sta_exts).first(__rank-1)))
return __extents_prod(__exts, 1, 0, __r);
else
{
size_t __sta_prod = __fwd_partial_prods<__sta_exts>[__r];
return __extents_prod(__exts, __sta_prod, 0, __r);
}
}
template<typename _IndexType, size_t _Nm>
consteval _IndexType
__fwd_prod(span<const _IndexType, _Nm> __values)
{
_IndexType __ret = 1;
for(auto __value : __values)
__ret *= __value;
return __ret;
}
// Preconditions: _r < _Extents::rank()
template<typename _Extents>
constexpr typename _Extents::index_type
__rev_prod(const _Extents& __exts, size_t __r) noexcept
{
constexpr size_t __rank = _Extents::rank();
constexpr auto& __sta_exts = __static_extents<_Extents>();
if constexpr (__rank == 1)
return 1;
else if constexpr (__rank == 2)
return __r == 0 ? __exts.extent(1) : 1;
else if constexpr (__all_dynamic(std::span(__sta_exts).last(__rank-1)))
return __extents_prod(__exts, 1, __r + 1, __rank);
else
{
size_t __sta_prod = __rev_partial_prods<__sta_exts>[__r];
return __extents_prod(__exts, __sta_prod, __r + 1, __rank);
}
}
template<typename _Extents>
constexpr typename _Extents::index_type
__size(const _Extents& __exts) noexcept
{
constexpr size_t __sta_prod = [] {
span<const size_t> __sta_exts = __static_extents<_Extents>();
size_t __ret = 1;
for(auto __ext : __sta_exts)
if (__ext != dynamic_extent)
__ret *= __ext;
return __ret;
}();
return __extents_prod(__exts, __sta_prod, 0, _Extents::rank());
}
template<typename _IndexType, size_t... _Counts>
auto __build_dextents_type(integer_sequence<size_t, _Counts...>)
-> extents<_IndexType, ((void) _Counts, dynamic_extent)...>;
}
template<typename _IndexType, size_t _Rank>
using dextents = decltype(__mdspan::__build_dextents_type<_IndexType>(
make_index_sequence<_Rank>()));
#if __glibcxx_mdspan >= 202406L
template<size_t _Rank, typename _IndexType = size_t>
using dims = dextents<_IndexType, _Rank>;
#endif
template<typename... _Integrals>
requires (is_convertible_v<_Integrals, size_t> && ...)
explicit extents(_Integrals...) ->
extents<size_t, __detail::__maybe_static_ext<_Integrals>...>;
struct layout_left
{
template<typename _Extents>
class mapping;
};
struct layout_right
{
template<typename _Extents>
class mapping;
};
struct layout_stride
{
template<typename _Extents>
class mapping;
};
#ifdef __glibcxx_padded_layouts
template<size_t _PaddingValue>
struct layout_left_padded
{
template<typename _Extents>
class mapping;
};
template<size_t _PaddingValue>
struct layout_right_padded
{
template<typename _Extents>
class mapping;
};
#endif
namespace __mdspan
{
template<typename _Tp>
constexpr bool __is_extents = false;
template<typename _IndexType, size_t... _Extents>
constexpr bool __is_extents<extents<_IndexType, _Extents...>> = true;
template<typename _Extents, typename... _Indices>
constexpr typename _Extents::index_type
__linear_index_left(const _Extents& __exts, _Indices... __indices)
noexcept
{
using _IndexType = typename _Extents::index_type;
_IndexType __res = 0;
if constexpr (sizeof...(__indices) > 0)
{
_IndexType __mult = 1;
auto __update = [&, __pos = 0u](_IndexType __idx) mutable
{
_GLIBCXX_DEBUG_ASSERT(cmp_less(__idx, __exts.extent(__pos)));
__res += __idx * __mult;
__mult *= __exts.extent(__pos);
++__pos;
};
(__update(__indices), ...);
}
return __res;
}
template<typename _IndexType>
consteval _IndexType
__static_quotient(std::span<const size_t> __sta_exts,
_IndexType __nom = __gnu_cxx::__int_traits<_IndexType>::__max)
{
for (auto __factor : __sta_exts)
{
if (__factor != dynamic_extent)
__nom /= _IndexType(__factor);
if (__nom == 0)
break;
}
return __nom;
}
template<typename _Extents,
typename _IndexType = typename _Extents::index_type>
requires __is_extents<_Extents>
consteval _IndexType
__static_quotient(_IndexType __nom
= __gnu_cxx::__int_traits<_IndexType>::__max)
{
std::span<const size_t> __sta_exts = __static_extents<_Extents>();
return __static_quotient<_IndexType>(__sta_exts, __nom);
}
template<typename _Extents>
constexpr bool
__is_representable_extents(const _Extents& __exts) noexcept
{
using _IndexType = _Extents::index_type;
if constexpr (__contains_zero(__static_extents<_Extents>()))
return true;
else
{
constexpr auto __sta_quo = __static_quotient<_Extents>();
if constexpr (_Extents::rank_dynamic() == 0)
return __sta_quo != 0;
else
{
auto __dyn_exts = __dynamic_extents(__exts);
if (__contains_zero(__dyn_exts))
return true;
if constexpr (__sta_quo == 0)
return false;
else
{
auto __dyn_quo = _IndexType(__sta_quo);
for (auto __factor : __dyn_exts)
{
__dyn_quo /= __factor;
if (__dyn_quo == 0)
return false;
}
return true;
}
}
}
}
template<typename _Extents, typename _IndexType>
concept __representable_size = _Extents::rank_dynamic() != 0
|| __contains_zero(__static_extents<_Extents>())
|| (__static_quotient<_Extents, _IndexType>() != 0);
template<typename _Layout, typename _Mapping>
concept __mapping_of =
is_same_v<typename _Layout::template mapping<
typename _Mapping::extents_type>,
_Mapping>;
template<template<size_t> typename _Layout, typename _Mapping>
concept __padded_mapping_of = __mapping_of<
_Layout<_Mapping::padding_value>, _Mapping>;
#ifdef __glibcxx_padded_layouts
template<typename _Mapping>
constexpr bool __is_left_padded_mapping = __padded_mapping_of<
layout_left_padded, _Mapping>;
template<typename _Mapping>
constexpr bool __is_right_padded_mapping = __padded_mapping_of<
layout_right_padded, _Mapping>;
template<typename _Mapping>
constexpr bool __is_padded_mapping = __is_left_padded_mapping<_Mapping>
|| __is_right_padded_mapping<_Mapping>;
#endif
template<typename _PaddedMapping>
consteval size_t
__get_static_stride()
{ return _PaddedMapping::_PaddedStorage::_S_static_stride; }
template<typename _Mapping>
concept __standardized_mapping = __mapping_of<layout_left, _Mapping>
|| __mapping_of<layout_right, _Mapping>
|| __mapping_of<layout_stride, _Mapping>
#ifdef __glibcxx_padded_layouts
|| __is_left_padded_mapping<_Mapping>
|| __is_right_padded_mapping<_Mapping>
#endif
;
// A tag type to create internal ctors.
class __internal_ctor
{ };
template<typename _Mapping>
constexpr typename _Mapping::index_type
__offset(const _Mapping& __m) noexcept
{
using _IndexType = typename _Mapping::index_type;
constexpr auto __rank = _Mapping::extents_type::rank();
if constexpr (__standardized_mapping<_Mapping>)
return 0;
else if (__empty(__m.extents()))
return 0;
else
{
auto __impl = [&__m]<size_t... _Counts>(index_sequence<_Counts...>)
{ return __m(((void) _Counts, _IndexType(0))...); };
return __impl(make_index_sequence<__rank>());
}
}
#ifdef __glibcxx_submdspan
template<typename _Tp>
constexpr bool __is_strided_slice = false;
template<typename _OffsetType, typename _ExtentType, typename _StrideType>
constexpr bool __is_strided_slice<strided_slice<_OffsetType,
_ExtentType, _StrideType>> = true;
template<typename _IndexType, typename _OIndexType>
consteval bool
__is_representable_integer(_OIndexType __value)
{
constexpr auto __min = __gnu_cxx::__int_traits<_IndexType>::__min;
constexpr auto __max = __gnu_cxx::__int_traits<_IndexType>::__max;
return std::cmp_less_equal(__min, __value)
&& std::cmp_less_equal(__value, __max);
}
template<typename _Tp>
constexpr bool __is_constant_wrapper = false;
template<_CwFixedValue _Xv, typename _Tp>
constexpr bool __is_constant_wrapper<constant_wrapper<_Xv, _Tp>>
= true;
template<size_t _Index, typename _Extents>
constexpr auto
__extract_extent(const _Extents& __exts)
{
using _IndexType = typename _Extents::index_type;
return extents<_IndexType, _Extents::static_extent(_Index)>{
__exts.extent(_Index)};
}
template<typename _Slice, typename _IndexType>
concept __acceptable_slice_type = same_as<_Slice, full_extent_t>
|| same_as<_Slice, _IndexType> || __is_constant_wrapper<_Slice>
|| __is_strided_slice<_Slice>;
template<typename _IndexType, typename... _Slices>
consteval auto
__subrank()
{
return (static_cast<size_t>(!convertible_to<_Slices, _IndexType>)
+ ... + 0);
}
template<typename _IndexType, typename... _Slices>
consteval auto
__inv_map_rank()
{
constexpr auto __rank = sizeof...(_Slices);
constexpr auto __sub_rank = __subrank<_IndexType, _Slices...>();
auto __map = std::array<size_t, __sub_rank>{};
auto __is_int_like = std::array<bool, __rank>{
convertible_to<_Slices, _IndexType>...};
size_t __i = 0;
for (size_t __k = 0; __k < __rank; ++__k)
if (!__is_int_like[__k])
__map[__i++] = __k;
return __map;
}
template<typename _Slice>
constexpr auto
__slice_begin(_Slice __slice)
{
if constexpr (same_as<_Slice, full_extent_t>)
return 0;
else if constexpr (__is_strided_slice<_Slice>)
return __slice.offset;
else
return __slice; // collapsing slice
}
template<typename _Mapping, typename... _Slices>
constexpr size_t
__suboffset(const _Mapping& __mapping, const _Slices&... __slices)
{
using _IndexType = typename _Mapping::index_type;
auto __any_past_the_end = [&]<size_t... _Is>(index_sequence<_Is...>)
{
auto __is_past_the_end = [](const auto& __slice, const auto& __ext)
{
using _Slice = remove_cvref_t<decltype(__slice)>;
if constexpr (is_convertible_v<_Slice, _IndexType>)
return false;
else if constexpr (same_as<_Slice, full_extent_t>
&& __ext.static_extent(0) != 0
&& __ext.static_extent(0) != dynamic_extent)
return false;
else
return __mdspan::__slice_begin(__slice) == __ext.extent(0);
};
const auto& __exts = __mapping.extents();
return ((__is_past_the_end(__slices...[_Is],
__mdspan::__extract_extent<_Is>(__exts))) || ...);
};
if constexpr ((same_as<_Slices, full_extent_t> && ...))
return __mdspan::__offset(__mapping);
if (__any_past_the_end(std::make_index_sequence<sizeof...(__slices)>()))
return __mapping.required_span_size();
return __mapping(__mdspan::__slice_begin(__slices)...);
}
template<typename _IndexType, size_t _Extent, typename _Slice>
consteval size_t
__static_slice_extent()
{
if constexpr (same_as<_Slice, full_extent_t>)
return _Extent;
else if constexpr (same_as<_Slice, constant_wrapper<_IndexType(0)>>)
return 0;
else if constexpr (__is_constant_wrapper<typename _Slice::extent_type>
&& __is_constant_wrapper<typename _Slice::stride_type>)
return 1 + ((typename _Slice::extent_type{}) - 1)
/ (typename _Slice::stride_type{});
else
return dynamic_extent;
}
template<size_t _K, typename _Extents, typename _Slice>
constexpr typename _Extents::index_type
__dynamic_slice_extent(const _Extents& __exts, _Slice __slice)
{
if constexpr (__is_strided_slice<_Slice>)
return __slice.extent == 0 ? 0 : 1 + (__slice.extent - 1) / __slice.stride;
else
return __exts.extent(_K);
}
template<typename _IndexType, size_t... _Extents, typename... _Slices>
requires (sizeof...(_Slices) == sizeof...(_Extents))
constexpr auto
__subextents(const extents<_IndexType, _Extents...>& __exts,
_Slices... __slices)
{
constexpr auto __inv_map = __mdspan::__inv_map_rank<_IndexType, _Slices...>();
auto __impl = [&]<size_t... _Indices>(std::index_sequence<_Indices...>)
{
using _SubExts = extents<_IndexType,
__mdspan::__static_slice_extent<_IndexType,
_Extents...[__inv_map[_Indices]],
_Slices...[__inv_map[_Indices]]>()...>;
if constexpr (_SubExts::rank_dynamic() == 0)
return _SubExts{};
else
{
using _StaticSubExtents = __mdspan::_StaticExtents<
__mdspan::__static_extents<_SubExts>()>;
auto __create = [&]<size_t... _Is>(std::index_sequence<_Is...>)
{
constexpr auto __slice_idx = [__inv_map](size_t __i) consteval
{
return __inv_map[_StaticSubExtents::_S_dynamic_index_inv(__i)];
};
return _SubExts{__mdspan::__dynamic_slice_extent<__slice_idx(_Is)>(
__exts, __slices...[__slice_idx(_Is)])...};
};
constexpr auto __dyn_subrank = _SubExts::rank_dynamic();
return __create(std::make_index_sequence<__dyn_subrank>());
}
};
return __impl(std::make_index_sequence<__inv_map.size()>());
}
enum class _LayoutSide
{
__left,
__right,
__unknown
};
template<typename _Mapping>
consteval _LayoutSide
__mapping_side()
{
if constexpr (__is_left_padded_mapping<_Mapping>
|| __mapping_of<layout_left, _Mapping>)
return _LayoutSide::__left;
if constexpr (__is_right_padded_mapping<_Mapping>
|| __mapping_of<layout_right, _Mapping>)
return _LayoutSide::__right;
else
return _LayoutSide::__unknown;
}
template<_LayoutSide _Side, size_t _Rank>
struct _StridesTrait
{
static constexpr const _LayoutSide _S_side = _Side;
static constexpr size_t
_S_idx(size_t __k) noexcept
{
if constexpr (_Side == _LayoutSide::__left)
return __k;
else
return _Rank - 1 - __k;
}
// Unifies the formulas for computing strides for padded and unpadded
// layouts.
template<typename _Mapping>
static constexpr typename _Mapping::index_type
_S_padded_extent(const _Mapping& __mapping, size_t __k)
{
if (__k == 0)
return __mapping.stride(_S_idx(1));
else
return __mapping.extents().extent(_S_idx(__k));
}
template<typename _IndexType, typename... _Slices>
static consteval auto
_S_inv_map()
{
static_assert(_Side != _LayoutSide::__unknown);
auto __impl = [&]<size_t... _Is>(std::index_sequence<_Is...>)
{
return __mdspan::__inv_map_rank<_IndexType, _Slices...[_S_idx(_Is)]...>();
};
return __impl(std::make_index_sequence<_Rank>());
}
};
template<typename _SubExts, typename _Mapping, typename... _Slices>
constexpr auto
__substrides_generic(const _Mapping& __mapping, const _Slices&... __slices)
{
using _IndexType = typename _Mapping::index_type;
if constexpr (_SubExts::rank() == 0)
return array<_IndexType, _SubExts::rank()>{};
else
{
auto __stride = [&__mapping](size_t __k, auto __slice) -> _IndexType
{
if constexpr (__is_strided_slice<decltype(__slice)>)
if (__slice.stride < __slice.extent)
return __mapping.stride(__k) * __slice.stride;
return __mapping.stride(__k);
};
auto __impl = [&]<size_t... _Is>(std::index_sequence<_Is...>)
{
constexpr auto __inv_map
= __mdspan::__inv_map_rank<_IndexType, _Slices...>();
return array<_IndexType, _SubExts::rank()>{
__stride(__inv_map[_Is], __slices...[__inv_map[_Is]])...};
};
return __impl(std::make_index_sequence<_SubExts::rank()>());
}
};
template<typename _SubExts, typename _Mapping, typename... _Slices>
constexpr auto
__substrides_standardized(const _Mapping& __mapping,
const _Slices&... __slices)
{
using _IndexType = typename _Mapping::index_type;
using _Trait = _StridesTrait<__mapping_side<_Mapping>(),
_Mapping::extents_type::rank()>;
using _SubTrait = _StridesTrait<__mapping_side<_Mapping>(), _SubExts::rank()>;
constexpr size_t __sub_rank = _SubExts::rank();
std::array<_IndexType, __sub_rank> __ret;
if constexpr (__sub_rank > 0)
{
constexpr auto __inv_map
= _Trait::template _S_inv_map<_IndexType, _Slices...>();
auto __loop = [&]<size_t... _Ks>(std::index_sequence<_Ks...>)
{
size_t __i0 = 0;
size_t __stride = 1;
auto __body = [&](size_t __k, auto __slice)
{
for (size_t __i = __i0; __i < __inv_map[__k]; ++__i)
__stride *= _Trait::_S_padded_extent(__mapping, __i);
size_t __krev = _SubTrait::_S_idx(__k);
if constexpr (__is_strided_slice<decltype(__slice)>)
{
if (__slice.stride < __slice.extent)
__ret[__krev] = __stride * __slice.stride;
else
__ret[__krev] = __stride;
}
else
__ret[__krev] = __stride;
__i0 = __inv_map[__k];
};
((__body(_Ks, __slices...[_Trait::_S_idx(__inv_map[_Ks])])),...);
};
__loop(std::make_index_sequence<__sub_rank>());
}
return __ret;
}
template<typename _SubExts, typename _Mapping, typename... _Slices>
constexpr auto
__substrides(const _Mapping& __mapping, const _Slices&... __slices)
{
if constexpr (__mdspan::__mapping_side<_Mapping>() == _LayoutSide::__unknown)
return __mdspan::__substrides_generic<_SubExts>(__mapping, __slices...);
else
return __mdspan::__substrides_standardized<_SubExts>(__mapping, __slices...);
}
template<typename _Slice>
concept __is_unit_stride_slice = (__mdspan::__is_strided_slice<_Slice>
&& __mdspan::__is_constant_wrapper<typename _Slice::stride_type>
&& _Slice::stride_type::value == 1)
|| std::same_as<_Slice, full_extent_t>;
// These are (forced) exclusive categories:
// - full & collapsing: obvious,
// - unit_strided_slice: strided_slice{a, b, cw<1>}, but not `full`,
// - strided_slice: strided_slice{a, b, c} with c != cw<1>.
enum class _SliceKind
{
__strided_slice,
__unit_strided_slice,
__full,
__collapsing
};
template<typename _Slice>
consteval _SliceKind
__make_slice_kind()
{
if constexpr (std::same_as<_Slice, full_extent_t>)
return _SliceKind::__full;
else if constexpr (__mdspan::__is_strided_slice<_Slice>)
{
if constexpr (__mdspan::__is_unit_stride_slice<_Slice>)
return _SliceKind::__unit_strided_slice;
else
return _SliceKind::__strided_slice;
}
else
return _SliceKind::__collapsing;
}
template<typename... _Slices>
consteval array<_SliceKind, sizeof...(_Slices)>
__make_slice_kind_array()
{
return array<_SliceKind, sizeof...(_Slices)>{
__mdspan::__make_slice_kind<_Slices>()...};
}
// __block_size - 1
// [full, ..., full, unit_slice , *]
consteval bool
__is_block(span<const _SliceKind> __slice_kinds, size_t __block_size)
{
if (__block_size == 0)
return false;
if (__block_size > __slice_kinds.size())
return false;
for (size_t __i = 0; __i < __block_size - 1; ++__i)
if (__slice_kinds[__i] != _SliceKind::__full)
return false;
auto __last = __slice_kinds[__block_size - 1];
return __last == _SliceKind::__full
|| __last == _SliceKind::__unit_strided_slice;
}
// __u __u + __sub_rank-2
// [unit_slice, i, ..., k, full, ..., full, unit_slice, *]
static consteval size_t
__padded_block_begin_generic(span<const _SliceKind> __slice_kinds,
size_t __sub_rank)
{
if (__slice_kinds[0] != _SliceKind::__full
&& __slice_kinds[0] != _SliceKind::__unit_strided_slice)
return dynamic_extent;
else if (__slice_kinds.size() == 1)
return dynamic_extent;
else
{
size_t __u = 1;
while(__u < __slice_kinds.size()
&& __slice_kinds[__u] == _SliceKind::__collapsing)
++__u;
if (__mdspan::__is_block(__slice_kinds.subspan(__u), __sub_rank -1))
return __u;
return dynamic_extent;
}
}
template<_LayoutSide _Side, size_t _Nm>
static consteval size_t
__padded_block_begin(span<const _SliceKind, _Nm> __slice_kinds, size_t __sub_rank)
{
if constexpr (_Side == _LayoutSide::__left)
return __mdspan::__padded_block_begin_generic(__slice_kinds, __sub_rank);
else
{
std::array<_SliceKind, _Nm> __rev_slices;
for(size_t __i = 0; __i < _Nm; ++__i)
__rev_slices[__i] = __slice_kinds[_Nm - 1 - __i];
auto __rev_slice_kinds = span<const _SliceKind>(__rev_slices);
auto __u = __mdspan::__padded_block_begin_generic(__rev_slice_kinds,
__sub_rank);
return __u == dynamic_extent ? dynamic_extent : _Nm - 1 - __u;
}
}
template<_LayoutSide _Side, bool _Padded>
struct _SubMdspanMapping;
template<>
struct _SubMdspanMapping<_LayoutSide::__left, false>
{
using _Layout = layout_left;
template<size_t _Pad> using _PaddedLayout = layout_left_padded<_Pad>;
template<typename _Mapping, size_t _Us>
static consteval size_t
_S_pad()
{
using _Extents = typename _Mapping::extents_type;
constexpr auto __sta_exts = __mdspan::__static_extents<_Extents>(0, _Us);
if constexpr (!__mdspan::__all_static(__sta_exts))
return dynamic_extent;
else
return __mdspan::__fwd_prod(__sta_exts);
}
template<size_t _Nm>
static consteval bool
_S_is_unpadded_submdspan(span<const _SliceKind, _Nm> __slice_kinds, size_t __sub_rank)
{ return __mdspan::__is_block(__slice_kinds, __sub_rank); }
};
template<>
struct _SubMdspanMapping<_LayoutSide::__left, true>
{
using _Layout = layout_left;
template<size_t _Pad> using _PaddedLayout = layout_left_padded<_Pad>;
template<typename _Mapping, size_t _Us>
static consteval size_t
_S_pad()
{
using _Extents = typename _Mapping::extents_type;
constexpr auto __sta_exts
= __mdspan::__static_extents<_Extents>(1, _Us);
constexpr auto __sta_padstride
= __mdspan::__get_static_stride<_Mapping>();
if constexpr (__sta_padstride == dynamic_extent
|| !__mdspan::__all_static(__sta_exts))
return dynamic_extent;
else
return __sta_padstride * __mdspan::__fwd_prod(__sta_exts);
}
template<size_t _Nm>
static consteval bool
_S_is_unpadded_submdspan(span<const _SliceKind, _Nm> __slice_kinds,
size_t __sub_rank)
{
if (__sub_rank == 1)
return __slice_kinds[0] == _SliceKind::__unit_strided_slice
|| __slice_kinds[0] == _SliceKind::__full;
else
return false;
}
};
template<>
struct _SubMdspanMapping<_LayoutSide::__right, false>
{
using _Layout = layout_right;
template<size_t _Pad> using _PaddedLayout = layout_right_padded<_Pad>;
template<typename _Mapping, size_t _Us>
static consteval size_t
_S_pad()
{
using _Extents = typename _Mapping::extents_type;
constexpr auto __rank = _Extents::rank();
constexpr auto __sta_exts
= __mdspan::__static_extents<_Extents>(_Us + 1, __rank);
if constexpr (!__mdspan::__all_static(__sta_exts))
return dynamic_extent;
else
return __fwd_prod(__sta_exts);
}
template<size_t _Nm>
static consteval bool
_S_is_unpadded_submdspan(span<const _SliceKind, _Nm> __slice_kinds,
size_t __sub_rank)
{
auto __rev_slice_kinds = array<_SliceKind, _Nm>{};
for(size_t __i = 0; __i < _Nm; ++__i)
__rev_slice_kinds[__i] = __slice_kinds[_Nm - 1 - __i];
return __mdspan::__is_block(span(__rev_slice_kinds), __sub_rank);
}
};
template<>
struct _SubMdspanMapping<_LayoutSide::__right, true>
{
using _Layout = layout_right;
template<size_t _Pad> using _PaddedLayout = layout_right_padded<_Pad>;
template<typename _Mapping, size_t _Us>
static consteval size_t
_S_pad()
{
using _Extents = typename _Mapping::extents_type;
constexpr auto __rank = _Extents::rank();
constexpr auto __sta_exts
= __mdspan::__static_extents<_Extents>(_Us + 1, __rank - 1);
constexpr auto __sta_padstride
= __mdspan::__get_static_stride<_Mapping>();
if constexpr (__sta_padstride == dynamic_extent
|| !__mdspan::__all_static(__sta_exts))
return dynamic_extent;
else
return __sta_padstride * __mdspan::__fwd_prod(__sta_exts);
}
template<size_t _Nm>
static consteval bool
_S_is_unpadded_submdspan(span<const _SliceKind, _Nm> __slice_kinds,
size_t __sub_rank)
{
if (__sub_rank == 1)
return __slice_kinds[_Nm - 1] == _SliceKind::__unit_strided_slice
|| __slice_kinds[_Nm - 1] == _SliceKind::__full;
else
return false;
}
};
template<typename _Mapping>
constexpr auto
__submdspan_mapping_impl(const _Mapping& __mapping)
{ return submdspan_mapping_result{__mapping, 0}; }
template<typename _Mapping, typename... _Slices>
requires (sizeof...(_Slices) > 0)
constexpr auto
__submdspan_mapping_impl(const _Mapping& __mapping, _Slices... __slices)
{
using _IndexType = typename _Mapping::index_type;
static_assert((__acceptable_slice_type<_Slices, _IndexType> && ...));
constexpr auto __side = __mdspan::__mapping_side<_Mapping>();
constexpr auto __rank = sizeof...(_Slices);
using _Trait = _SubMdspanMapping<__side, __is_padded_mapping<_Mapping>>;
using _SliceView = span<const _SliceKind, __rank>;
constexpr auto __slice_kinds = __mdspan::__make_slice_kind_array<_Slices...>();
auto __offset = __mdspan::__suboffset(__mapping, __slices...);
auto __sub_exts = __mdspan::__subextents(__mapping.extents(), __slices...);
using _SubExts = decltype(__sub_exts);
constexpr auto __sub_rank = _SubExts::rank();
if constexpr (__sub_rank == 0)
return submdspan_mapping_result{
typename _Trait::_Layout::mapping(__sub_exts), __offset};
else if constexpr (_Trait::_S_is_unpadded_submdspan(
_SliceView(__slice_kinds), __sub_rank))
return submdspan_mapping_result{
typename _Trait::_Layout::mapping(__sub_exts), __offset};
else if constexpr (
constexpr auto __u = __padded_block_begin<__side>(
_SliceView(__slice_kinds), __sub_rank);
__u != dynamic_extent)
{
constexpr auto __pad = _Trait::template _S_pad<_Mapping, __u>();
using _Layout = typename _Trait::template _PaddedLayout<__pad>;
return submdspan_mapping_result{
typename _Layout::mapping(__sub_exts, __mapping.stride(__u)),
__offset};
}
else
{
auto __sub_strides
= __mdspan::__substrides<_SubExts>(__mapping, __slices...);
return submdspan_mapping_result{
layout_stride::mapping(__sub_exts, __sub_strides), __offset};
}
}
#endif // __glibcxx_submdspan
}
template<typename _Extents>
class layout_left::mapping
{
public:
using extents_type = _Extents;
using index_type = typename extents_type::index_type;
using size_type = typename extents_type::size_type;
using rank_type = typename extents_type::rank_type;
using layout_type = layout_left;
static_assert(__mdspan::__representable_size<extents_type, index_type>,
"The size of extents_type must be representable as index_type");
constexpr
mapping() noexcept = default;
constexpr
mapping(const mapping&) noexcept = default;
constexpr
mapping(const extents_type& __extents) noexcept
: _M_extents(__extents)
{ __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents)); }
template<typename _OExtents>
requires is_constructible_v<extents_type, _OExtents>
constexpr explicit(!is_convertible_v<_OExtents, extents_type>)
mapping(const mapping<_OExtents>& __other) noexcept
: mapping(__other.extents(), __mdspan::__internal_ctor{})
{ }
template<typename _OExtents>
requires (extents_type::rank() <= 1)
&& is_constructible_v<extents_type, _OExtents>
constexpr explicit(!is_convertible_v<_OExtents, extents_type>)
mapping(const layout_right::mapping<_OExtents>& __other) noexcept
: mapping(__other.extents(), __mdspan::__internal_ctor{})
{ }
// noexcept for consistency with other layouts.
template<typename _OExtents>
requires is_constructible_v<extents_type, _OExtents>
constexpr explicit(!(extents_type::rank() == 0
&& is_convertible_v<_OExtents, extents_type>))
mapping(const layout_stride::mapping<_OExtents>& __other) noexcept
: mapping(__other.extents(), __mdspan::__internal_ctor{})
{ __glibcxx_assert(*this == __other); }
#if __glibcxx_padded_layouts
template<typename _LeftpadMapping>
requires __mdspan::__is_left_padded_mapping<_LeftpadMapping>
&& is_constructible_v<extents_type,
typename _LeftpadMapping::extents_type>
constexpr
explicit(!is_convertible_v<typename _LeftpadMapping::extents_type,
extents_type>)
mapping(const _LeftpadMapping& __other) noexcept
: mapping(__other.extents(), __mdspan::__internal_ctor{})
{
constexpr size_t __ostride_sta
= __mdspan::__get_static_stride<_LeftpadMapping>();
if constexpr (extents_type::rank() > 1)
{
if constexpr (extents_type::static_extent(0) != dynamic_extent
&& __ostride_sta != dynamic_extent)
static_assert(extents_type::static_extent(0) == __ostride_sta);
else
__glibcxx_assert(__other.stride(1)
== __other.extents().extent(0));
}
}
#endif // __glibcxx_padded_layouts
constexpr mapping&
operator=(const mapping&) noexcept = default;
constexpr const extents_type&
extents() const noexcept { return _M_extents; }
constexpr index_type
required_span_size() const noexcept
{ return __mdspan::__size(_M_extents); }
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 4314. Missing move in mdspan layout mapping::operator()
template<__mdspan::__valid_index_type<index_type>... _Indices>
requires (sizeof...(_Indices) == extents_type::rank())
constexpr index_type
operator()(_Indices... __indices) const noexcept
{
return __mdspan::__linear_index_left(_M_extents,
static_cast<index_type>(std::move(__indices))...);
}
static constexpr bool
is_always_unique() noexcept { return true; }
static constexpr bool
is_always_exhaustive() noexcept { return true; }
static constexpr bool
is_always_strided() noexcept { return true; }
static constexpr bool
is_unique() noexcept { return true; }
static constexpr bool
is_exhaustive() noexcept { return true; }
static constexpr bool
is_strided() noexcept { return true; }
constexpr index_type
stride(rank_type __i) const noexcept
requires (extents_type::rank() > 0)
{
__glibcxx_assert(__i < extents_type::rank());
return __mdspan::__fwd_prod(_M_extents, __i);
}
template<typename _OExtents>
requires (extents_type::rank() == _OExtents::rank())
friend constexpr bool
operator==(const mapping& __self, const mapping<_OExtents>& __other)
noexcept
{ return __self.extents() == __other.extents(); }
private:
template<typename _OExtents>
constexpr explicit
mapping(const _OExtents& __oexts, __mdspan::__internal_ctor) noexcept
: _M_extents(__oexts)
{
static_assert(__mdspan::__representable_size<_OExtents, index_type>,
"The size of OtherExtents must be representable as index_type");
__glibcxx_assert(__mdspan::__is_representable_extents(_M_extents));
}
#if __glibcxx_submdspan
template<typename... _Slices>
requires (extents_type::rank() == sizeof...(_Slices))
friend constexpr auto
submdspan_mapping(const mapping& __mapping, _Slices... __slices)
{ return __mdspan::__submdspan_mapping_impl(__mapping, __slices...); }
#endif // __glibcxx_submdspan
[[no_unique_address]] extents_type _M_extents{};
};
namespace __mdspan
{
template<typename _Extents, typename... _Indices>
constexpr typename _Extents::index_type
__linear_index_right(const _Extents& __exts, _Indices... __indices)
noexcept
{
using _IndexType = typename _Extents::index_type;
array<_IndexType, sizeof...(__indices)> __ind_arr{__indices...};
_IndexType __res = 0;
if constexpr (sizeof...(__indices) > 0)
{
_IndexType __mult = 1;
auto __update = [&, __pos = __exts.rank()](_IndexType) mutable
{
--__pos;
_GLIBCXX_DEBUG_ASSERT(cmp_less(__ind_arr[__pos],
__exts.extent(__pos)));
__res += __ind_arr[__pos] * __mult;
__mult *= __exts.extent(__pos);
};
(__update(__indices), ...);
}
return __res;
}
}
template<typename _Extents>
class layout_right::mapping
{
public:
using extents_type = _Extents;
using index_type = typename extents_type::index_type;
using size_type = typename extents_type::size_type;
using rank_type = typename extents_type::rank_type;
using layout_type = layout_right;
static_assert(__mdspan::__representable_size<extents_type, index_type>,
"The size of extents_type must be representable as index_type");
constexpr
mapping() noexcept = default;
constexpr
mapping(const mapping&) noexcept = default;
constexpr
mapping(const extents_type& __extents) noexcept
: _M_extents(__extents)
{ __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents)); }
template<typename _OExtents>
requires is_constructible_v<extents_type, _OExtents>
constexpr explicit(!is_convertible_v<_OExtents, extents_type>)
mapping(const mapping<_OExtents>& __other) noexcept
: mapping(__other.extents(), __mdspan::__internal_ctor{})
{ }
template<typename _OExtents>
requires (extents_type::rank() <= 1)
&& is_constructible_v<extents_type, _OExtents>
constexpr explicit(!is_convertible_v<_OExtents, extents_type>)
mapping(const layout_left::mapping<_OExtents>& __other) noexcept
: mapping(__other.extents(), __mdspan::__internal_ctor{})
{ }
template<typename _OExtents>
requires is_constructible_v<extents_type, _OExtents>
constexpr explicit(!(extents_type::rank() == 0
&& is_convertible_v<_OExtents, extents_type>))
mapping(const layout_stride::mapping<_OExtents>& __other) noexcept
: mapping(__other.extents(), __mdspan::__internal_ctor{})
{ __glibcxx_assert(*this == __other); }
#if __glibcxx_padded_layouts
template<typename _RightPaddedMapping>
requires __mdspan::__is_right_padded_mapping<_RightPaddedMapping>
&& is_constructible_v<extents_type,
typename _RightPaddedMapping::extents_type>
constexpr
explicit(!is_convertible_v<typename _RightPaddedMapping::extents_type,
extents_type>)
mapping(const _RightPaddedMapping& __other) noexcept
: mapping(__other.extents(), __mdspan::__internal_ctor{})
{
constexpr size_t __rank = extents_type::rank();
constexpr size_t __ostride_sta
= __mdspan::__get_static_stride<_RightPaddedMapping>();
if constexpr (__rank > 1)
{
if constexpr (extents_type::static_extent(__rank - 1) != dynamic_extent
&& __ostride_sta != dynamic_extent)
static_assert(extents_type::static_extent(__rank - 1)
== __ostride_sta);
else
__glibcxx_assert(__other.stride(__rank - 2)
== __other.extents().extent(__rank - 1));
}
}
#endif
constexpr mapping&
operator=(const mapping&) noexcept = default;
constexpr const extents_type&
extents() const noexcept { return _M_extents; }
constexpr index_type
required_span_size() const noexcept
{ return __mdspan::__size(_M_extents); }
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 4314. Missing move in mdspan layout mapping::operator()
template<__mdspan::__valid_index_type<index_type>... _Indices>
requires (sizeof...(_Indices) == extents_type::rank())
constexpr index_type
operator()(_Indices... __indices) const noexcept
{
return __mdspan::__linear_index_right(
_M_extents, static_cast<index_type>(std::move(__indices))...);
}
static constexpr bool
is_always_unique() noexcept
{ return true; }
static constexpr bool
is_always_exhaustive() noexcept
{ return true; }
static constexpr bool
is_always_strided() noexcept
{ return true; }
static constexpr bool
is_unique() noexcept
{ return true; }
static constexpr bool
is_exhaustive() noexcept
{ return true; }
static constexpr bool
is_strided() noexcept
{ return true; }
constexpr index_type
stride(rank_type __i) const noexcept
requires (extents_type::rank() > 0)
{
__glibcxx_assert(__i < extents_type::rank());
return __mdspan::__rev_prod(_M_extents, __i);
}
template<typename _OExtents>
requires (extents_type::rank() == _OExtents::rank())
friend constexpr bool
operator==(const mapping& __self, const mapping<_OExtents>& __other)
noexcept
{ return __self.extents() == __other.extents(); }
private:
template<typename _OExtents>
constexpr explicit
mapping(const _OExtents& __oexts, __mdspan::__internal_ctor) noexcept
: _M_extents(__oexts)
{
static_assert(__mdspan::__representable_size<_OExtents, index_type>,
"The size of OtherExtents must be representable as index_type");
__glibcxx_assert(__mdspan::__is_representable_extents(_M_extents));
}
#if __glibcxx_submdspan
template<typename... _Slices>
requires (extents_type::rank() == sizeof...(_Slices))
friend constexpr auto
submdspan_mapping(const mapping& __mapping, _Slices... __slices)
{ return __mdspan::__submdspan_mapping_impl(__mapping, __slices...); }
#endif // __glibcxx_submdspan
[[no_unique_address]] extents_type _M_extents{};
};
namespace __mdspan
{
template<typename _Mp>
concept __mapping_alike = requires
{
requires __is_extents<typename _Mp::extents_type>;
{ _Mp::is_always_strided() } -> same_as<bool>;
{ _Mp::is_always_exhaustive() } -> same_as<bool>;
{ _Mp::is_always_unique() } -> same_as<bool>;
bool_constant<_Mp::is_always_strided()>::value;
bool_constant<_Mp::is_always_exhaustive()>::value;
bool_constant<_Mp::is_always_unique()>::value;
};
template<typename _Mapping, typename... _Indices>
constexpr typename _Mapping::index_type
__linear_index_strides(const _Mapping& __m, _Indices... __indices)
noexcept
{
using _IndexType = typename _Mapping::index_type;
_IndexType __res = 0;
if constexpr (sizeof...(__indices) > 0)
{
auto __update = [&, __pos = 0u](_IndexType __idx) mutable
{
_GLIBCXX_DEBUG_ASSERT(cmp_less(__idx,
__m.extents().extent(__pos)));
__res += __idx * __m.stride(__pos++);
};
(__update(__indices), ...);
}
return __res;
}
}
template<typename _Extents>
class layout_stride::mapping
{
public:
using extents_type = _Extents;
using index_type = typename extents_type::index_type;
using size_type = typename extents_type::size_type;
using rank_type = typename extents_type::rank_type;
using layout_type = layout_stride;
static_assert(__mdspan::__representable_size<extents_type, index_type>,
"The size of extents_type must be representable as index_type");
constexpr
mapping() noexcept
{
// The precondition is either statically asserted, or automatically
// satisfied because dynamic extents are zero-initialized.
size_t __stride = 1;
for (size_t __i = extents_type::rank(); __i > 0; --__i)
{
_M_strides[__i - 1] = index_type(__stride);
__stride *= size_t(_M_extents.extent(__i - 1));
}
}
constexpr
mapping(const mapping&) noexcept = default;
template<typename _OIndexType>
requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
constexpr
mapping(const extents_type& __exts,
span<_OIndexType, extents_type::rank()> __strides) noexcept
: _M_extents(__exts)
{
for (size_t __i = 0; __i < extents_type::rank(); ++__i)
_M_strides[__i] = index_type(as_const(__strides[__i]));
}
template<typename _OIndexType>
requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
constexpr
mapping(const extents_type& __exts,
const array<_OIndexType, extents_type::rank()>& __strides)
noexcept
: mapping(__exts,
span<const _OIndexType, extents_type::rank()>(__strides))
{ }
template<__mdspan::__mapping_alike _StridedMapping>
requires (is_constructible_v<extents_type,
typename _StridedMapping::extents_type>
&& _StridedMapping::is_always_unique()
&& _StridedMapping::is_always_strided())
constexpr explicit(!(
is_convertible_v<typename _StridedMapping::extents_type, extents_type>
&& __mdspan::__standardized_mapping<_StridedMapping>))
mapping(const _StridedMapping& __other) noexcept
: _M_extents(__other.extents())
{
using _OIndexType = _StridedMapping::index_type;
using _OExtents = _StridedMapping::extents_type;
__glibcxx_assert(__mdspan::__offset(__other) == 0);
static_assert(__mdspan::__representable_size<_OExtents, index_type>,
"The size of StridedMapping::extents_type must be representable as"
" index_type");
if constexpr (cmp_greater(__gnu_cxx::__int_traits<_OIndexType>::__max,
__gnu_cxx::__int_traits<index_type>::__max))
__glibcxx_assert(!cmp_less(
__gnu_cxx::__int_traits<index_type>::__max,
__other.required_span_size())
&& "other.required_span_size() must be representable"
" as index_type");
if constexpr (extents_type::rank() > 0)
for (size_t __i = 0; __i < extents_type::rank(); ++__i)
_M_strides[__i] = index_type(__other.stride(__i));
}
constexpr mapping&
operator=(const mapping&) noexcept = default;
constexpr const extents_type&
extents() const noexcept { return _M_extents; }
constexpr array<index_type, extents_type::rank()>
strides() const noexcept
{
array<index_type, extents_type::rank()> __ret;
for (size_t __i = 0; __i < extents_type::rank(); ++__i)
__ret[__i] = _M_strides[__i];
return __ret;
}
constexpr index_type
required_span_size() const noexcept
{
if (__mdspan::__empty(_M_extents))
return 0;
index_type __ret = 1;
for (size_t __i = 0; __i < extents_type::rank(); ++__i)
__ret += (_M_extents.extent(__i) - 1) * _M_strides[__i];
return __ret;
}
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 4314. Missing move in mdspan layout mapping::operator()
template<__mdspan::__valid_index_type<index_type>... _Indices>
requires (sizeof...(_Indices) == extents_type::rank())
constexpr index_type
operator()(_Indices... __indices) const noexcept
{
return __mdspan::__linear_index_strides(*this,
static_cast<index_type>(std::move(__indices))...);
}
static constexpr bool
is_always_unique() noexcept { return true; }
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 4266. layout_stride::mapping should treat empty mappings as exhaustive
static constexpr bool
is_always_exhaustive() noexcept
{
return (_Extents::rank() == 0) || __mdspan::__contains_zero(
__mdspan::__static_extents<extents_type>());
}
static constexpr bool
is_always_strided() noexcept { return true; }
static constexpr bool
is_unique() noexcept { return true; }
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 4266. layout_stride::mapping should treat empty mappings as exhaustive
constexpr bool
is_exhaustive() const noexcept
{
if constexpr (!is_always_exhaustive())
{
auto __size = __mdspan::__size(_M_extents);
if(__size > 0)
return __size == required_span_size();
}
return true;
}
static constexpr bool
is_strided() noexcept { return true; }
constexpr index_type
stride(rank_type __r) const noexcept { return _M_strides[__r]; }
template<__mdspan::__mapping_alike _OMapping>
requires ((extents_type::rank() == _OMapping::extents_type::rank())
&& _OMapping::is_always_strided())
friend constexpr bool
operator==(const mapping& __self, const _OMapping& __other) noexcept
{
if (__self.extents() != __other.extents())
return false;
if constexpr (extents_type::rank() > 0)
for (size_t __i = 0; __i < extents_type::rank(); ++__i)
if (!cmp_equal(__self.stride(__i), __other.stride(__i)))
return false;
return __mdspan::__offset(__other) == 0;
}
private:
#if __glibcxx_submdspan
template<typename... _Slices>
requires (extents_type::rank() == sizeof...(_Slices))
friend constexpr auto
submdspan_mapping(const mapping& __mapping, _Slices... __slices)
{
if constexpr (sizeof...(_Slices) == 0)
return submdspan_mapping_result{__mapping, 0};
else
{
auto __offset = __mdspan::__suboffset(__mapping, __slices...);
auto __sub_exts = __mdspan::__subextents(__mapping.extents(), __slices...);
auto __sub_strides
= __mdspan::__substrides<decltype(__sub_exts)>(__mapping, __slices...);
return submdspan_mapping_result{
layout_stride::mapping(__sub_exts, __sub_strides), __offset};
}
}
#endif
using _Strides = typename __array_traits<index_type,
extents_type::rank()>::_Type;
[[no_unique_address]] extents_type _M_extents;
[[no_unique_address]] _Strides _M_strides;
};
#ifdef __glibcxx_padded_layouts
namespace __mdspan
{
constexpr size_t
__least_multiple(size_t __x, size_t __y)
{
if (__x <= 1)
return __y;
return (__y / __x + (__y % __x != 0)) * __x ;
}
template<typename _IndexType>
constexpr bool
__is_representable_least_multiple(size_t __x, size_t __y)
{
constexpr auto __y_max = __gnu_cxx::__int_traits<_IndexType>::__max;
if(std::cmp_greater(__y, __y_max))
return false;
if(__x <= 1)
return true;
auto __max_delta = __y_max - static_cast<_IndexType>(__y);
auto __y_mod_x = __y % __x;
auto __delta = (__y_mod_x == 0) ? size_t(0) : (__x - __y_mod_x);
return std::cmp_less_equal(__delta, __max_delta);
}
template<typename _Extents, size_t _PaddingValue, typename _LayoutTraits,
size_t _Rank = _Extents::rank()>
concept __valid_static_stride = (_Extents::rank() <= 1)
|| (_PaddingValue == dynamic_extent)
|| (_Extents::static_extent(_LayoutTraits::_S_ext_idx) == dynamic_extent)
|| (__is_representable_least_multiple<size_t>(
_PaddingValue, _Extents::static_extent(_LayoutTraits::_S_ext_idx)));
template<size_t _PaddedStride, typename _Extents,
typename _LayoutTraits>
consteval bool
__is_representable_padded_size()
{
using _IndexType = typename _Extents::index_type;
auto __sta_exts = __static_extents<_Extents>(
_LayoutTraits::_S_unpad_begin, _LayoutTraits::_S_unpad_end);
size_t __max = __gnu_cxx::__int_traits<_IndexType>::__max;
return __static_quotient(__sta_exts, __max / _PaddedStride) != 0;
}
template<typename _Extents, size_t _PaddedStride, typename _LayoutTraits,
size_t _Rank = _Extents::rank()>
concept __valid_padded_size = (_Rank <= 1)
|| (_PaddedStride == dynamic_extent)
|| (!__all_static(__static_extents<_Extents>()))
|| (__contains_zero(__static_extents<_Extents>()))
|| (__is_representable_padded_size<_PaddedStride, _Extents,
_LayoutTraits>());
template<typename _Extents, typename _Stride, typename... _Indices>
constexpr typename _Extents::index_type
__linear_index_leftpad(const _Extents& __exts, _Stride __stride,
_Indices... __indices)
{
// i0 + stride*(i1 + extents.extent(1)*...)
using _IndexType = typename _Extents::index_type;
_IndexType __res = 0;
if constexpr (sizeof...(__indices) > 0)
{
_IndexType __mult = 1;
auto __update_rest = [&, __pos = 1u](_IndexType __idx) mutable
{
__res += __idx * __mult;
__mult *= __exts.extent(__pos);
++__pos;
};
auto __update = [&](_IndexType __idx, auto... __rest)
{
__res += __idx;
__mult = __stride.extent(0);
(__update_rest(__rest), ...);
};
__update(__indices...);
}
return __res;
}
template<typename _Extents, typename _Stride, typename... _Indices>
constexpr typename _Extents::index_type
__linear_index_rightpad(const _Extents& __exts, _Stride __stride,
_Indices... __indices)
{
// i[n-1] + stride*(i[n-2] + extents.extent(n-2])*...)
using _IndexType = typename _Extents::index_type;
_IndexType __res = 0;
if constexpr (sizeof...(__indices) > 0)
{
_IndexType __mult = 1;
array<_IndexType, sizeof...(__indices)> __ind_arr{__indices...};
auto __update_rest = [&, __pos = __exts.rank()-1](_IndexType) mutable
{
--__pos;
__res += __ind_arr[__pos] * __mult;
__mult *= __exts.extent(__pos);
};
auto __update = [&](_IndexType, auto... __rest)
{
__res += __ind_arr[__exts.rank() - 1];
__mult = __stride.extent(0);
(__update_rest(__rest), ...);
};
__update(__indices...);
}
return __res;
}
template<size_t _Rank>
struct _LeftPaddedLayoutTraits
{
using _LayoutSame = layout_left;
using _LayoutOther = layout_right;
constexpr static const size_t _S_ext_idx = 0;
constexpr static const size_t _S_stride_idx = 1;
constexpr static const size_t _S_unpad_begin = 1;
constexpr static const size_t _S_unpad_end = _Rank;
template<typename _IndexType, size_t _StaticStride, size_t..._Extents>
constexpr static auto
_S_make_padded_extent(
extents<_IndexType, _StaticStride> __stride,
const extents<_IndexType, _Extents...>& __exts)
{
auto __impl = [&]<size_t... _Is>(integer_sequence<size_t, _Is...>)
{
return extents<_IndexType, _StaticStride,
(_Extents...[_Is + 1])...>{
__stride.extent(0), __exts.extent(_Is + 1)...};
};
return __impl(make_index_sequence<sizeof...(_Extents) - 1>());
}
};
template<size_t _Rank>
struct _RightPaddedLayoutTraits
{
using _LayoutSame = layout_right;
using _LayoutOther = layout_left;
constexpr static size_t _S_ext_idx = _Rank - 1;
constexpr static size_t _S_stride_idx = _Rank - 2;
constexpr static size_t _S_unpad_begin = 0;
constexpr static size_t _S_unpad_end = _Rank - 1;
template<typename _IndexType, size_t _StaticStride, size_t..._Extents>
constexpr static auto
_S_make_padded_extent(
extents<_IndexType, _StaticStride> __stride,
const extents<_IndexType, _Extents...>& __exts)
{
auto __impl = [&]<size_t... _Is>(integer_sequence<size_t, _Is...>)
{
return extents<_IndexType, (_Extents...[_Is])..., _StaticStride>{
__exts.extent(_Is)..., __stride.extent(0)};
};
return __impl(make_index_sequence<sizeof...(_Extents) - 1>());
}
};
template<size_t _PaddingValue, typename _Extents, typename _LayoutTraits>
class _PaddedStorage
{
using _LayoutSame = typename _LayoutTraits::_LayoutSame;
public:
using _IndexType = typename _Extents::index_type;
constexpr static size_t _S_rank = _Extents::rank();
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 4372. Weaken Mandates: for dynamic padding values in padded layouts
static_assert((_PaddingValue == dynamic_extent)
|| (cmp_less_equal(_PaddingValue,
__gnu_cxx::__int_traits<_IndexType>::__max)),
"padding_value must be representable as index_type");
static_assert(__representable_size<_Extents, _IndexType>,
"The size of extents_type must be representable as index_type");
static_assert(__valid_static_stride<_Extents, _PaddingValue,
_LayoutTraits>,
"The padded stride must be representable as size_t");
static constexpr size_t _S_static_stride = [] consteval
{
constexpr size_t __rank = _Extents::rank();
if constexpr (__rank <= 1)
return 0;
else
{
constexpr size_t __ext_idx = _LayoutTraits::_S_ext_idx;
constexpr size_t __sta_ext = _Extents::static_extent(__ext_idx);
if constexpr (__sta_ext == 0)
return size_t(0);
else if constexpr (_PaddingValue == dynamic_extent
|| __sta_ext == dynamic_extent)
return dynamic_extent;
else
return __least_multiple(_PaddingValue, __sta_ext);
}
}();
static_assert(_S_static_stride == dynamic_extent
|| cmp_less_equal(_S_static_stride,
__gnu_cxx::__int_traits<_IndexType>::__max),
"Padded stride must be representable as index_type");
static_assert(__valid_padded_size<_Extents, _S_static_stride,
_LayoutTraits>);
constexpr
_PaddedStorage() noexcept
{
if constexpr (_S_rank > 1)
if constexpr (_S_static_stride == dynamic_extent
&& _S_static_padextent() != dynamic_extent)
_M_stride = _Stride{_S_static_padextent()};
}
constexpr explicit
_PaddedStorage(const _Extents& __exts)
: _M_extents(__exts)
{
if constexpr (!__all_static(__static_extents<_Extents>()))
__glibcxx_assert(__is_representable_extents(_M_extents));
if constexpr (_S_rank > 1)
{
_IndexType __stride;
if constexpr (_PaddingValue == dynamic_extent)
__stride = _M_padextent();
else if constexpr (_S_static_padextent() != dynamic_extent)
return;
else
{
__glibcxx_assert(
__is_representable_least_multiple<_IndexType>(
_PaddingValue, _M_padextent()));
__stride = static_cast<_IndexType>(
__least_multiple(_PaddingValue, _M_padextent()));
__glibcxx_assert(__is_representable_extents(
_LayoutTraits::_S_make_padded_extent(
std::dextents<_IndexType, 1>{__stride},
_M_extents)));
}
_M_stride = _Stride{__stride};
}
}
constexpr explicit
_PaddedStorage(const _Extents& __exts, _IndexType __pad)
: _M_extents(__exts)
{
if constexpr (_PaddingValue != dynamic_extent)
__glibcxx_assert(cmp_equal(_PaddingValue, __pad));
if constexpr (_S_rank > 1 && _S_static_stride == dynamic_extent)
{
__glibcxx_assert(
__is_representable_least_multiple<_IndexType>(
__pad, _M_padextent()));
_M_stride = _Stride{static_cast<_IndexType>(
__least_multiple(__pad, _M_padextent()))};
__glibcxx_assert(__is_representable_extents(
_LayoutTraits::_S_make_padded_extent(
_M_stride, _M_extents)));
}
}
template<typename _OExtents>
constexpr explicit
_PaddedStorage(
const typename _LayoutSame::template mapping<_OExtents>& __other)
: _PaddedStorage(_Extents(__other.extents()))
{
constexpr size_t __stride_idx = _LayoutTraits::_S_stride_idx;
constexpr size_t __ext_idx = _LayoutTraits::_S_ext_idx;
if constexpr (_S_rank > 1 && _PaddingValue != dynamic_extent)
{
static_assert(_S_static_stride == dynamic_extent
|| _OExtents::static_extent(__ext_idx) == dynamic_extent
|| _S_static_stride == _OExtents::static_extent(__ext_idx),
"The padded stride must be compatible with other");
if constexpr (_S_static_stride == dynamic_extent
|| _OExtents::static_extent(__stride_idx) == dynamic_extent)
__glibcxx_assert(std::cmp_equal(_M_padstride(),
_M_padextent()));
}
}
template<typename _OExtents>
constexpr explicit
_PaddedStorage(const typename layout_stride::mapping<_OExtents>&
__other)
: _M_extents(__other.extents())
{
__glibcxx_assert(cmp_less_equal(__other.required_span_size(),
__gnu_cxx::__int_traits<_IndexType>
::__max));
constexpr size_t __stride_idx = _LayoutTraits::_S_stride_idx;
if constexpr (_S_rank > 1)
{
if constexpr (_PaddingValue != dynamic_extent)
__glibcxx_assert(cmp_equal(__other.stride(__stride_idx),
_M_calc_padstride())
&& "The padded stride must be compatible with other");
if constexpr (_S_static_stride == dynamic_extent)
_M_stride = _Stride{__other.stride(__stride_idx)};
}
}
template<typename _SamePaddedMapping>
constexpr explicit
_PaddedStorage(_LayoutTraits::_LayoutSame,
const _SamePaddedMapping& __other)
: _M_extents(__other.extents())
{
if constexpr (_S_rank > 1)
{
static_assert(_PaddingValue == dynamic_extent
|| _SamePaddedMapping::padding_value == dynamic_extent
|| _PaddingValue == _SamePaddedMapping::padding_value,
"If neither PaddingValue is dynamic_extent, then they must "
"be equal");
constexpr size_t __stride_idx = _LayoutTraits::_S_stride_idx;
if constexpr (_PaddingValue != dynamic_extent)
__glibcxx_assert(cmp_equal(__other.stride(__stride_idx),
_M_calc_padstride())
&& "The padded stride must be compatible with other");
if constexpr (_S_static_stride == dynamic_extent)
_M_stride = _Stride{__other.stride(__stride_idx)};
}
__glibcxx_assert(cmp_less_equal(__other.required_span_size(),
__gnu_cxx::__int_traits<_IndexType>::__max));
}
template<typename _OtherPaddedMapping>
constexpr explicit
_PaddedStorage(_LayoutTraits::_LayoutOther,
const _OtherPaddedMapping& __other) noexcept
: _M_extents(__other.extents())
{
__glibcxx_assert(cmp_less_equal(__other.required_span_size(),
__gnu_cxx::__int_traits<_IndexType>::__max));
}
static constexpr bool
_M_is_always_exhaustive() noexcept
{
if constexpr (_S_rank <= 1)
return true;
else
return _S_static_padextent() != dynamic_extent
&& _S_static_stride != dynamic_extent
&& _S_static_padextent() == _S_static_stride;
}
constexpr bool
_M_is_exhaustive() const noexcept
{
if constexpr (_M_is_always_exhaustive())
return true;
else
return cmp_equal(_M_padextent(), _M_padstride());
}
constexpr static size_t
_S_static_padextent() noexcept
{ return _Extents::static_extent(_LayoutTraits::_S_ext_idx); }
constexpr _IndexType
_M_padextent() const noexcept
{ return _M_extents.extent(_LayoutTraits::_S_ext_idx); }
constexpr _IndexType
_M_calc_padstride() const noexcept
{
if constexpr (_S_static_stride != dynamic_extent)
return _S_static_stride;
else if constexpr (_PaddingValue != dynamic_extent)
return __least_multiple(_PaddingValue, _M_padextent());
else
return _M_padextent();
}
constexpr _IndexType
_M_padstride() const noexcept
{ return _M_stride.extent(0); }
constexpr _IndexType
_M_required_span_size() const noexcept
{
if constexpr (_S_rank == 0)
return 1;
else if (__mdspan::__empty(_M_extents))
return 0;
else
{
size_t __stride = static_cast<size_t>(_M_padstride());
size_t __prod_rest = __mdspan::__fwd_prod(_M_extents,
_LayoutTraits::_S_unpad_begin, _LayoutTraits::_S_unpad_end);
size_t __delta = _M_padstride() - _M_padextent();
return static_cast<_IndexType>(__stride * __prod_rest - __delta);
}
}
template<typename _SamePaddedMapping>
constexpr bool
_M_equal(const _SamePaddedMapping& __other) const noexcept
{
return _M_extents == __other.extents()
&& (_S_rank < 2
|| cmp_equal(_M_stride.extent(0),
__other.stride(_LayoutTraits::_S_stride_idx)));
}
using _Stride = std::extents<_IndexType, _S_static_stride>;
[[no_unique_address]] _Stride _M_stride;
[[no_unique_address]] _Extents _M_extents;
};
}
template<size_t _PaddingValue>
template<typename _Extents>
class layout_left_padded<_PaddingValue>::mapping
{
public:
static constexpr size_t padding_value = _PaddingValue;
using extents_type = _Extents;
using index_type = typename extents_type::index_type;
using size_type = typename extents_type::size_type;
using rank_type = typename extents_type::rank_type;
using layout_type = layout_left_padded<padding_value>;
private:
static constexpr size_t _S_rank = extents_type::rank();
using _PaddedStorage = __mdspan::_PaddedStorage<_PaddingValue,
_Extents, __mdspan::_LeftPaddedLayoutTraits<_S_rank>>;
[[no_unique_address]] _PaddedStorage _M_storage;
consteval friend size_t
__mdspan::__get_static_stride<mapping>();
constexpr index_type
_M_extent(size_t __r) const noexcept
{ return _M_storage._M_extents.extent(__r); }
constexpr index_type
_M_padstride() const noexcept
{ return _M_storage._M_stride.extent(0); }
public:
constexpr
mapping() noexcept
{ }
constexpr
mapping(const mapping&) noexcept = default;
constexpr
mapping(const extents_type& __exts)
: _M_storage(__exts)
{ }
template<__mdspan::__valid_index_type<index_type> _OIndexType>
constexpr
mapping(const extents_type& __exts, _OIndexType __pad)
: _M_storage(__exts,
__mdspan::__index_type_cast<index_type>(std::move(__pad)))
{ }
template<typename _OExtents>
requires is_constructible_v<extents_type, _OExtents>
constexpr explicit(!is_convertible_v<_OExtents, extents_type>)
mapping(const layout_left::mapping<_OExtents>& __other)
: _M_storage(__other)
{ }
template<typename _OExtents>
requires is_constructible_v<_OExtents, extents_type>
constexpr explicit(!(_OExtents::rank() == 0
&& is_convertible_v<_OExtents, extents_type>))
mapping(const typename layout_stride::mapping<_OExtents>& __other)
: _M_storage(__other)
{ __glibcxx_assert(*this == __other); }
template<typename _LeftPaddedMapping>
requires __mdspan::__is_left_padded_mapping<_LeftPaddedMapping>
&& is_constructible_v<extents_type,
typename _LeftPaddedMapping::extents_type>
constexpr explicit(
!is_convertible_v<typename _LeftPaddedMapping::extents_type,
extents_type>
|| _S_rank > 1 && (padding_value != dynamic_extent
|| _LeftPaddedMapping::padding_value == dynamic_extent))
mapping(const _LeftPaddedMapping& __other)
: _M_storage(layout_left{}, __other)
{ }
template<typename _RightPaddedMapping>
requires (__mdspan::__is_right_padded_mapping<_RightPaddedMapping>
|| __mdspan::__mapping_of<layout_right, _RightPaddedMapping>)
&& (_S_rank <= 1)
&& is_constructible_v<extents_type,
typename _RightPaddedMapping::extents_type>
constexpr explicit(!is_convertible_v<
typename _RightPaddedMapping::extents_type, extents_type>)
mapping(const _RightPaddedMapping& __other) noexcept
: _M_storage(layout_right{}, __other)
{ }
constexpr mapping&
operator=(const mapping&) noexcept = default;
constexpr const extents_type&
extents() const noexcept { return _M_storage._M_extents; }
constexpr array<index_type, _S_rank>
strides() const noexcept
{
array<index_type, _S_rank> __ret;
if constexpr (_S_rank > 0)
__ret[0] = 1;
if constexpr (_S_rank > 1)
__ret[1] = _M_padstride();
if constexpr (_S_rank > 2)
for(size_t __i = 2; __i < _S_rank; ++__i)
__ret[__i] = __ret[__i - 1] * _M_extent(__i - 1);
return __ret;
}
constexpr index_type
required_span_size() const noexcept
{ return _M_storage._M_required_span_size(); }
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 4314. Missing move in mdspan layout mapping::operator()
template<__mdspan::__valid_index_type<index_type>... _Indices>
requires (sizeof...(_Indices) == _S_rank)
constexpr index_type
operator()(_Indices... __indices) const noexcept
{
return __mdspan::__linear_index_leftpad(
extents(), _M_storage._M_stride,
static_cast<index_type>(std::move(__indices))...);
}
static constexpr bool
is_always_exhaustive() noexcept
{ return _PaddedStorage::_M_is_always_exhaustive(); }
constexpr bool
is_exhaustive() noexcept
{ return _M_storage._M_is_exhaustive(); }
static constexpr bool
is_always_unique() noexcept { return true; }
static constexpr bool
is_unique() noexcept { return true; }
static constexpr bool
is_always_strided() noexcept { return true; }
static constexpr bool
is_strided() noexcept { return true; }
constexpr index_type
stride(rank_type __r) const noexcept
{
__glibcxx_assert(__r < _S_rank);
if (__r == 0)
return 1;
else
return static_cast<index_type>(
static_cast<size_t>(_M_padstride()) *
static_cast<size_t>(__mdspan::__fwd_prod(extents(), 1, __r)));
}
template<typename _LeftpadMapping>
requires(__mdspan::__is_left_padded_mapping<_LeftpadMapping>
&& _LeftpadMapping::extents_type::rank() == _S_rank)
friend constexpr bool
operator==(const mapping& __self, const _LeftpadMapping& __other)
noexcept
{ return __self._M_storage._M_equal(__other); }
private:
#if __glibcxx_submdspan
template<typename... _Slices>
requires (extents_type::rank() == sizeof...(_Slices))
friend constexpr auto
submdspan_mapping(const mapping& __mapping, _Slices... __slices)
{ return __mdspan::__submdspan_mapping_impl(__mapping, __slices...); }
#endif // __glibcxx_submdspan
};
template<size_t _PaddingValue>
template<typename _Extents>
class layout_right_padded<_PaddingValue>::mapping {
public:
static constexpr size_t padding_value = _PaddingValue;
using extents_type = _Extents;
using index_type = typename extents_type::index_type;
using size_type = typename extents_type::size_type;
using rank_type = typename extents_type::rank_type;
using layout_type = layout_right_padded<_PaddingValue>;
private:
static constexpr size_t _S_rank = extents_type::rank();
using _PaddedStorage = __mdspan::_PaddedStorage<_PaddingValue,
_Extents, __mdspan::_RightPaddedLayoutTraits<_S_rank>>;
[[no_unique_address]] _PaddedStorage _M_storage;
consteval friend size_t
__mdspan::__get_static_stride<mapping>();
constexpr index_type
_M_extent(size_t __r) const noexcept
{ return _M_storage._M_extents.extent(__r); }
constexpr index_type
_M_padstride() const noexcept
{ return _M_storage._M_stride.extent(0); }
public:
constexpr
mapping() noexcept
{ }
constexpr
mapping(const mapping&) noexcept = default;
constexpr
mapping(const extents_type& __exts)
: _M_storage(__exts)
{ }
template<__mdspan::__valid_index_type<index_type> _OIndexType>
constexpr
mapping(const extents_type& __exts, _OIndexType __pad)
: _M_storage(__exts,
__mdspan::__index_type_cast<index_type>(std::move(__pad)))
{ }
template<typename _OExtents>
requires is_constructible_v<extents_type, _OExtents>
constexpr explicit(!is_convertible_v<_OExtents, extents_type>)
mapping(const layout_right::mapping<_OExtents>& __other)
: _M_storage(__other)
{ }
template<typename _OExtents>
requires is_constructible_v<_OExtents, extents_type>
constexpr explicit(!(_OExtents::rank() == 0
&& is_convertible_v<_OExtents, extents_type>))
mapping(const typename layout_stride::mapping<_OExtents>& __other)
: _M_storage(__other)
{ __glibcxx_assert(*this == __other); }
template<typename _RightPaddedMapping>
requires __mdspan::__is_right_padded_mapping<_RightPaddedMapping>
&& is_constructible_v<extents_type,
typename _RightPaddedMapping::extents_type>
constexpr explicit(
!is_convertible_v<typename _RightPaddedMapping::extents_type,
extents_type>
|| _S_rank > 1 && (padding_value != dynamic_extent
|| _RightPaddedMapping::padding_value == dynamic_extent))
mapping(const _RightPaddedMapping& __other)
: _M_storage(layout_right{}, __other)
{ }
template<typename _LeftPaddedMapping>
requires (__mdspan::__is_left_padded_mapping<_LeftPaddedMapping>
|| __mdspan::__mapping_of<layout_left, _LeftPaddedMapping>)
&& (_S_rank <= 1)
&& is_constructible_v<extents_type,
typename _LeftPaddedMapping::extents_type>
constexpr explicit(!is_convertible_v<
typename _LeftPaddedMapping::extents_type, extents_type>)
mapping(const _LeftPaddedMapping& __other) noexcept
: _M_storage(layout_left{}, __other)
{ }
constexpr mapping& operator=(const mapping&) noexcept = default;
constexpr const extents_type&
extents() const noexcept { return _M_storage._M_extents; }
constexpr array<index_type, _S_rank>
strides() const noexcept
{
array<index_type, _S_rank> __ret;
if constexpr (_S_rank > 0)
__ret[_S_rank - 1] = 1;
if constexpr (_S_rank > 1)
__ret[_S_rank - 2] = _M_padstride();
if constexpr (_S_rank > 2)
for(size_t __i = _S_rank - 2; __i > 0; --__i)
__ret[__i - 1] = __ret[__i] * _M_extent(__i);
return __ret;
}
constexpr index_type
required_span_size() const noexcept
{ return _M_storage._M_required_span_size(); }
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 4314. Missing move in mdspan layout mapping::operator()
template<__mdspan::__valid_index_type<index_type>... _Indices>
requires (sizeof...(_Indices) == _S_rank)
constexpr index_type
operator()(_Indices... __indices) const noexcept
{
return __mdspan::__linear_index_rightpad(
extents(), _M_storage._M_stride,
static_cast<index_type>(std::move(__indices))...);
}
static constexpr bool
is_always_exhaustive() noexcept
{ return _PaddedStorage::_M_is_always_exhaustive(); }
constexpr bool
is_exhaustive() noexcept
{ return _M_storage._M_is_exhaustive(); }
static constexpr bool
is_always_unique() noexcept { return true; }
static constexpr bool
is_unique() noexcept { return true; }
static constexpr bool
is_always_strided() noexcept { return true; }
static constexpr bool
is_strided() noexcept { return true; }
constexpr index_type
stride(rank_type __r) const noexcept
{
__glibcxx_assert(__r < _S_rank);
if constexpr (_S_rank <= 1)
return 1;
else if (__r == _S_rank - 1)
return 1;
else if (__r == _S_rank - 2)
return _M_padstride();
else
return static_cast<index_type>(
static_cast<size_t>(_M_padstride()) *
static_cast<size_t>(__mdspan::__fwd_prod(
extents(), __r + 1, _S_rank - 1)));
}
template<typename _RightPaddedMapping>
requires(__mdspan::__is_right_padded_mapping<_RightPaddedMapping>
&& _RightPaddedMapping::extents_type::rank() == _S_rank)
friend constexpr bool
operator==(const mapping& __self, const _RightPaddedMapping& __other)
noexcept
{ return __self._M_storage._M_equal(__other); }
#if __glibcxx_submdspan
private:
template<typename... _Slices>
requires (extents_type::rank() == sizeof...(_Slices))
friend constexpr auto
submdspan_mapping(const mapping& __mapping, _Slices... __slices)
{ return __mdspan::__submdspan_mapping_impl(__mapping, __slices...); }
#endif // __glibcxx_submdspan
};
#endif // __glibcxx_padded_layouts
template<typename _ElementType>
struct default_accessor
{
static_assert(!is_array_v<_ElementType>,
"ElementType must not be an array type");
static_assert(!is_abstract_v<_ElementType>,
"ElementType must not be an abstract class type");
using offset_policy = default_accessor;
using element_type = _ElementType;
using reference = element_type&;
using data_handle_type = element_type*;
constexpr
default_accessor() noexcept = default;
template<typename _OElementType>
requires is_convertible_v<_OElementType(*)[], element_type(*)[]>
constexpr
default_accessor(default_accessor<_OElementType>) noexcept
{ }
constexpr reference
access(data_handle_type __p, size_t __i) const noexcept
{ return __p[__i]; }
constexpr data_handle_type
offset(data_handle_type __p, size_t __i) const noexcept
{ return __p + __i; }
};
#ifdef __glibcxx_aligned_accessor
template<typename _ElementType, size_t _ByteAlignment>
struct aligned_accessor
{
static_assert(has_single_bit(_ByteAlignment),
"ByteAlignment must be a power of two");
static_assert(_ByteAlignment >= alignof(_ElementType));
using offset_policy = default_accessor<_ElementType>;
using element_type = _ElementType;
using reference = element_type&;
using data_handle_type = element_type*;
static constexpr size_t byte_alignment = _ByteAlignment;
constexpr
aligned_accessor() noexcept = default;
template<typename _OElementType, size_t _OByteAlignment>
requires (_OByteAlignment >= byte_alignment)
&& is_convertible_v<_OElementType(*)[], element_type(*)[]>
constexpr
aligned_accessor(aligned_accessor<_OElementType, _OByteAlignment>)
noexcept
{ }
template<typename _OElementType>
requires is_convertible_v<_OElementType(*)[], element_type(*)[]>
constexpr explicit
aligned_accessor(default_accessor<_OElementType>) noexcept
{ }
template<typename _OElementType>
requires is_convertible_v<element_type(*)[], _OElementType(*)[]>
constexpr
operator default_accessor<_OElementType>() const noexcept
{ return {}; }
constexpr reference
access(data_handle_type __p, size_t __i) const noexcept
{ return std::assume_aligned<byte_alignment>(__p)[__i]; }
constexpr typename offset_policy::data_handle_type
offset(data_handle_type __p, size_t __i) const noexcept
{ return std::assume_aligned<byte_alignment>(__p) + __i; }
};
#endif
template<typename _ElementType, typename _Extents,
typename _LayoutPolicy = layout_right,
typename _AccessorPolicy = default_accessor<_ElementType>>
class mdspan
{
static_assert(!is_array_v<_ElementType>,
"ElementType must not be an array type");
static_assert(!is_abstract_v<_ElementType>,
"ElementType must not be an abstract class type");
static_assert(__mdspan::__is_extents<_Extents>,
"Extents must be a specialization of std::extents");
static_assert(is_same_v<_ElementType,
typename _AccessorPolicy::element_type>);
public:
using extents_type = _Extents;
using layout_type = _LayoutPolicy;
using accessor_type = _AccessorPolicy;
using mapping_type = typename layout_type::template mapping<extents_type>;
using element_type = _ElementType;
using value_type = remove_cv_t<element_type>;
using index_type = typename extents_type::index_type;
using size_type = typename extents_type::size_type;
using rank_type = typename extents_type::rank_type;
using data_handle_type = typename accessor_type::data_handle_type;
using reference = typename accessor_type::reference;
static constexpr rank_type
rank() noexcept { return extents_type::rank(); }
static constexpr rank_type
rank_dynamic() noexcept { return extents_type::rank_dynamic(); }
static constexpr size_t
static_extent(rank_type __r) noexcept
{ return extents_type::static_extent(__r); }
constexpr index_type
extent(rank_type __r) const noexcept { return extents().extent(__r); }
constexpr
mdspan()
requires (rank_dynamic() > 0)
&& is_default_constructible_v<data_handle_type>
&& is_default_constructible_v<mapping_type>
&& is_default_constructible_v<accessor_type> = default;
constexpr
mdspan(const mdspan& __other) = default;
constexpr
mdspan(mdspan&& __other) = default;
template<__mdspan::__valid_index_type<index_type>... _OIndexTypes>
requires (sizeof...(_OIndexTypes) == rank()
|| sizeof...(_OIndexTypes) == rank_dynamic())
&& is_constructible_v<mapping_type, extents_type>
&& is_default_constructible_v<accessor_type>
constexpr explicit
mdspan(data_handle_type __handle, _OIndexTypes... __exts)
: _M_accessor(),
_M_mapping(_Extents(static_cast<index_type>(std::move(__exts))...)),
_M_handle(std::move(__handle))
{ }
template<typename _OIndexType, size_t _Nm>
requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
&& (_Nm == rank() || _Nm == rank_dynamic())
&& is_constructible_v<mapping_type, extents_type>
&& is_default_constructible_v<accessor_type>
constexpr explicit(_Nm != rank_dynamic())
mdspan(data_handle_type __handle, span<_OIndexType, _Nm> __exts)
: _M_accessor(), _M_mapping(extents_type(__exts)),
_M_handle(std::move(__handle))
{ }
template<typename _OIndexType, size_t _Nm>
requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
&& (_Nm == rank() || _Nm == rank_dynamic())
&& is_constructible_v<mapping_type, extents_type>
&& is_default_constructible_v<accessor_type>
constexpr explicit(_Nm != rank_dynamic())
mdspan(data_handle_type __handle, const array<_OIndexType, _Nm>& __exts)
: _M_accessor(), _M_mapping(extents_type(__exts)),
_M_handle(std::move(__handle))
{ }
constexpr
mdspan(data_handle_type __handle, const extents_type& __exts)
requires is_constructible_v<mapping_type, const extents_type&>
&& is_default_constructible_v<accessor_type>
: _M_accessor(), _M_mapping(__exts), _M_handle(std::move(__handle))
{ }
constexpr
mdspan(data_handle_type __handle, const mapping_type& __mapping)
requires is_default_constructible_v<accessor_type>
: _M_accessor(), _M_mapping(__mapping), _M_handle(std::move(__handle))
{ }
constexpr
mdspan(data_handle_type __handle, const mapping_type& __mapping,
const accessor_type& __accessor)
: _M_accessor(__accessor), _M_mapping(__mapping),
_M_handle(std::move(__handle))
{ }
template<typename _OElementType, typename _OExtents, typename _OLayout,
typename _OAccessor>
requires is_constructible_v<mapping_type,
const typename _OLayout::template mapping<_OExtents>&>
&& is_constructible_v<accessor_type, const _OAccessor&>
constexpr explicit(!is_convertible_v<
const typename _OLayout::template mapping<_OExtents>&, mapping_type>
|| !is_convertible_v<const _OAccessor&, accessor_type>)
mdspan(const mdspan<_OElementType, _OExtents, _OLayout, _OAccessor>&
__other)
: _M_accessor(__other.accessor()), _M_mapping(__other.mapping()),
_M_handle(__other.data_handle())
{
static_assert(is_constructible_v<data_handle_type,
const typename _OAccessor::data_handle_type&>);
static_assert(is_constructible_v<extents_type, _OExtents>);
}
constexpr mdspan&
operator=(const mdspan& __other) = default;
constexpr mdspan&
operator=(mdspan&& __other) = default;
template<__mdspan::__valid_index_type<index_type>... _OIndexTypes>
requires (sizeof...(_OIndexTypes) == rank())
constexpr reference
operator[](_OIndexTypes... __indices) const
{
if constexpr (rank() == 0)
return _M_accessor.access(_M_handle, _M_mapping());
else if constexpr (!(is_same_v<_OIndexTypes, index_type> && ...))
return operator[](
__mdspan::__index_type_cast<index_type>(std::move(__indices))...);
else
{
auto __is_multi_index = [&]<size_t... _Counts>(index_sequence<_Counts...>)
{ return ((__indices < extents().extent(_Counts)) && ...); };
__glibcxx_assert(__is_multi_index(make_index_sequence<rank()>()));
return _M_accessor.access(_M_handle, _M_mapping(__indices...));
}
}
template<typename _OIndexType>
requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
constexpr reference
operator[](span<_OIndexType, rank()> __indices) const
{
auto __call = [&]<size_t... _Counts>(index_sequence<_Counts...>)
-> reference
{
return operator[](
__mdspan::__index_type_cast<index_type>(as_const(__indices[_Counts]))...);
};
return __call(make_index_sequence<rank()>());
}
template<typename _OIndexType>
requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
constexpr reference
operator[](const array<_OIndexType, rank()>& __indices) const
{ return operator[](span<const _OIndexType, rank()>(__indices)); }
#if __cplusplus > 202302L
template<__mdspan::__valid_index_type<index_type>... _OIndexTypes>
requires (sizeof...(_OIndexTypes) == rank())
constexpr reference
at(_OIndexTypes... __indices) const
{
if constexpr (rank() == 0)
return _M_accessor.access(_M_handle, _M_mapping());
else if constexpr (!(is_integral_v<_OIndexTypes> && ...))
return at(__index_int_t<_OIndexTypes>(std::move(__indices))...);
else
{
auto __check_bound = [&]<typename _OIntType>(size_t __dim, _OIntType __index)
{
if constexpr (is_signed_v<_OIntType>)
if (__index < 0)
std::__throw_out_of_range_fmt(
__N("mdspan::at: %zuth index is negative"), __dim);
const auto __ext = extents().extent(__dim);
if (std::cmp_greater_equal(__index, __ext))
std::__throw_out_of_range_fmt(
__N("mdspan::at: %zuth index (which is %zu)"
" >= extent(%zu) (which is %zu)"),
__dim, size_t(__index), __dim, size_t(__ext));
};
auto __check_bounds = [&]<size_t... _Counts>(index_sequence<_Counts...>)
{ (__check_bound(_Counts, __indices), ...); };
__check_bounds(make_index_sequence<rank()>());
auto __index = _M_mapping(static_cast<index_type>(__indices)...);
return _M_accessor.access(_M_handle, __index);
}
}
template<typename _OIndexType>
requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
constexpr reference
at(span<_OIndexType, rank()> __indices) const
{
auto __call = [&]<size_t... _Counts>(index_sequence<_Counts...>)
-> reference
{
return at(
__index_int_t<_OIndexType>(as_const(__indices[_Counts]))...);
};
return __call(make_index_sequence<rank()>());
}
template<typename _OIndexType>
requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
constexpr reference
at(const array<_OIndexType, rank()>& __indices) const
{ return at(span<const _OIndexType, rank()>(__indices)); }
#endif // C++26
constexpr size_type
size() const noexcept
{
__glibcxx_assert(cmp_less_equal(_M_mapping.required_span_size(),
__gnu_cxx::__int_traits<size_t>
::__max));
return size_type(__mdspan::__size(extents()));
}
[[nodiscard]]
constexpr bool
empty() const noexcept
{ return __mdspan::__empty(extents()); }
friend constexpr void
swap(mdspan& __x, mdspan& __y) noexcept
{
using std::swap;
swap(__x._M_mapping, __y._M_mapping);
swap(__x._M_accessor, __y._M_accessor);
swap(__x._M_handle, __y._M_handle);
}
constexpr const extents_type&
extents() const noexcept { return _M_mapping.extents(); }
constexpr const data_handle_type&
data_handle() const noexcept { return _M_handle; }
constexpr const mapping_type&
mapping() const noexcept { return _M_mapping; }
constexpr const accessor_type&
accessor() const noexcept { return _M_accessor; }
// Strengthened noexcept for all `is_*` methods.
static constexpr bool
is_always_unique() noexcept(noexcept(mapping_type::is_always_unique()))
{ return mapping_type::is_always_unique(); }
static constexpr bool
is_always_exhaustive()
noexcept(noexcept(mapping_type::is_always_exhaustive()))
{ return mapping_type::is_always_exhaustive(); }
static constexpr bool
is_always_strided()
noexcept(noexcept(mapping_type::is_always_strided()))
{ return mapping_type::is_always_strided(); }
constexpr bool
is_unique() const noexcept(noexcept(_M_mapping.is_unique()))
{ return _M_mapping.is_unique(); }
constexpr bool
is_exhaustive() const noexcept(noexcept(_M_mapping.is_exhaustive()))
{ return _M_mapping.is_exhaustive(); }
constexpr bool
is_strided() const noexcept(noexcept(_M_mapping.is_strided()))
{ return _M_mapping.is_strided(); }
constexpr index_type
stride(rank_type __r) const { return _M_mapping.stride(__r); }
private:
template<typename _OIndexType>
using __index_int_t = std::__conditional_t<
is_integral_v<_OIndexType>, _OIndexType, index_type>;
[[no_unique_address]] accessor_type _M_accessor = accessor_type();
[[no_unique_address]] mapping_type _M_mapping = mapping_type();
[[no_unique_address]] data_handle_type _M_handle = data_handle_type();
};
template<typename _CArray>
requires is_array_v<_CArray> && (rank_v<_CArray> == 1)
mdspan(_CArray&)
-> mdspan<remove_all_extents_t<_CArray>,
extents<size_t, extent_v<_CArray, 0>>>;
template<typename _Pointer>
requires is_pointer_v<remove_reference_t<_Pointer>>
mdspan(_Pointer&&)
-> mdspan<remove_pointer_t<remove_reference_t<_Pointer>>, extents<size_t>>;
template<typename _ElementType, typename... _Integrals>
requires (is_convertible_v<_Integrals, size_t> && ...)
&& (sizeof...(_Integrals) > 0)
explicit mdspan(_ElementType*, _Integrals...)
-> mdspan<_ElementType,
extents<size_t, __detail::__maybe_static_ext<_Integrals>...>>;
template<typename _ElementType, typename _OIndexType, size_t _Nm>
mdspan(_ElementType*, span<_OIndexType, _Nm>)
-> mdspan<_ElementType, dextents<size_t, _Nm>>;
template<typename _ElementType, typename _OIndexType, size_t _Nm>
mdspan(_ElementType*, const array<_OIndexType, _Nm>&)
-> mdspan<_ElementType, dextents<size_t, _Nm>>;
template<typename _ElementType, typename _IndexType, size_t... _ExtentsPack>
mdspan(_ElementType*, const extents<_IndexType, _ExtentsPack...>&)
-> mdspan<_ElementType, extents<_IndexType, _ExtentsPack...>>;
template<typename _ElementType, typename _MappingType>
mdspan(_ElementType*, const _MappingType&)
-> mdspan<_ElementType, typename _MappingType::extents_type,
typename _MappingType::layout_type>;
template<typename _MappingType, typename _AccessorType>
mdspan(const typename _AccessorType::data_handle_type&, const _MappingType&,
const _AccessorType&)
-> mdspan<typename _AccessorType::element_type,
typename _MappingType::extents_type,
typename _MappingType::layout_type, _AccessorType>;
#if __glibcxx_submdspan
namespace __mdspan
{
template<typename _IndexType, typename _Slice>
constexpr auto
__canonical_index(_Slice&& __slice)
{
if constexpr (__detail::__integral_constant_like<_Slice>)
{
static_assert(__is_representable_integer<_IndexType>(_Slice::value));
static_assert(_Slice::value >= 0);
return std::cw<_IndexType(_Slice::value)>;
}
else
return __mdspan::__index_type_cast<_IndexType>(std::move(__slice));
}
template<typename _IndexType, typename _Slice>
constexpr auto
__slice_cast(_Slice&& __slice)
{
using _SliceType = remove_cvref_t<_Slice>;
if constexpr (is_convertible_v<_SliceType, full_extent_t>)
return static_cast<full_extent_t>(std::move(__slice));
else if constexpr (is_convertible_v<_SliceType, _IndexType>)
return __mdspan::__canonical_index<_IndexType>(std::move(__slice));
else if constexpr (__is_strided_slice<_SliceType>)
{
auto __extent
= __mdspan::__canonical_index<_IndexType>(std::move(__slice.extent));
auto __offset
= __mdspan::__canonical_index<_IndexType>(std::move(__slice.offset));
if constexpr (is_same_v<decltype(__extent),
constant_wrapper<_IndexType(0)>>)
return strided_slice{
.offset = __offset,
.extent = __extent,
.stride = cw<_IndexType(1)>
};
else
return strided_slice{
.offset = __offset,
.extent = __extent,
.stride
= __mdspan::__canonical_index<_IndexType>(std::move(__slice.stride))
};
}
else
{
auto [__sbegin, __send] = std::move(__slice);
auto __offset
= __mdspan::__canonical_index<_IndexType>(std::move(__sbegin));
auto __end
= __mdspan::__canonical_index<_IndexType>(std::move(__send));
return strided_slice{
.offset = __offset,
.extent = __mdspan::__canonical_index<_IndexType>(__end - __offset),
.stride = cw<_IndexType(1)>
};
}
}
template<typename _IndexType, size_t _Extent, typename _OIndexType>
constexpr void
__check_valid_index(const extents<_IndexType, _Extent>& __ext,
const _OIndexType& __idx)
{
if constexpr (__is_constant_wrapper<_OIndexType>
&& _Extent != dynamic_extent)
{
static_assert(_OIndexType::value >= 0);
static_assert(std::cmp_less_equal(_OIndexType::value, _Extent));
}
else
__glibcxx_assert(__idx <= __ext.extent(0));
}
template<typename _IndexType, size_t _Extent, typename _Slice>
constexpr void
__check_valid_slice(const extents<_IndexType, _Extent>& __ext,
const _Slice& __slice)
{
if constexpr (__is_strided_slice<_Slice>)
{
// DEVIATION: For empty slices, P3663r3 does not allow us to check
// that this is less than or equal to the k-th extent (at runtime).
// We're only allowed to check if __slice.offset, __slice.extent
// are constant wrappers and __ext is a static extent.
__mdspan::__check_valid_index(__ext, __slice.offset);
__mdspan::__check_valid_index(__ext, __slice.extent);
if constexpr (__is_constant_wrapper<typename _Slice::extent_type>
&& __is_constant_wrapper<typename _Slice::stride_type>)
static_assert(_Slice::stride_type::value > 0);
else
__glibcxx_assert(__slice.extent == 0 || __slice.stride > 0);
if constexpr (__is_constant_wrapper<typename _Slice::offset_type>
&& __is_constant_wrapper<typename _Slice::extent_type>
&& _Extent != dynamic_extent)
static_assert(std::cmp_greater_equal(
_Extent - _Slice::offset_type::value,
_Slice::extent_type::value));
else
__glibcxx_assert(__ext.extent(0) - __slice.offset
>= __slice.extent);
}
else if constexpr (__is_constant_wrapper<_Slice>
&& _Extent != dynamic_extent)
static_assert(std::cmp_less(_Slice::value, _Extent));
else if constexpr (convertible_to<_Slice, _IndexType>)
__glibcxx_assert(__slice < __ext.extent(0));
}
template<typename _Extents, typename... _Slices>
constexpr void
__check_valid_slices(const _Extents& __exts, const _Slices&... __slices)
{
constexpr auto __rank = _Extents::rank();
auto __impl = [&]<size_t... _Is>(index_sequence<_Is...>)
{
((__mdspan::__check_valid_slice(__extract_extent<_Is>(__exts),
__slices...[_Is])),...);
};
__impl(make_index_sequence<__rank>());
}
template<typename _Slice>
using __full_extent_t = std::full_extent_t;
// Enables ADL-only calls from submdspan.
void submdspan_mapping() = delete;
template<typename _Mapping, typename... _Slices>
concept __sliceable_mapping = requires(const _Mapping __m, _Slices... __slices)
{
{ submdspan_mapping(__m, __slices...) } -> __submdspan_mapping_result;
};
template<typename _Mapping, typename... _Slices>
constexpr auto
__submapping(const _Mapping& __mapping, _Slices... __slices)
{
__mdspan::__check_valid_slices(__mapping.extents(), __slices...);
return submdspan_mapping(__mapping, __slices...);
}
}
template<typename _IndexType, size_t... _Extents, typename... _RawSlices>
requires (sizeof...(_RawSlices) == sizeof...(_Extents))
constexpr auto
subextents(const extents<_IndexType, _Extents...>& __exts,
_RawSlices... __raw_slices)
{
auto __impl = [&__exts](auto... __slices)
{
__mdspan::__check_valid_slices(__exts, __slices...);
return __mdspan::__subextents(__exts, __slices...);
};
return __impl(__mdspan::__slice_cast<_IndexType>(__raw_slices)...);
}
template<typename _IndexType, size_t... _Extents, typename... _RawSlices>
requires (sizeof...(_Extents) == sizeof...(_RawSlices))
constexpr auto
canonical_slices(const extents<_IndexType, _Extents...>& __exts,
_RawSlices... __raw_slices)
{
auto __impl = [&__exts](auto... __slices)
{
__mdspan::__check_valid_slices(__exts, __slices...);
return std::make_tuple(__slices...);
};
return __impl(__mdspan::__slice_cast<_IndexType>(__raw_slices)...);
}
template<typename _ElementType, typename _Extents, typename _Layout,
typename _Accessor, typename... _RawSlices>
requires (sizeof...(_RawSlices) == _Extents::rank()
&& __mdspan::__sliceable_mapping<typename _Layout::template mapping<_Extents>,
__mdspan::__full_extent_t<_RawSlices>...>)
constexpr auto
submdspan(
const mdspan<_ElementType, _Extents, _Layout, _Accessor>& __md,
_RawSlices... __raw_slices)
{
using _IndexType = typename _Extents::index_type;
auto [__mapping, __offset] = __mdspan::__submapping(
__md.mapping(), __mdspan::__slice_cast<_IndexType>(__raw_slices)...);
return std::mdspan(
__md.accessor().offset(__md.data_handle(), __offset),
std::move(__mapping),
typename _Accessor::offset_policy(__md.accessor()));
}
#endif // __glibcxx_submdspan
_GLIBCXX_END_NAMESPACE_VERSION
}
#endif
#endif
array
span
tuple
type_traits
utility
align.h
version.h
stdexcept_throw.h
std::assume_aligned
constexpr _Tp * assume_aligned(_Tp *__ptr) noexcept
Inform the compiler that a pointer is aligned.
Definition align.h:90
std::make_tuple
constexpr tuple< typename __decay_and_strip< _Elements >::__type... > make_tuple(_Elements &&... __args)
Create a tuple containing copies of the arguments.
Definition tuple:2723
std::move
constexpr std::remove_reference< _Tp >::type && move(_Tp &&__t) noexcept
Convert a value to an rvalue.
Definition move.h:138
std::forward
constexpr _Tp && forward(typename std::remove_reference< _Tp >::type &__t) noexcept
Forward an lvalue.
Definition move.h:72
std
ISO C++ entities toplevel namespace is std.
std::make_index_sequence
make_integer_sequence< size_t, _Num > make_index_sequence
Alias template make_index_sequence.
Definition utility.h:166
std::index_sequence
integer_sequence< size_t, _Idx... > index_sequence
Alias template index_sequence.
Definition utility.h:162
__gnu_cxx::__int_traits
__numeric_traits_integer< _Tp > __int_traits
Convenience alias for __numeric_traits<integer-type>.
Definition ext/numeric_traits.h:134