: 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;
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
{
}
};
+ 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
{
noexcept
{ return __self._M_storage._M_equal(__other); }
};
+
+ template<size_t _PaddingValue>
+ template<typename _Extents>
+ class layout_right_padded<_PaddingValue>::mapping {
+ public:
+ static constexpr size_t padding_value = _PaddingValue;
+ using extents_type = _Extents;
+ using index_type = typename extents_type::index_type;
+ using size_type = typename extents_type::size_type;
+ using rank_type = typename extents_type::rank_type;
+ using layout_type = layout_right_padded<_PaddingValue>;
+
+ private:
+ static constexpr size_t _S_rank = extents_type::rank();
+ using _PaddedStorage = __mdspan::_PaddedStorage<_PaddingValue,
+ _Extents, __mdspan::_RightPaddedLayoutTraits<_S_rank>>;
+ [[no_unique_address]] _PaddedStorage _M_storage;
+
+ consteval friend size_t
+ __mdspan::__get_static_stride<mapping>();
+
+ constexpr index_type
+ _M_extent(size_t __r) const noexcept
+ { return _M_storage._M_extents.extent(__r); }
+
+ constexpr index_type
+ _M_padstride() const noexcept
+ { return _M_storage._M_stride.extent(0); }
+
+ public:
+ constexpr
+ mapping() noexcept
+ { }
+
+ constexpr
+ mapping(const mapping&) noexcept = default;
+
+ constexpr
+ mapping(const extents_type& __exts)
+ : _M_storage(__exts)
+ { }
+
+ template<__mdspan::__valid_index_type<index_type> _OIndexType>
+ constexpr mapping(const extents_type& __exts, _OIndexType __pad)
+ : _M_storage(__exts,
+ __mdspan::__index_type_cast<index_type>(std::move(__pad)))
+ { }
+
+ template<typename _OExtents>
+ requires is_constructible_v<extents_type, _OExtents>
+ constexpr explicit(!is_convertible_v<_OExtents, extents_type>)
+ mapping(const layout_right::mapping<_OExtents>& __other)
+ : _M_storage(__other)
+ { }
+
+ template<typename _OExtents>
+ requires is_constructible_v<_OExtents, extents_type>
+ constexpr explicit(_OExtents::rank() > 0)
+ mapping(const typename layout_stride::mapping<_OExtents>& __other)
+ : _M_storage(__other)
+ { __glibcxx_assert(*this == __other); }
+
+ template<typename _RightPaddedMapping>
+ requires __mdspan::__is_right_padded_mapping<_RightPaddedMapping>
+ && is_constructible_v<extents_type,
+ typename _RightPaddedMapping::extents_type>
+ constexpr explicit(_S_rank > 1 && (padding_value != dynamic_extent
+ || _RightPaddedMapping::padding_value == dynamic_extent))
+ mapping(const _RightPaddedMapping& __other)
+ : _M_storage(layout_right{}, __other)
+ { }
+
+ template<typename _LeftPaddedMapping>
+ requires (__mdspan::__is_left_padded_mapping<_LeftPaddedMapping>
+ || __mdspan::__mapping_of<layout_left, _LeftPaddedMapping>)
+ && (_S_rank <= 1)
+ && is_constructible_v<extents_type,
+ typename _LeftPaddedMapping::extents_type>
+ constexpr explicit(!is_convertible_v<
+ typename _LeftPaddedMapping::extents_type, extents_type>)
+ mapping(const _LeftPaddedMapping& __other) noexcept
+ : _M_storage(layout_left{}, __other)
+ { }
+
+ constexpr mapping& operator=(const mapping&) noexcept = default;
+
+ constexpr const extents_type&
+ extents() const noexcept { return _M_storage._M_extents; }
+
+ constexpr array<index_type, _S_rank>
+ strides() const noexcept
+ {
+ array<index_type, _S_rank> __ret;
+ if constexpr (_S_rank > 0)
+ __ret[_S_rank - 1] = 1;
+ if constexpr (_S_rank > 1)
+ __ret[_S_rank - 2] = _M_padstride();
+ if constexpr (_S_rank > 2)
+ for(size_t __i = _S_rank - 2; __i > 0; --__i)
+ __ret[__i - 1] = __ret[__i] * _M_extent(__i);
+ return __ret;
+ }
+
+ constexpr index_type
+ required_span_size() const noexcept
+ { return _M_storage._M_required_span_size(); }
+
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4314. Missing move in mdspan layout mapping::operator()
+ template<__mdspan::__valid_index_type<index_type>... _Indices>
+ requires (sizeof...(_Indices) == _S_rank)
+ constexpr index_type
+ operator()(_Indices... __indices) const noexcept
+ {
+ return __mdspan::__linear_index_rightpad(
+ extents(), _M_storage._M_stride,
+ static_cast<index_type>(std::move(__indices))...);
+ }
+
+ static constexpr bool
+ is_always_exhaustive() noexcept
+ { return _PaddedStorage::_M_is_always_exhaustive(); }
+
+ constexpr bool
+ is_exhaustive() noexcept
+ { return _M_storage._M_is_exhaustive(); }
+
+ static constexpr bool
+ is_always_unique() noexcept { return true; }
+
+ static constexpr bool
+ is_always_strided() noexcept { return true; }
+
+ static constexpr bool
+ is_unique() noexcept { return true; }
+
+ static constexpr bool
+ is_strided() noexcept { return true; }
+
+ constexpr index_type
+ stride(rank_type __r) const noexcept
+ {
+ __glibcxx_assert(__r < _S_rank);
+ if constexpr (_S_rank <= 1)
+ return 1;
+ else if (__r == _S_rank - 1)
+ return 1;
+ else if (__r == _S_rank - 2)
+ return _M_padstride();
+ else
+ return static_cast<index_type>(
+ static_cast<size_t>(_M_padstride()) *
+ static_cast<size_t>(__mdspan::__fwd_prod(
+ extents(), __r + 1, _S_rank - 1)));
+ }
+
+ template<typename _RightPaddedMapping>
+ requires(__mdspan::__is_right_padded_mapping<_RightPaddedMapping>
+ && _RightPaddedMapping::extents_type::rank() == _S_rank)
+ friend constexpr bool
+ operator==(const mapping& __self, const _RightPaddedMapping& __other)
+ noexcept
+ { return __self._M_storage._M_equal(__other); }
+ };
#endif // __glibcxx_padded_layouts
template<typename _ElementType>
using std::mdspan;
#if __glibcxx_padded_layouts
using std::layout_left_padded;
+ using std::layout_right_padded;
#endif
- // FIXME layout_right_padded, strided_slice, submdspan_mapping_result,
- // full_extent_t, full_extent, submdspan_extents, mdsubspan
+ // FIXME strided_slice, submdspan_mapping_result, full_extent_t, full_extent,
+ // submdspan_extents, mdsubspan
}
#endif
test_all<std::layout_right>();
#if __cplusplus > 202302L
test_padded_all<std::layout_left_padded>();
+ test_padded_all<std::layout_right_padded>();
#endif
from_left_or_right::test_all<std::layout_left, std::layout_right>();
static_assert(test_all<std::layout_stride>());
#if __cplusplus > 202302L
static_assert(test_padded_all<std::layout_left_padded>());
+ static_assert(test_padded_all<std::layout_right_padded>());
#endif
return 0;
}
#if __cplusplus > 202302L
template<typename Layout>
- requires is_left_padded<Layout>
+ requires is_left_padded<Layout> || is_right_padded<Layout>
struct TestStride2D<Layout>
{
static constexpr void
#if __cplusplus > 202302L
template<typename Layout>
- requires is_left_padded<Layout>
+ requires is_left_padded<Layout> || is_right_padded<Layout>
struct TestStride3D<Layout>
{
static constexpr void
test_all<std::layout_stride>();
#if __cplusplus > 202302L
test_padded_all<std::layout_left_padded>();
+ test_padded_all<std::layout_right_padded>();
#endif
test_has_op_eq<std::layout_right, std::layout_left, false>();
test_has_op_eq<std::layout_left, std::layout_stride, true>();
#if __cplusplus > 202302L
test_padded_has_op_eq<std::layout_left_padded>();
+ test_padded_has_op_eq<std::layout_right_padded>();
#endif
test_has_op_eq_peculiar();
test_all<std::layout_left_padded>();
static_assert(test_all<std::layout_left_padded>());
+ test_all<std::layout_right_padded>();
+ static_assert(test_all<std::layout_right_padded>());
+
test_from_pad_all<std::layout_left_padded>();
+ test_from_pad_all<std::layout_right_padded>();
return 0;
}
return true;
}
static_assert(test_from_extens_representable_sta<std::layout_left_padded>()); // { dg-error "from here" }
+static_assert(test_from_extens_representable_sta<std::layout_right_padded>()); // { dg-error "from here" }
template<template<size_t> typename Layout>
constexpr bool
return true;
}
static_assert(test_from_extents_representable_padded_size<std::layout_left_padded>()); // { dg-error "expansion of" }
+static_assert(test_from_extents_representable_padded_size<std::layout_right_padded>()); // { dg-error "expansion of" }
template<template<size_t> typename Layout>
constexpr bool
return true;
}
static_assert(test_from_extents_representable_stride<std::layout_left_padded>()); // { dg-error "expansion of" }
+static_assert(test_from_extents_representable_stride<std::layout_right_padded>()); // { dg-error "expansion of" }
template<template<size_t> typename Layout>
constexpr bool
return true;
}
static_assert(test_from_pad_representable_stride<std::layout_left_padded>()); // { dg-error "expansion of" }
+static_assert(test_from_pad_representable_stride<std::layout_right_padded>()); // { dg-error "expansion of" }
template<template<size_t> typename Layout>
constexpr bool
return true;
}
static_assert(test_from_pad_representable_padded_size<std::layout_left_padded>()); // { dg-error "expansion of" }
+static_assert(test_from_pad_representable_padded_size<std::layout_right_padded>()); // { dg-error "expansion of" }
template<template<size_t> typename Layout>
constexpr bool
return true;
}
static_assert(test_from_left<std::layout_left_padded>()); // { dg-error "required from here" }
+static_assert(test_from_left<std::layout_right_padded>()); // { dg-error "required from here" }
template<template<size_t> typename Layout>
constexpr bool
return true;
}
static_assert(test_from_left_bad_runtime_stride<std::layout_left_padded>()); // { dg-error "expansion of" }
+static_assert(test_from_left_bad_runtime_stride<std::layout_right_padded>()); // { dg-error "expansion of" }
template<template<size_t> typename Layout>
constexpr bool
return true;
}
static_assert(test_from_left_representable_extents<std::layout_left_padded>()); // { dg-error "expansion of" }
+static_assert(test_from_left_representable_extents<std::layout_right_padded>()); // { dg-error "expansion of" }
template<template<size_t> typename Layout, size_t PaddingValue>
constexpr bool
}
static_assert(test_pad_overflow<std::layout_left_padded, 1>()); // { dg-error "expansion of" }
static_assert(test_pad_overflow<std::layout_left_padded, dyn>()); // { dg-error "expansion of" }
+static_assert(test_pad_overflow<std::layout_right_padded, 1>()); // { dg-error "expansion of" }
+static_assert(test_pad_overflow<std::layout_right_padded, dyn>()); // { dg-error "expansion of" }
template<template<size_t> typename Layout, size_t PaddingValue>
constexpr bool
}
static_assert(test_from_pad_negative<std::layout_left_padded, 1>()); // { dg-error "expansion of" }
static_assert(test_from_pad_negative<std::layout_left_padded, dyn>()); // { dg-error "expansion of" }
+static_assert(test_from_pad_negative<std::layout_right_padded, 1>()); // { dg-error "expansion of" }
+static_assert(test_from_pad_negative<std::layout_right_padded, dyn>()); // { dg-error "expansion of" }
template<template<size_t> typename Layout, size_t Pad>
constexpr bool
}
static_assert(test_static_pad_same<std::layout_left_padded, 1>()); // { dg-error "expansion of" }
static_assert(test_static_pad_same<std::layout_left_padded, 3>()); // { dg-error "expansion of" }
+static_assert(test_static_pad_same<std::layout_right_padded, 1>()); // { dg-error "expansion of" }
+static_assert(test_static_pad_same<std::layout_right_padded, 3>()); // { dg-error "expansion of" }
template<template<size_t> typename Layout>
constexpr bool
return true;
}
static_assert(test_from_stride_wrong_stride0<std::layout_left_padded>()); // { dg-error "expansion of" }
+static_assert(test_from_stride_wrong_stride0<std::layout_right_padded>()); // { dg-error "expansion of" }
template<template<size_t> typename Layout>
constexpr bool
return true;
}
static_assert(test_from_stride_wrong_stride1<std::layout_left_padded>()); // { dg-error "expansion of" }
+static_assert(test_from_stride_wrong_stride1<std::layout_right_padded>()); // { dg-error "expansion of" }
template<template<size_t> typename Layout>
constexpr bool
return true;
}
static_assert(test_from_stride_wrong_stride2<std::layout_left_padded>());
+static_assert(test_from_stride_wrong_stride2<std::layout_right_padded>());
template<template<size_t> typename Layout>
constexpr bool
return true;
}
static_assert(test_from_stride_oversized<std::layout_left_padded>()); // { dg-error "expansion of" }
+static_assert(test_from_stride_oversized<std::layout_right_padded>()); // { dg-error "expansion of" }
template<template<size_t> typename Layout>
constexpr bool
return true;
}
static_assert(test_from_samepad_dyn<std::layout_left_padded>()); // { dg-error "expansion of" }
+static_assert(test_from_samepad_dyn<std::layout_right_padded>()); // { dg-error "expansion of" }
template<template<size_t> typename Layout>
constexpr bool
return true;
}
static_assert(test_from_samepad_sta<std::layout_left_padded>()); // { dg-error "expansion of" }
+static_assert(test_from_samepad_sta<std::layout_right_padded>()); // { dg-error "expansion of" }
template<template<size_t> typename Layout>
constexpr bool
return true;
}
static_assert(test_from_samepad_oversized<std::layout_left_padded>()); // { dg-error "expansion of" }
+static_assert(test_from_samepad_oversized<std::layout_right_padded>()); // { dg-error "expansion of" }
template<template<size_t> typename Layout, size_t RunId>
constexpr bool
static_assert(test_to_same_not_exhaustive<std::layout_left_padded, 1>()); // { dg-error "expansion of" }
static_assert(test_to_same_not_exhaustive<std::layout_left_padded, 2>()); // { dg-error "expansion of" }
static_assert(test_to_same_not_exhaustive<std::layout_left_padded, 3>()); // { dg-error "expansion of" }
+static_assert(test_to_same_not_exhaustive<std::layout_right_padded, 0>()); // { dg-error "expansion of" }
+static_assert(test_to_same_not_exhaustive<std::layout_right_padded, 1>()); // { dg-error "expansion of" }
+static_assert(test_to_same_not_exhaustive<std::layout_right_padded, 2>()); // { dg-error "expansion of" }
+static_assert(test_to_same_not_exhaustive<std::layout_right_padded, 3>()); // { dg-error "expansion of" }
template<template<size_t> typename Layout>
constexpr bool
return true;
}
static_assert(test_statically_bad_padding_value1<std::layout_left_padded>()); // { dg-error "required from" }
+static_assert(test_statically_bad_padding_value1<std::layout_right_padded>()); // { dg-error "required from" }
template<template<size_t> typename Layout>
constexpr bool
return true;
}
static_assert(test_statically_bad_padding_value2<std::layout_left_padded>()); // { dg-error "required from" }
+static_assert(test_statically_bad_padding_value2<std::layout_right_padded>()); // { dg-error "required from" }
template<template<size_t> typename Layout>
constexpr bool
return true;
}
static_assert(test_statically_oversized<std::layout_left_padded>()); // { dg-error "from here" }
+static_assert(test_statically_oversized<std::layout_right_padded>()); // { dg-error "from here" }
// { dg-prune-output "padding_value must be representable as index_type" }
// { dg-prune-output "non-constant condition for static assertion" }
= true;
#endif
+template<typename Layout>
+ constexpr static bool is_right_padded = false;
+
+#if __cplusplus > 202302L
+template<size_t PaddingValue>
+ constexpr static bool is_right_padded<std::layout_right_padded<PaddingValue>>
+ = true;
+#endif
+
template<typename Layout>
constexpr bool
- is_padded_layout = is_left_padded<Layout>;
+ is_padded_layout = is_left_padded<Layout> || is_right_padded<Layout>;
#if __cplusplus > 202302L
+template<typename Extents>
+ constexpr auto
+ dynamic_extents_array(const Extents& exts)
+ {
+ std::array<typename Extents::index_type, Extents::rank()> ret;
+ for(size_t i = 0; i < Extents::rank(); ++i)
+ ret[i] = exts.extent(i);
+ return ret;
+ }
enum class PaddingSide
{
- Left
+ Left,
+ Right
};
struct DeducePaddingSide
template<template<size_t> typename Layout>
constexpr static PaddingSide
from_template()
- { return PaddingSide::Left; }
+ {
+ if constexpr (std::same_as<Layout<0>, std::layout_left_padded<0>>)
+ return PaddingSide::Left;
+ else
+ return PaddingSide::Right;
+ }
template<typename Layout>
constexpr static PaddingSide
from_typename()
- { return PaddingSide::Left; }
+ {
+ if constexpr (is_left_padded<Layout>)
+ return PaddingSide::Left;
+ else
+ return PaddingSide::Right;
+ }
};
template<PaddingSide Side>
{ return exts.extent(0); }
};
+template<>
+ struct LayoutTraits<PaddingSide::Right>
+ {
+ using layout_same = std::layout_right;
+ using layout_other = std::layout_left;
+
+ template<typename IndexType, size_t... Extents>
+ constexpr static auto
+ make_extents(const std::extents<IndexType, Extents...>& exts)
+ {
+ constexpr size_t rank = sizeof...(Extents);
+ auto impl = [&]<size_t... I>(std::index_sequence<I...>)
+ {
+ auto dyn_exts = make_array(dynamic_extents_array(exts));
+ return std::extents<IndexType, Extents...[rank - 1 - I]...>(dyn_exts);
+ };
+ return impl(std::make_index_sequence<rank>());
+ }
+
+ template<typename Extents>
+ using extents_type = decltype(make_extents(std::declval<Extents>()));
+
+ template<typename T, size_t N>
+ constexpr static std::array<T, N>
+ make_array(std::array<T, N> a)
+ {
+ std::ranges::reverse(a);
+ return a;
+ }
+
+ template<typename Mapping>
+ constexpr static auto
+ padded_stride(const Mapping& m)
+ {
+ auto rank = Mapping::extents_type::rank();
+ return m.stride(rank - 2);
+ }
+
+ template<typename Extents>
+ constexpr static auto
+ padded_extent(const Extents& exts)
+ {
+ auto rank = Extents::rank();
+ return exts.extent(rank - 1);
+ }
+ };
+
#endif
#endif