mirror of git://gcc.gnu.org/git/gcc.git
2455 lines
75 KiB
C++
2455 lines
75 KiB
C++
// <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>
|
|
|
|
#if __cplusplus > 202302L
|
|
#include <bits/align.h>
|
|
#endif
|
|
|
|
#define __glibcxx_want_mdspan
|
|
#define __glibcxx_want_aligned_accessor
|
|
#include <bits/version.h>
|
|
|
|
#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 _OIndexType>
|
|
constexpr _IndexType
|
|
__index_type_cast(_OIndexType&& __other)
|
|
{
|
|
if constexpr (std::is_integral_v<_OIndexType>)
|
|
{
|
|
__glibcxx_assert(cmp_less_equal(__other,
|
|
__gnu_cxx::__int_traits<_IndexType>::__max));
|
|
if constexpr (std::is_signed_v<_OIndexType>)
|
|
__glibcxx_assert(__other >= 0);
|
|
return std::move(__other);
|
|
}
|
|
else
|
|
{
|
|
auto __ret = static_cast<_IndexType>(std::move(__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),
|
|
_M_dyn_exts + _S_dynamic_index(__end)};
|
|
}
|
|
|
|
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); }
|
|
}
|
|
|
|
template<typename _IndexType, size_t... _Extents>
|
|
class extents
|
|
{
|
|
static_assert(__is_standard_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");
|
|
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 const array<size_t, rank()>&
|
|
__mdspan::__static_extents<extents>();
|
|
|
|
friend span<const index_type>
|
|
__mdspan::__dynamic_extents<extents>(const extents&, size_t, size_t);
|
|
|
|
using _Storage = __mdspan::_ExtentsStorage<
|
|
_IndexType, array<size_t, sizeof...(_Extents)>{_Extents...}>;
|
|
[[no_unique_address]] _Storage _M_exts;
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
// 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>;
|
|
#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 _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)
|
|
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));
|
|
}
|
|
|
|
[[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)
|
|
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));
|
|
}
|
|
|
|
[[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>
|
|
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>());
|
|
}
|
|
}
|
|
|
|
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:
|
|
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::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)
|
|
mapping(const typename layout_stride::mapping<_OExtents>& __other)
|
|
: _M_storage(__other)
|
|
{ __glibcxx_assert(*this == __other); }
|
|
|
|
template<typename _LeftpadMapping>
|
|
requires __mdspan::__is_left_padded_mapping<_LeftpadMapping>
|
|
&& is_constructible_v<extents_type,
|
|
typename _LeftpadMapping::extents_type>
|
|
constexpr explicit(_S_rank > 1 && (padding_value != dynamic_extent
|
|
|| _LeftpadMapping::padding_value == dynamic_extent))
|
|
mapping(const _LeftpadMapping& __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_always_strided() noexcept { return true; }
|
|
|
|
static constexpr bool
|
|
is_unique() 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); }
|
|
};
|
|
|
|
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)
|
|
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(_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_always_strided() noexcept { return true; }
|
|
|
|
static constexpr bool
|
|
is_unique() 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); }
|
|
};
|
|
#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
|
|
|
|
namespace __mdspan
|
|
{
|
|
template<typename _Extents, typename _IndexType, size_t _Nm>
|
|
constexpr bool
|
|
__is_multi_index(const _Extents& __exts, span<_IndexType, _Nm> __indices)
|
|
{
|
|
static_assert(__exts.rank() == _Nm);
|
|
for (size_t __i = 0; __i < __exts.rank(); ++__i)
|
|
if (__indices[__i] >= __exts.extent(__i))
|
|
return false;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
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
|
|
{
|
|
auto __checked_call = [this](auto... __idxs) -> index_type
|
|
{
|
|
if constexpr (sizeof...(__idxs) > 0)
|
|
__glibcxx_assert(__mdspan::__is_multi_index(extents(),
|
|
span<const index_type, sizeof...(__idxs)>({__idxs...})));
|
|
return _M_mapping(__idxs...);
|
|
};
|
|
|
|
auto __index = __checked_call(
|
|
static_cast<index_type>(std::move(__indices))...);
|
|
return _M_accessor.access(_M_handle, __index);
|
|
}
|
|
|
|
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 (*this)[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 (*this)[span<const _OIndexType, rank()>(__indices)]; }
|
|
|
|
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:
|
|
[[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>;
|
|
|
|
_GLIBCXX_END_NAMESPACE_VERSION
|
|
}
|
|
#endif
|
|
#endif
|