// <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
	  {
	    // _GLIBCXX_RESOLVE_LIB_DEFECTS
	    // 4314. Missing move in mdspan layout mapping::operator()
	    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 extent_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 _FirstType, typename _LastType, typename _StrideType = constant_wrapper<1zu>>
    struct range_slice
    {
      static_assert(__is_signed_or_unsigned_integer<_FirstType>::value
	|| __detail::__integral_constant_like<_FirstType>);
      static_assert(__is_signed_or_unsigned_integer<_LastType>::value
	|| __detail::__integral_constant_like<_LastType>);
      static_assert(__is_signed_or_unsigned_integer<_StrideType>::value
	|| __detail::__integral_constant_like<_StrideType>);

      [[no_unique_address]] _FirstType first{};
      [[no_unique_address]] _LastType last{};
      [[no_unique_address]] _StrideType 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_extent_slice = false;

    template<typename _OffsetType, typename _ExtentType, typename _StrideType>
      constexpr bool __is_extent_slice<extent_slice<_OffsetType,
	  _ExtentType, _StrideType>> = true;

    template<typename _Tp>
      constexpr bool __is_range_slice = false;

    template<typename _FirstType, typename _LastType, typename _StrideType>
      constexpr bool __is_range_slice<range_slice<_FirstType,
	  _LastType, _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<auto _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_extent_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_extent_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>)
	  return _Slice::extent_type::value;
	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_extent_slice<_Slice>)
	  return __slice.extent;
	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_extent_slice<decltype(__slice)>)
		if (__slice.extent > 1)
		  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_extent_slice<decltype(__slice)>)
		  {
		    if (__slice.extent > 1)
		      __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_extent_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_extent_slice: extent_slice{a, b, cw<1>}, but not `full`,
    //  - extent_slice: extent_slice{a, b, c} with c != cw<1>.
    enum class _SliceKind
    {
      __extent_slice,
      __unit_stride_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_extent_slice<_Slice>)
	  {
	    if constexpr (__mdspan::__is_unit_stride_slice<_Slice>)
	      return _SliceKind::__unit_stride_slice;
	    else
	      return _SliceKind::__extent_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_stride_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_stride_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_stride_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_stride_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] =
	      __mdspan::__index_type_cast<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() const 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() const 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>;

  // _GLIBCXX_RESOLVE_LIB_DEFECTS
  // 4511. Inconsistency between the deduction guide of std::mdspan taking...
  template<typename _MappingType, typename _AccessorType>
    mdspan(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 _OffsetType, typename _SpanType, typename _StrideType>
    constexpr auto
    __canonical_range_slice(_OffsetType __offset, _SpanType __span,
			    _StrideType __stride)
    {
      if constexpr (is_same_v<_SpanType, constant_wrapper<_IndexType(0)>>
		    || is_same_v<_StrideType, constant_wrapper<_IndexType(1)>>)
	return extent_slice{
	  .offset = __offset,
	  .extent = __span,
	  .stride = cw<_IndexType(1)>
	};
      else if constexpr (__is_constant_wrapper<_StrideType>)
        {
	  static_assert(_StrideType::value > 0);
	  if constexpr (__is_constant_wrapper<_SpanType>)
	    return extent_slice{
	      .offset = __offset,
	      .extent = cw<_IndexType(1 + (_SpanType::value - 1) / _StrideType::value)>,
	      .stride = __stride
	    };
	  else
	    return extent_slice{
	      .offset = __offset,
	      .extent = _IndexType(__span > 0 ? 1 + (__span - 1) / _StrideType::value : 0),
	      .stride = __stride
	    };
        }
      else if (__span == 0 || __stride == 1)
	return extent_slice{
	  .offset = __offset,
	  .extent = _IndexType(__span),
	  .stride = _IndexType(1)
	};
      else
        {
	  __glibcxx_assert(__stride > 0);
	  return extent_slice{
	    .offset = __offset,
	    .extent = _IndexType(1 + (__span - 1) / __stride),
	    .stride = __stride
	  };
	}
    }

    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_extent_slice<_SliceType>)
	  return extent_slice{
	    .offset = __mdspan::__canonical_index<_IndexType>(std::move(__slice.offset)),
	    .extent = __mdspan::__canonical_index<_IndexType>(std::move(__slice.extent)),
	    .stride = __mdspan::__canonical_index<_IndexType>(std::move(__slice.stride))
	  };
	else if constexpr (__is_range_slice<_SliceType>)
	  {
	    auto __first
	      = __mdspan::__canonical_index<_IndexType>(std::move(__slice.first));
	    auto __last
	      = __mdspan::__canonical_index<_IndexType>(std::move(__slice.last));
	    return __mdspan::__canonical_range_slice<_IndexType>(
		     __first,
		     __mdspan::__canonical_index<_IndexType>(__last - __first),
		     __mdspan::__canonical_index<_IndexType>(std::move(__slice.stride)));
	  }
	else
	  {
	    auto [__sbegin, __send] = std::move(__slice);
	    auto __cbegin
	      = __mdspan::__canonical_index<_IndexType>(std::move(__sbegin));
	    auto __cend
	      = __mdspan::__canonical_index<_IndexType>(std::move(__send));
	    auto __cspan
	      = __mdspan::__canonical_index<_IndexType>(__cend - __cbegin);
	    return __mdspan::__canonical_range_slice<_IndexType>(
		     __cbegin, __cspan, cw<_IndexType(1)>);
	  }
      }

   template<typename _IndexType, size_t _Extent, typename _OIndexType>
      constexpr void
      __check_inrange_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(_OIndexType::value, _Extent));
	  }
	else
	  __glibcxx_assert(__idx < __ext.extent(0));
      }

    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_extent_slice<_Slice>)
	  {
	    __mdspan::__check_valid_index(__ext, __slice.extent);
	    // 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.
	    if constexpr (is_same_v<typename _Slice::extent_type,
				    constant_wrapper<_IndexType(0)>>)
	      __mdspan::__check_valid_index(__ext, __slice.offset);
	    else if constexpr (is_same_v<typename _Slice::extent_type,
				         constant_wrapper<_IndexType(1)>>)
              __mdspan::__check_inrange_index(__ext, __slice.offset);
	    else if constexpr (__is_constant_wrapper<typename _Slice::extent_type>)
	      { 
              	__mdspan::__check_inrange_index(__ext, __slice.offset);
		if constexpr (__is_constant_wrapper<typename _Slice::stride_type>)
		  static_assert(_Slice::stride_type::value > 0);
		else
		  __glibcxx_assert(__slice.stride > 0);

		if constexpr (_Extent != dynamic_extent
		     && __is_constant_wrapper<typename _Slice::offset_type>)
                  static_assert(std::cmp_greater_equal(
		    _Extent - _Slice::offset_type::value,
		    _Slice::extent_type::value));
		if constexpr (_Extent != dynamic_extent
		     && __is_constant_wrapper<typename _Slice::stride_type>)
                  static_assert(std::cmp_greater(
		    _Extent,
		    (_Slice::extent_type::value - 1) * _Slice::stride_type::value));

		if constexpr (_Extent != dynamic_extent
		     && __is_constant_wrapper<typename _Slice::offset_type>
	             && __is_constant_wrapper<typename _Slice::stride_type>)
                  static_assert(std::cmp_greater(
		    _Extent - _Slice::offset_type::value,
		    (_Slice::extent_type::value - 1) * _Slice::stride_type::value));
		else
		  __glibcxx_assert(std::cmp_greater(
		    __ext.extent(0) - __slice.offset,
		    (_Slice::extent_type::value - 1) * __slice.stride));
	      }
	    else if constexpr (is_same_v<typename _Slice::stride_type,
                                         constant_wrapper<_IndexType(1)>>)
	      {
	        __mdspan::__check_valid_index(__ext, __slice.offset);
		__glibcxx_assert(std::cmp_greater_equal(
		  __ext.extent(0) - __slice.offset,
		  __slice.extent));
              }
	    else if (__slice.extent == 0)
	      __mdspan::__check_valid_index(__ext, __slice.offset);
	    else
	      {
	        __glibcxx_assert(__slice.offset < __ext.extent(0));
		__glibcxx_assert(__slice.extent == 1 || __slice.stride > 0);
		__glibcxx_assert(__slice.extent == 1 || std::cmp_greater(
		  __ext.extent(0) - __slice.offset,
		  (__slice.extent - 1) * __slice.stride));
	      }
	  }
	else if constexpr (!is_same_v<_Slice, full_extent_t>)
          __mdspan::__check_inrange_index(__ext, __slice);
      }

    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
