blob: bcf2fa60feabd0e3be47fc354bfe7bf0c8e96298 [file] [log] [blame]
// <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 <limits>
#include <utility>
#define __glibcxx_want_mdspan
#include <bits/version.h>
#ifdef __glibcxx_mdspan
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
namespace __mdspan
{
template<typename _IndexType, array _Extents>
class _ExtentsStorage
{
public:
static consteval bool
_S_is_dyn(size_t __ext) noexcept
{ return __ext == dynamic_extent; }
template<typename _OIndexType>
static constexpr _IndexType
_S_int_cast(const _OIndexType& __other) noexcept
{ return _IndexType(__other); }
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_dynamic_extents.
static constexpr auto _S_dynamic_index = [] 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 += _S_is_dyn(_Extents[__i]);
}
__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 auto _S_dynamic_index_inv = [] consteval
{
array<size_t, _S_rank_dynamic> __ret;
for (size_t __i = 0, __r = 0; __i < _S_rank; ++__i)
if (_S_is_dyn(_Extents[__i]))
__ret[__r++] = __i;
return __ret;
}();
static constexpr size_t
_S_static_extent(size_t __r) noexcept
{ return _Extents[__r]; }
constexpr _IndexType
_M_extent(size_t __r) const noexcept
{
auto __se = _Extents[__r];
if (__se == dynamic_extent)
return _M_dynamic_extents[_S_dynamic_index[__r]];
else
return __se;
}
template<size_t _OtherRank, typename _GetOtherExtent>
constexpr void
_M_init_dynamic_extents(_GetOtherExtent __get_extent) noexcept
{
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_dynamic_extents[__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]; });
}
private:
using _S_storage = __array_traits<_IndexType, _S_rank_dynamic>::_Type;
[[no_unique_address]] _S_storage _M_dynamic_extents{};
};
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 <= numeric_limits<_IndexType>::max();
}
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 _S_storage::_S_rank; }
static constexpr rank_type
rank_dynamic() noexcept { return _S_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 _S_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_dynamic_extents._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) || ...)
|| (numeric_limits<index_type>::max()
< numeric_limits<_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_dynamic_extents(__other._M_dynamic_extents)
{ }
template<__mdspan::__valid_index_type<index_type>... _OIndexTypes>
requires (sizeof...(_OIndexTypes) == rank()
|| sizeof...(_OIndexTypes) == rank_dynamic())
constexpr explicit extents(_OIndexTypes... __exts) noexcept
: _M_dynamic_extents(span<const _IndexType, sizeof...(_OIndexTypes)>(
initializer_list{_S_storage::_S_int_cast(__exts)...}))
{ }
template<__mdspan::__valid_index_type<index_type> _OIndexType, size_t _Nm>
requires (_Nm == rank() || _Nm == rank_dynamic())
constexpr explicit(_Nm != rank_dynamic())
extents(span<_OIndexType, _Nm> __exts) noexcept
: _M_dynamic_extents(span<const _OIndexType, _Nm>(__exts))
{ }
template<__mdspan::__valid_index_type<index_type> _OIndexType, size_t _Nm>
requires (_Nm == rank() || _Nm == rank_dynamic())
constexpr explicit(_Nm != rank_dynamic())
extents(const array<_OIndexType, _Nm>& __exts) noexcept
: _M_dynamic_extents(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
{
for (size_t __i = 0; __i < __self.rank(); ++__i)
if (!cmp_equal(__self.extent(__i), __other.extent(__i)))
return false;
return true;
}
}
private:
using _S_storage = __mdspan::_ExtentsStorage<
_IndexType, array<size_t, sizeof...(_Extents)>{_Extents...}>;
[[no_unique_address]] _S_storage _M_dynamic_extents;
template<typename _OIndexType, size_t... _OExtents>
friend class extents;
};
namespace __mdspan
{
template<typename _IndexType, size_t... _Counts>
auto __build_dextents_type(integer_sequence<size_t, _Counts...>)
-> extents<_IndexType, ((void) _Counts, dynamic_extent)...>;
template<typename _Tp>
consteval size_t
__dynamic_extent() { return dynamic_extent; }
}
template<typename _IndexType, size_t _Rank>
using dextents = decltype(__mdspan::__build_dextents_type<_IndexType>(
make_index_sequence<_Rank>()));
template<typename... _Integrals>
requires (is_convertible_v<_Integrals, size_t> && ...)
explicit extents(_Integrals...) ->
extents<size_t, __mdspan::__dynamic_extent<_Integrals>()...>;
_GLIBCXX_END_NAMESPACE_VERSION
}
#endif
#endif