mirror of git://gcc.gnu.org/git/gcc.git
libstdc++: Implement std::layout_left_padded [PR110352].
This commit adds a new layout layout_left_padded as standardized in N5014. It adds a purely internal feature testing macro padded_layouts and registers layout_left_padded in the std module. This commit implements LWG4372, because without it's not possible to properly test padded layouts with a dynamic padding value. It also implements LWG4314, for consistency with prior layouts. The implementation uses a _PaddedStorage to deduplicate most of the code shared between left- and right-padded layouts. It's implemented through aggregation rather than inheritence, because of a bug related to inheriting conditionally explicit ctors. The tests are written such that the canonical version works for layout_left_padded. A version for layout_right_padded is derived essentially by reversing the order of the extents. PR libstdc++/110352 libstdc++-v3/ChangeLog: * include/bits/version.def (padded_layouts): Add new internal feature testing macro. * include/bits/version.h: Regenerate. * include/std/mdspan (__fwd_prod): New overload. (layout_left_padded): Add declaration and implementation. (layout_right_padded): Add declaration only. (layout_left::mapping::mapping): New overload for left padded mappings. (__index_type_cast): New function that performs a checked cast to index_type. (__is_left_padded_mapping): New concept. (__is_right_padded_mapping): Ditto. (__standardized_mapping): Recognize left and right padded mappings. (_LeftPaddedIndices): Traits for left padded details. (_PaddedStorage): New class for implementing padded layouts. * src/c++23/std.cc.in (layout_left_padded): Add. * testsuite/23_containers/mdspan/layouts/class_mandate_neg.cc: Refactor and add tests for layout_left_padded. * testsuite/23_containers/mdspan/layouts/ctors.cc: Ditto. * testsuite/23_containers/mdspan/layouts/empty.cc: Ditto. * testsuite/23_containers/mdspan/layouts/mapping.cc: Ditto. * testsuite/23_containers/mdspan/layouts/padded.cc: Ditto. * testsuite/23_containers/mdspan/layouts/padded_neg.cc: Ditto. * testsuite/23_containers/mdspan/layouts/padded_traits.h: New traits. Reviewed-by: Tomasz Kamiński <tkaminsk@redhat.com> Signed-off-by: Luc Grosheintz <luc.grosheintz@gmail.com>
This commit is contained in:
parent
c5bee7e24d
commit
8c71d18f54
|
@ -1062,6 +1062,16 @@ ftms = {
|
|||
cxxmin = 26;
|
||||
extra_cond = "__glibcxx_assume_aligned "
|
||||
"&& __glibcxx_is_sufficiently_aligned";
|
||||
};
|
||||
};
|
||||
|
||||
// Purely internal macro padded layouts.
|
||||
ftms = {
|
||||
name = padded_layouts;
|
||||
no_stdname = true; // internal
|
||||
values = {
|
||||
v = 1;
|
||||
cxxmin = 26;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -1193,6 +1193,15 @@
|
|||
#endif /* !defined(__cpp_lib_aligned_accessor) && defined(__glibcxx_want_aligned_accessor) */
|
||||
#undef __glibcxx_want_aligned_accessor
|
||||
|
||||
#if !defined(__cpp_lib_padded_layouts)
|
||||
# if (__cplusplus > 202302L)
|
||||
# define __glibcxx_padded_layouts 1L
|
||||
# if defined(__glibcxx_want_all) || defined(__glibcxx_want_padded_layouts)
|
||||
# endif
|
||||
# endif
|
||||
#endif /* !defined(__cpp_lib_padded_layouts) && defined(__glibcxx_want_padded_layouts) */
|
||||
#undef __glibcxx_want_padded_layouts
|
||||
|
||||
#if !defined(__cpp_lib_ssize)
|
||||
# if (__cplusplus >= 202002L)
|
||||
# define __glibcxx_ssize 201902L
|
||||
|
|
|
@ -71,6 +71,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
return true;
|
||||
}
|
||||
|
||||
template<typename _IndexType, typename _OIndexType>
|
||||
constexpr _IndexType
|
||||
__index_type_cast(_OIndexType&& __other)
|
||||
{
|
||||
if constexpr (std::is_integral_v<_OIndexType>)
|
||||
{
|
||||
__glibcxx_assert(cmp_less_equal(__other,
|
||||
__gnu_cxx::__int_traits<_IndexType>::__max));
|
||||
if constexpr (std::is_signed_v<_OIndexType>)
|
||||
__glibcxx_assert(__other >= 0);
|
||||
return std::move(__other);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto __ret = static_cast<_IndexType>(std::move(__other));
|
||||
if constexpr (std::is_signed_v<_IndexType>)
|
||||
__glibcxx_assert(__ret >= 0);
|
||||
return __ret;
|
||||
}
|
||||
}
|
||||
|
||||
template<array _Extents>
|
||||
class _StaticExtents
|
||||
{
|
||||
|
@ -261,6 +282,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
__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
|
||||
|
@ -476,6 +505,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
}
|
||||
|
||||
// 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
|
||||
|
@ -567,6 +611,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
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>
|
||||
|
@ -669,10 +729,34 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
is_same_v<typename _Layout::template mapping<typename _Mapping::extents_type>,
|
||||
_Mapping>;
|
||||
|
||||
template<template<size_t> typename _Layout, typename _Mapping>
|
||||
concept __padded_mapping_of = __mapping_of<
|
||||
_Layout<_Mapping::padding_value>, _Mapping>;
|
||||
|
||||
#ifdef __glibcxx_padded_layouts
|
||||
template<typename _Mapping>
|
||||
constexpr bool __is_left_padded_mapping = __padded_mapping_of<
|
||||
layout_left_padded, _Mapping>;
|
||||
|
||||
template<typename _Mapping>
|
||||
constexpr bool __is_right_padded_mapping = __padded_mapping_of<
|
||||
layout_right_padded, _Mapping>;
|
||||
#endif
|
||||
|
||||
template<typename _PaddedMapping>
|
||||
consteval size_t
|
||||
__get_static_stride()
|
||||
{ return _PaddedMapping::_PaddedStorage::_S_static_stride; }
|
||||
|
||||
template<typename _Mapping>
|
||||
concept __standardized_mapping = __mapping_of<layout_left, _Mapping>
|
||||
|| __mapping_of<layout_right, _Mapping>
|
||||
|| __mapping_of<layout_stride, _Mapping>;
|
||||
|| __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
|
||||
|
@ -726,6 +810,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
: 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;
|
||||
|
||||
|
@ -1173,6 +1283,550 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
[[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<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 _PaddingValue, typename _Extents, typename _LayoutTraits>
|
||||
class _PaddedStorage
|
||||
{
|
||||
using _LayoutSame = typename _LayoutTraits::_LayoutSame;
|
||||
|
||||
public:
|
||||
using _IndexType = typename _Extents::index_type;
|
||||
constexpr static size_t _S_rank = _Extents::rank();
|
||||
|
||||
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
||||
// 4372. Weaken Mandates: for dynamic padding values in padded layouts
|
||||
static_assert((_PaddingValue == dynamic_extent)
|
||||
|| (cmp_less_equal(_PaddingValue,
|
||||
__gnu_cxx::__int_traits<_IndexType>::__max)),
|
||||
"padding_value must be representable as index_type");
|
||||
|
||||
static_assert(__representable_size<_Extents, _IndexType>,
|
||||
"The size of extents_type must be representable as index_type");
|
||||
|
||||
static_assert(__valid_static_stride<_Extents, _PaddingValue,
|
||||
_LayoutTraits>,
|
||||
"The padded stride must be representable as size_t");
|
||||
|
||||
static constexpr size_t _S_static_stride = [] consteval
|
||||
{
|
||||
constexpr size_t __rank = _Extents::rank();
|
||||
if constexpr (__rank <= 1)
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
constexpr size_t __ext_idx = _LayoutTraits::_S_ext_idx;
|
||||
constexpr size_t __sta_ext = _Extents::static_extent(__ext_idx);
|
||||
if constexpr (__sta_ext == 0)
|
||||
return size_t(0);
|
||||
else if constexpr (_PaddingValue == dynamic_extent
|
||||
|| __sta_ext == dynamic_extent)
|
||||
return dynamic_extent;
|
||||
else
|
||||
return __least_multiple(_PaddingValue, __sta_ext);
|
||||
}
|
||||
}();
|
||||
|
||||
static_assert(_S_static_stride == dynamic_extent
|
||||
|| cmp_less_equal(_S_static_stride,
|
||||
__gnu_cxx::__int_traits<_IndexType>::__max),
|
||||
"Padded stride must be representable as index_type");
|
||||
|
||||
static_assert(__valid_padded_size<_Extents, _S_static_stride,
|
||||
_LayoutTraits>);
|
||||
|
||||
constexpr
|
||||
_PaddedStorage() noexcept
|
||||
{
|
||||
if constexpr (_S_rank > 1)
|
||||
if constexpr (_S_static_stride == dynamic_extent
|
||||
&& _S_static_padextent() != dynamic_extent)
|
||||
_M_stride = _Stride{_S_static_padextent()};
|
||||
}
|
||||
|
||||
constexpr explicit
|
||||
_PaddedStorage(const _Extents& __exts)
|
||||
: _M_extents(__exts)
|
||||
{
|
||||
if constexpr (!__all_static(__static_extents<_Extents>()))
|
||||
__glibcxx_assert(__is_representable_extents(_M_extents));
|
||||
|
||||
if constexpr (_S_rank > 1)
|
||||
{
|
||||
_IndexType __stride;
|
||||
if constexpr (_PaddingValue == dynamic_extent)
|
||||
__stride = _M_padextent();
|
||||
else if constexpr (_S_static_padextent() != dynamic_extent)
|
||||
return;
|
||||
else
|
||||
{
|
||||
__glibcxx_assert(
|
||||
__is_representable_least_multiple<_IndexType>(
|
||||
_PaddingValue, _M_padextent()));
|
||||
|
||||
__stride = static_cast<_IndexType>(
|
||||
__least_multiple(_PaddingValue, _M_padextent()));
|
||||
|
||||
__glibcxx_assert(__is_representable_extents(
|
||||
_LayoutTraits::_S_make_padded_extent(
|
||||
std::dextents<_IndexType, 1>{__stride},
|
||||
_M_extents)));
|
||||
}
|
||||
_M_stride = _Stride{__stride};
|
||||
}
|
||||
}
|
||||
|
||||
constexpr explicit
|
||||
_PaddedStorage(const _Extents& __exts, _IndexType __pad)
|
||||
: _M_extents(__exts)
|
||||
{
|
||||
if constexpr (_PaddingValue != dynamic_extent)
|
||||
__glibcxx_assert(cmp_equal(_PaddingValue, __pad));
|
||||
if constexpr (_S_rank > 1 && _S_static_stride == dynamic_extent)
|
||||
{
|
||||
__glibcxx_assert(
|
||||
__is_representable_least_multiple<_IndexType>(
|
||||
__pad, _M_padextent()));
|
||||
|
||||
_M_stride = _Stride{static_cast<_IndexType>(
|
||||
__least_multiple(__pad, _M_padextent()))};
|
||||
|
||||
__glibcxx_assert(__is_representable_extents(
|
||||
_LayoutTraits::_S_make_padded_extent(
|
||||
_M_stride, _M_extents)));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename _OExtents>
|
||||
constexpr explicit
|
||||
_PaddedStorage(const typename _LayoutSame::mapping<_OExtents>&
|
||||
__other)
|
||||
: _PaddedStorage(_Extents(__other.extents()))
|
||||
{
|
||||
constexpr size_t __stride_idx = _LayoutTraits::_S_stride_idx;
|
||||
constexpr size_t __ext_idx = _LayoutTraits::_S_ext_idx;
|
||||
if constexpr (_S_rank > 1 && _PaddingValue != dynamic_extent)
|
||||
{
|
||||
static_assert(_S_static_stride == dynamic_extent
|
||||
|| _OExtents::static_extent(__ext_idx) == dynamic_extent
|
||||
|| _S_static_stride == _OExtents::static_extent(__ext_idx),
|
||||
"The padded stride must be compatible with other");
|
||||
|
||||
if constexpr (_S_static_stride == dynamic_extent
|
||||
|| _OExtents::static_extent(__stride_idx) == dynamic_extent)
|
||||
__glibcxx_assert(std::cmp_equal(_M_padstride(),
|
||||
_M_padextent()));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename _OExtents>
|
||||
constexpr explicit
|
||||
_PaddedStorage(const typename layout_stride::mapping<_OExtents>&
|
||||
__other)
|
||||
: _M_extents(__other.extents())
|
||||
{
|
||||
__glibcxx_assert(cmp_less_equal(__other.required_span_size(),
|
||||
__gnu_cxx::__int_traits<_IndexType>
|
||||
::__max));
|
||||
|
||||
constexpr size_t __stride_idx = _LayoutTraits::_S_stride_idx;
|
||||
if constexpr (_S_rank > 1)
|
||||
{
|
||||
if constexpr (_PaddingValue != dynamic_extent)
|
||||
__glibcxx_assert(cmp_equal(__other.stride(__stride_idx),
|
||||
_M_calc_padstride())
|
||||
&& "The padded stride must be compatible with other");
|
||||
if constexpr (_S_static_stride == dynamic_extent)
|
||||
_M_stride = _Stride{__other.stride(__stride_idx)};
|
||||
}
|
||||
}
|
||||
|
||||
template<typename _SamePaddedMapping>
|
||||
constexpr explicit
|
||||
_PaddedStorage(_LayoutTraits::_LayoutSame,
|
||||
const _SamePaddedMapping& __other)
|
||||
: _M_extents(__other.extents())
|
||||
{
|
||||
if constexpr (_S_rank > 1)
|
||||
{
|
||||
static_assert(_PaddingValue == dynamic_extent
|
||||
|| _SamePaddedMapping::padding_value == dynamic_extent
|
||||
|| _PaddingValue == _SamePaddedMapping::padding_value,
|
||||
"If neither PaddingValue is dynamic_extent, then they must "
|
||||
"be equal");
|
||||
|
||||
constexpr size_t __stride_idx = _LayoutTraits::_S_stride_idx;
|
||||
if constexpr (_PaddingValue != dynamic_extent)
|
||||
__glibcxx_assert(cmp_equal(__other.stride(__stride_idx),
|
||||
_M_calc_padstride())
|
||||
&& "The padded stride must be compatible with other");
|
||||
if constexpr (_S_static_stride == dynamic_extent)
|
||||
_M_stride = _Stride{__other.stride(__stride_idx)};
|
||||
}
|
||||
__glibcxx_assert(cmp_less_equal(__other.required_span_size(),
|
||||
__gnu_cxx::__int_traits<_IndexType>::__max));
|
||||
}
|
||||
|
||||
template<typename _OtherPaddedMapping>
|
||||
constexpr explicit
|
||||
_PaddedStorage(_LayoutTraits::_LayoutOther,
|
||||
const _OtherPaddedMapping& __other) noexcept
|
||||
: _M_extents(__other.extents())
|
||||
{
|
||||
__glibcxx_assert(cmp_less_equal(__other.required_span_size(),
|
||||
__gnu_cxx::__int_traits<_IndexType>::__max));
|
||||
}
|
||||
|
||||
static constexpr bool
|
||||
_M_is_always_exhaustive() noexcept
|
||||
{
|
||||
if constexpr (_S_rank <= 1)
|
||||
return true;
|
||||
else
|
||||
return _S_static_padextent() != dynamic_extent
|
||||
&& _S_static_stride != dynamic_extent
|
||||
&& _S_static_padextent() == _S_static_stride;
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
_M_is_exhaustive() const noexcept
|
||||
{
|
||||
if constexpr (_M_is_always_exhaustive())
|
||||
return true;
|
||||
else
|
||||
return cmp_equal(_M_padextent(), _M_padstride());
|
||||
}
|
||||
|
||||
constexpr static size_t
|
||||
_S_static_padextent() noexcept
|
||||
{ return _Extents::static_extent(_LayoutTraits::_S_ext_idx); }
|
||||
|
||||
constexpr _IndexType
|
||||
_M_padextent() const noexcept
|
||||
{ return _M_extents.extent(_LayoutTraits::_S_ext_idx); }
|
||||
|
||||
constexpr _IndexType
|
||||
_M_calc_padstride() const noexcept
|
||||
{
|
||||
if constexpr (_S_static_stride != dynamic_extent)
|
||||
return _S_static_stride;
|
||||
else if constexpr (_PaddingValue != dynamic_extent)
|
||||
return __least_multiple(_PaddingValue, _M_padextent());
|
||||
else
|
||||
return _M_padextent();
|
||||
}
|
||||
|
||||
constexpr _IndexType
|
||||
_M_padstride() const noexcept
|
||||
{ return _M_stride.extent(0); }
|
||||
|
||||
constexpr _IndexType
|
||||
_M_required_span_size() const noexcept
|
||||
{
|
||||
if constexpr (_S_rank == 0)
|
||||
return 1;
|
||||
else if (__mdspan::__empty(_M_extents))
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
size_t __stride = static_cast<size_t>(_M_padstride());
|
||||
size_t __prod_rest = __mdspan::__fwd_prod(_M_extents,
|
||||
_LayoutTraits::_S_unpad_begin, _LayoutTraits::_S_unpad_end);
|
||||
size_t __delta = _M_padstride() - _M_padextent();
|
||||
return static_cast<_IndexType>(__stride * __prod_rest - __delta);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename _SamePaddedMapping>
|
||||
constexpr bool
|
||||
_M_equal(const _SamePaddedMapping& __other) const noexcept
|
||||
{
|
||||
return _M_extents == __other.extents()
|
||||
&& (_S_rank < 2
|
||||
|| cmp_equal(_M_stride.extent(0),
|
||||
__other.stride(_LayoutTraits::_S_stride_idx)));
|
||||
}
|
||||
|
||||
using _Stride = std::extents<_IndexType, _S_static_stride>;
|
||||
[[no_unique_address]] _Stride _M_stride;
|
||||
[[no_unique_address]] _Extents _M_extents;
|
||||
};
|
||||
}
|
||||
|
||||
template<size_t _PaddingValue>
|
||||
template<typename _Extents>
|
||||
class layout_left_padded<_PaddingValue>::mapping
|
||||
{
|
||||
public:
|
||||
static constexpr size_t padding_value = _PaddingValue;
|
||||
|
||||
using extents_type = _Extents;
|
||||
using index_type = typename extents_type::index_type;
|
||||
using size_type = typename extents_type::size_type;
|
||||
using rank_type = typename extents_type::rank_type;
|
||||
using layout_type = layout_left_padded<padding_value>;
|
||||
|
||||
private:
|
||||
static constexpr size_t _S_rank = extents_type::rank();
|
||||
using _PaddedStorage = __mdspan::_PaddedStorage<_PaddingValue,
|
||||
_Extents, __mdspan::_LeftPaddedLayoutTraits<_S_rank>>;
|
||||
[[no_unique_address]] _PaddedStorage _M_storage;
|
||||
|
||||
consteval friend size_t
|
||||
__mdspan::__get_static_stride<mapping>();
|
||||
|
||||
constexpr index_type
|
||||
_M_extent(size_t __r) const noexcept
|
||||
{ return _M_storage._M_extents.extent(__r); }
|
||||
|
||||
constexpr index_type
|
||||
_M_padstride() const noexcept
|
||||
{ return _M_storage._M_stride.extent(0); }
|
||||
|
||||
public:
|
||||
constexpr
|
||||
mapping() noexcept
|
||||
{ }
|
||||
|
||||
constexpr
|
||||
mapping(const mapping&) noexcept = default;
|
||||
|
||||
constexpr
|
||||
mapping(const extents_type& __exts)
|
||||
: _M_storage(__exts)
|
||||
{ }
|
||||
|
||||
template<__mdspan::__valid_index_type<index_type> _OIndexType>
|
||||
constexpr mapping(const extents_type& __exts, _OIndexType __pad)
|
||||
: _M_storage(__exts,
|
||||
__mdspan::__index_type_cast<index_type>(std::move(__pad)))
|
||||
{ }
|
||||
|
||||
template<typename _OExtents>
|
||||
requires is_constructible_v<extents_type, _OExtents>
|
||||
constexpr explicit(!is_convertible_v<_OExtents, extents_type>)
|
||||
mapping(const layout_left::mapping<_OExtents>& __other)
|
||||
: _M_storage(__other)
|
||||
{ }
|
||||
|
||||
template<typename _OExtents>
|
||||
requires is_constructible_v<_OExtents, extents_type>
|
||||
constexpr explicit(_OExtents::rank() > 0)
|
||||
mapping(const typename layout_stride::mapping<_OExtents>& __other)
|
||||
: _M_storage(__other)
|
||||
{ __glibcxx_assert(*this == __other); }
|
||||
|
||||
template<typename _LeftpadMapping>
|
||||
requires __mdspan::__is_left_padded_mapping<_LeftpadMapping>
|
||||
&& is_constructible_v<extents_type,
|
||||
typename _LeftpadMapping::extents_type>
|
||||
constexpr explicit(_S_rank > 1 && (padding_value != dynamic_extent
|
||||
|| _LeftpadMapping::padding_value == dynamic_extent))
|
||||
mapping(const _LeftpadMapping& __other)
|
||||
: _M_storage(layout_left{}, __other)
|
||||
{ }
|
||||
|
||||
template<typename _RightPaddedMapping>
|
||||
requires (__mdspan::__is_right_padded_mapping<_RightPaddedMapping>
|
||||
|| __mdspan::__mapping_of<layout_right, _RightPaddedMapping>)
|
||||
&& (_S_rank <= 1)
|
||||
&& is_constructible_v<extents_type,
|
||||
typename _RightPaddedMapping::extents_type>
|
||||
constexpr explicit(!is_convertible_v<
|
||||
typename _RightPaddedMapping::extents_type, extents_type>)
|
||||
mapping(const _RightPaddedMapping& __other) noexcept
|
||||
: _M_storage(layout_right{}, __other)
|
||||
{ }
|
||||
|
||||
constexpr mapping&
|
||||
operator=(const mapping&) noexcept = default;
|
||||
|
||||
constexpr const extents_type&
|
||||
extents() const noexcept { return _M_storage._M_extents; }
|
||||
|
||||
constexpr array<index_type, _S_rank>
|
||||
strides() const noexcept
|
||||
{
|
||||
array<index_type, _S_rank> __ret;
|
||||
if constexpr (_S_rank > 0)
|
||||
__ret[0] = 1;
|
||||
if constexpr (_S_rank > 1)
|
||||
__ret[1] = _M_padstride();
|
||||
if constexpr (_S_rank > 2)
|
||||
for(size_t __i = 2; __i < _S_rank; ++__i)
|
||||
__ret[__i] = __ret[__i - 1] * _M_extent(__i - 1);
|
||||
return __ret;
|
||||
}
|
||||
|
||||
constexpr index_type
|
||||
required_span_size() const noexcept
|
||||
{ return _M_storage._M_required_span_size(); }
|
||||
|
||||
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
||||
// 4314. Missing move in mdspan layout mapping::operator()
|
||||
template<__mdspan::__valid_index_type<index_type>... _Indices>
|
||||
requires (sizeof...(_Indices) == _S_rank)
|
||||
constexpr index_type
|
||||
operator()(_Indices... __indices) const noexcept
|
||||
{
|
||||
return __mdspan::__linear_index_leftpad(
|
||||
extents(), _M_storage._M_stride,
|
||||
static_cast<index_type>(std::move(__indices))...);
|
||||
}
|
||||
|
||||
static constexpr bool
|
||||
is_always_exhaustive() noexcept
|
||||
{ return _PaddedStorage::_M_is_always_exhaustive(); }
|
||||
|
||||
constexpr bool
|
||||
is_exhaustive() noexcept
|
||||
{ return _M_storage._M_is_exhaustive(); }
|
||||
|
||||
static constexpr bool
|
||||
is_always_unique() noexcept { return true; }
|
||||
|
||||
static constexpr bool
|
||||
is_always_strided() noexcept { return true; }
|
||||
|
||||
static constexpr bool
|
||||
is_unique() noexcept { return true; }
|
||||
|
||||
static constexpr bool
|
||||
is_strided() noexcept { return true; }
|
||||
|
||||
constexpr index_type
|
||||
stride(rank_type __r) const noexcept
|
||||
{
|
||||
__glibcxx_assert(__r < _S_rank);
|
||||
if (__r == 0)
|
||||
return 1;
|
||||
else
|
||||
return static_cast<index_type>(
|
||||
static_cast<size_t>(_M_padstride()) *
|
||||
static_cast<size_t>(__mdspan::__fwd_prod(extents(), 1, __r)));
|
||||
}
|
||||
|
||||
template<typename _LeftpadMapping>
|
||||
requires(__mdspan::__is_left_padded_mapping<_LeftpadMapping>
|
||||
&& _LeftpadMapping::extents_type::rank() == _S_rank)
|
||||
friend constexpr bool
|
||||
operator==(const mapping& __self, const _LeftpadMapping& __other)
|
||||
noexcept
|
||||
{ return __self._M_storage._M_equal(__other); }
|
||||
};
|
||||
#endif // __glibcxx_padded_layouts
|
||||
|
||||
template<typename _ElementType>
|
||||
struct default_accessor
|
||||
{
|
||||
|
@ -1370,7 +2024,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
mdspan(data_handle_type __handle, const mapping_type& __mapping,
|
||||
const accessor_type& __accessor)
|
||||
: _M_accessor(__accessor), _M_mapping(__mapping),
|
||||
_M_handle(std::move(__handle))
|
||||
_M_handle(std::move(__handle))
|
||||
{ }
|
||||
|
||||
template<typename _OElementType, typename _OExtents, typename _OLayout,
|
||||
|
|
|
@ -1869,9 +1869,11 @@ export namespace std
|
|||
using std::aligned_accessor;
|
||||
#endif
|
||||
using std::mdspan;
|
||||
// FIXME layout_left_padded, layout_right_padded, strided_slice,
|
||||
// submdspan_mapping_result, full_extent_t, full_extent, submdspan_extents,
|
||||
// mdsubspan
|
||||
#if __glibcxx_padded_layouts
|
||||
using std::layout_left_padded;
|
||||
#endif
|
||||
// FIXME layout_right_padded, strided_slice, submdspan_mapping_result,
|
||||
// full_extent_t, full_extent, submdspan_extents, mdsubspan
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -46,3 +46,4 @@ auto b6 = B<6, std::layout_stride, std::layout_left>(); // { dg-error "require
|
|||
auto b7 = B<7, std::layout_stride, std::layout_stride>(); // { dg-error "required from" }
|
||||
|
||||
// { dg-prune-output "must be representable as index_type" }
|
||||
// { dg-prune-output "static assertion failed" }
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// { dg-do run { target c++23 } }
|
||||
#include <mdspan>
|
||||
|
||||
#include "padded_traits.h"
|
||||
#include <cstdint>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
|
@ -27,7 +28,6 @@ template<typename Mapping, typename OMapping>
|
|||
VERIFY(std::cmp_equal(m.stride(i), other.stride(i)));
|
||||
}
|
||||
|
||||
|
||||
template<typename To, typename From>
|
||||
constexpr void
|
||||
verify_convertible(From from)
|
||||
|
@ -40,7 +40,10 @@ template<typename To, typename From>
|
|||
constexpr void
|
||||
verify_nothrow_convertible(From from)
|
||||
{
|
||||
static_assert(std::is_nothrow_constructible_v<To, From>);
|
||||
if constexpr (is_padded_layout<typename To::layout_type>)
|
||||
static_assert(std::is_constructible_v<To, From>);
|
||||
else
|
||||
static_assert(std::is_nothrow_constructible_v<To, From>);
|
||||
verify_convertible<To>(from);
|
||||
}
|
||||
|
||||
|
@ -57,7 +60,10 @@ template<typename To, typename From>
|
|||
constexpr void
|
||||
verify_nothrow_constructible(From from)
|
||||
{
|
||||
static_assert(std::is_nothrow_constructible_v<To, From>);
|
||||
if constexpr (is_padded_layout<typename To::layout_type>)
|
||||
static_assert(std::is_constructible_v<To, From>);
|
||||
else
|
||||
static_assert(std::is_nothrow_constructible_v<To, From>);
|
||||
verify_constructible<To>(from);
|
||||
}
|
||||
|
||||
|
@ -196,6 +202,16 @@ namespace from_extents
|
|||
// ctor: mapping(mapping<OExtents>)
|
||||
namespace from_same_layout
|
||||
{
|
||||
template<typename Layout, typename Extents, typename OExtents>
|
||||
constexpr void
|
||||
verify_convertible(OExtents exts)
|
||||
{
|
||||
using Mapping = typename Layout::mapping<Extents>;
|
||||
using OMapping = typename Layout::mapping<OExtents>;
|
||||
|
||||
::verify_convertible<Mapping>(OMapping(exts));
|
||||
}
|
||||
|
||||
template<typename Layout, typename Extents, typename OExtents>
|
||||
constexpr void
|
||||
verify_nothrow_convertible(OExtents exts)
|
||||
|
@ -223,8 +239,12 @@ namespace from_same_layout
|
|||
verify_nothrow_convertible<Layout, std::extents<unsigned int>>(
|
||||
std::extents<int>{});
|
||||
|
||||
verify_nothrow_constructible<Layout, std::extents<int>>(
|
||||
std::extents<unsigned int>{});
|
||||
if constexpr (!is_padded_layout<Layout>)
|
||||
verify_nothrow_constructible<Layout, std::extents<int>>(
|
||||
std::extents<unsigned int>{});
|
||||
else
|
||||
verify_convertible<Layout, std::extents<int>>(
|
||||
std::extents<unsigned int>{});
|
||||
|
||||
assert_not_constructible<
|
||||
typename Layout::mapping<std::extents<int>>,
|
||||
|
@ -234,8 +254,12 @@ namespace from_same_layout
|
|||
typename Layout::mapping<std::extents<int, 1>>,
|
||||
typename Layout::mapping<std::extents<int>>>();
|
||||
|
||||
verify_nothrow_constructible<Layout, std::extents<int, 1>>(
|
||||
std::extents<int, dyn>{1});
|
||||
if constexpr (!is_padded_layout<Layout>)
|
||||
verify_nothrow_constructible<Layout, std::extents<int, 1>>(
|
||||
std::extents<int, dyn>{1});
|
||||
else
|
||||
verify_convertible<Layout, std::extents<int, 1>>(
|
||||
std::extents<int, dyn>{1});
|
||||
|
||||
verify_nothrow_convertible<Layout, std::extents<int, dyn>>(
|
||||
std::extents<int, 1>{});
|
||||
|
@ -247,8 +271,12 @@ namespace from_same_layout
|
|||
verify_nothrow_constructible<Layout, std::extents<int, 1, 2>>(
|
||||
std::extents<int, dyn, 2>{1});
|
||||
|
||||
verify_nothrow_convertible<Layout, std::extents<int, dyn, 2>>(
|
||||
std::extents<int, 1, 2>{});
|
||||
if constexpr (!is_padded_layout<Layout>)
|
||||
verify_nothrow_convertible<Layout, std::extents<int, dyn, 2>>(
|
||||
std::extents<int, 1, 2>{});
|
||||
else
|
||||
verify_nothrow_constructible<Layout, std::extents<int, dyn, 2>>(
|
||||
std::extents<int, 1, 2>{});
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -424,11 +452,24 @@ template<typename Layout>
|
|||
from_stride::test_all<Layout>();
|
||||
}
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr void
|
||||
test_padded_all()
|
||||
{
|
||||
test_all<Layout<0>>();
|
||||
test_all<Layout<1>>();
|
||||
test_all<Layout<2>>();
|
||||
test_all<Layout<dyn>>();
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
test_all<std::layout_left>();
|
||||
test_all<std::layout_right>();
|
||||
#if __cplusplus > 202302L
|
||||
test_padded_all<std::layout_left_padded>();
|
||||
#endif
|
||||
|
||||
from_left_or_right::test_all<std::layout_left, std::layout_right>();
|
||||
from_left_or_right::test_all<std::layout_right, std::layout_left>();
|
||||
|
|
|
@ -35,7 +35,8 @@ template<typename Layout, typename Int>
|
|||
{
|
||||
constexpr Int n1 = std::numeric_limits<Int>::max();
|
||||
constexpr size_t n2 = std::dynamic_extent - 1;
|
||||
constexpr size_t n = std::cmp_less(n1, n2) ? size_t(n1) : n2;
|
||||
// Allow some room for padding.
|
||||
constexpr size_t n = (std::cmp_less(n1, n2) ? size_t(n1) : n2) - 4;
|
||||
|
||||
verify_all(typename Layout::mapping<std::extents<Int, n, n, 0, n, n>>{});
|
||||
verify_all(typename Layout::mapping<std::extents<Int, 0, n, n, n>>{});
|
||||
|
@ -73,7 +74,8 @@ template<typename Layout, typename Int>
|
|||
{
|
||||
constexpr Int n1 = std::numeric_limits<Int>::max();
|
||||
constexpr size_t n2 = std::dynamic_extent - 1;
|
||||
constexpr Int n = std::cmp_less(n1, n2) ? n1 : Int(n2);
|
||||
// Allow some room for padding.
|
||||
constexpr Int n = (std::cmp_less(n1, n2) ? n1 : Int(n2)) - 4;
|
||||
|
||||
verify_all(make_mapping<Layout>(
|
||||
std::extents<Int, dyn, dyn, 0, dyn, dyn>{n, n, n, n}));
|
||||
|
@ -121,11 +123,25 @@ template<typename Layout>
|
|||
return true;
|
||||
}
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr bool
|
||||
test_padded_all()
|
||||
{
|
||||
static_assert(test_all<Layout<0>>());
|
||||
static_assert(test_all<Layout<1>>());
|
||||
static_assert(test_all<Layout<2>>());
|
||||
static_assert(test_all<Layout<dyn>>());
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
static_assert(test_all<std::layout_left>());
|
||||
static_assert(test_all<std::layout_right>());
|
||||
static_assert(test_all<std::layout_stride>());
|
||||
#if __cplusplus > 202302L
|
||||
static_assert(test_padded_all<std::layout_left_padded>());
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <mdspan>
|
||||
|
||||
#include "../int_like.h"
|
||||
#include "padded_traits.h"
|
||||
#include <cstdint>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
|
@ -370,6 +371,37 @@ template<>
|
|||
}
|
||||
};
|
||||
|
||||
#if __cplusplus > 202302L
|
||||
template<typename Layout>
|
||||
requires is_left_padded<Layout>
|
||||
struct TestStride2D<Layout>
|
||||
{
|
||||
static constexpr void
|
||||
run()
|
||||
{
|
||||
using Traits = LayoutTraits<DeducePaddingSide::from_typename<Layout>()>;
|
||||
using Extents = typename Traits::extents_type<std::extents<int, 3, 5>>;
|
||||
using Mapping = typename Layout::mapping<Extents>;
|
||||
constexpr size_t padding_value = Mapping::padding_value;
|
||||
|
||||
Mapping m;
|
||||
size_t effective_pad = (padding_value == 0 || padding_value == dyn)
|
||||
? size_t(1) : padding_value;
|
||||
|
||||
constexpr auto i0 = is_left_padded<Layout> ? 0 : 1;
|
||||
VERIFY(m.stride(i0) == 1);
|
||||
|
||||
// The next multiple of padding_value, that's greater or equal
|
||||
// to exts.extent(0) is the unique value in the range:
|
||||
// [exts.extent(0), exts.extent(0) + padding_value)
|
||||
// that is divisible by padding_value.
|
||||
auto stride = Traits::padded_stride(m);
|
||||
VERIFY((stride % effective_pad) == 0);
|
||||
VERIFY(3 <= stride && std::cmp_less(stride, 3 + effective_pad));
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template<typename Layout>
|
||||
constexpr void
|
||||
test_stride_2d()
|
||||
|
@ -423,6 +455,40 @@ template<>
|
|||
}
|
||||
};
|
||||
|
||||
#if __cplusplus > 202302L
|
||||
template<typename Layout>
|
||||
requires is_left_padded<Layout>
|
||||
struct TestStride3D<Layout>
|
||||
{
|
||||
static constexpr void
|
||||
run()
|
||||
{
|
||||
using Traits = LayoutTraits<DeducePaddingSide::from_typename<Layout>()>;
|
||||
using Extents = typename Traits::extents_type<std::extents<int, 3, 5, 7>>;
|
||||
using Mapping = typename Layout::mapping<Extents>;
|
||||
constexpr size_t padding_value = Mapping::padding_value;
|
||||
|
||||
Mapping m;
|
||||
size_t effective_pad = (padding_value == 0 || padding_value == dyn)
|
||||
? size_t(1) : padding_value;
|
||||
|
||||
constexpr auto i0 = is_left_padded<Layout> ? 0 : 2;
|
||||
VERIFY(m.stride(i0) == 1);
|
||||
|
||||
// The next multiple of padding_value, that's greater or equal
|
||||
// to exts.extent(0) is the unique value in the range:
|
||||
// [exts.extent(0), exts.extent(0) + padding_value)
|
||||
// that is divisible by padding_value.
|
||||
auto stride = Traits::padded_stride(m);
|
||||
VERIFY((stride % effective_pad) == 0);
|
||||
VERIFY(3 <= stride && std::cmp_less(stride, 3 + effective_pad));
|
||||
|
||||
constexpr auto i2 = is_left_padded<Layout> ? 2 : 0;
|
||||
VERIFY(stride * 5 == m.stride(i2));
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template<typename Layout>
|
||||
constexpr void
|
||||
test_stride_3d()
|
||||
|
@ -451,7 +517,8 @@ template<typename Layout>
|
|||
test_has_stride_0d()
|
||||
{
|
||||
using Mapping = typename Layout::mapping<std::extents<int>>;
|
||||
constexpr bool expected = std::is_same_v<Layout, std::layout_stride>;
|
||||
constexpr bool expected = !(std::is_same_v<Layout, std::layout_left>
|
||||
|| std::is_same_v<Layout, std::layout_right>);
|
||||
static_assert(has_stride<Mapping> == expected);
|
||||
}
|
||||
|
||||
|
@ -595,16 +662,54 @@ template<typename Layout>
|
|||
test_has_op_eq<Layout, Layout, true>();
|
||||
}
|
||||
|
||||
#if __cplusplus > 202302L
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr bool
|
||||
test_padded_all()
|
||||
{
|
||||
test_all<Layout<0>>();
|
||||
test_all<Layout<1>>();
|
||||
test_all<Layout<2>>();
|
||||
test_all<Layout<5>>();
|
||||
test_all<Layout<dyn>>();
|
||||
return true;
|
||||
}
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr bool
|
||||
test_padded_has_op_eq()
|
||||
{
|
||||
using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
|
||||
test_has_op_eq<typename Traits::layout_same, Layout<0>, false>();
|
||||
test_has_op_eq<typename Traits::layout_same, Layout<6>, false>();
|
||||
test_has_op_eq<typename Traits::layout_same, Layout<dyn>, false>();
|
||||
// The next one looks strange, because it's neither. Somehow, the
|
||||
// conversion rules seem to be playing a critical role again.
|
||||
// test_has_op_eq<typename Traits::layout_other, Layout<0>, false>();
|
||||
|
||||
test_has_op_eq<Layout<2>, Layout<6>, true>();
|
||||
test_has_op_eq<Layout<2>, Layout<dyn>, true>();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
test_all<std::layout_left>();
|
||||
test_all<std::layout_right>();
|
||||
test_all<std::layout_stride>();
|
||||
#if __cplusplus > 202302L
|
||||
test_padded_all<std::layout_left_padded>();
|
||||
#endif
|
||||
|
||||
test_has_op_eq<std::layout_right, std::layout_left, false>();
|
||||
test_has_op_eq<std::layout_right, std::layout_stride, true>();
|
||||
test_has_op_eq<std::layout_left, std::layout_stride, true>();
|
||||
#if __cplusplus > 202302L
|
||||
test_padded_has_op_eq<std::layout_left_padded>();
|
||||
#endif
|
||||
|
||||
test_has_op_eq_peculiar();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,673 @@
|
|||
// { dg-do run { target c++26 } }
|
||||
#include <mdspan>
|
||||
|
||||
#include <cstdint>
|
||||
#include "../int_like.h"
|
||||
#include "padded_traits.h"
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
constexpr size_t dyn = std::dynamic_extent;
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr bool
|
||||
test_representable_padded_size()
|
||||
{
|
||||
using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
|
||||
{
|
||||
using E = typename Traits::extents_type<std::extents<uint8_t, 64, 2>>;
|
||||
[[maybe_unused]] typename Layout<1>::mapping<E> m1;
|
||||
}
|
||||
|
||||
{
|
||||
using E = typename Traits::extents_type<std::extents<uint8_t, 0, 2>>;
|
||||
[[maybe_unused]] typename Layout<0>::mapping<E> m1;
|
||||
[[maybe_unused]] typename Layout<1>::mapping<E> m2;
|
||||
[[maybe_unused]] typename Layout<128>::mapping<E> m3;
|
||||
[[maybe_unused]] typename Layout<255>::mapping<E> m4;
|
||||
}
|
||||
|
||||
{
|
||||
using E = typename Traits::extents_type<std::extents<uint8_t, 0, 2>>;
|
||||
[[maybe_unused]] typename Layout<dyn>::mapping<E> m1(E{}, 0);
|
||||
[[maybe_unused]] typename Layout<dyn>::mapping<E> m2(E{}, 1);
|
||||
[[maybe_unused]] typename Layout<dyn>::mapping<E> m3(E{}, 128);
|
||||
[[maybe_unused]] typename Layout<dyn>::mapping<E> m4(E{}, 255);
|
||||
}
|
||||
|
||||
{
|
||||
using E = typename Traits::extents_type<std::extents<uint8_t, dyn, 2>>;
|
||||
[[maybe_unused]] typename Layout<0>::mapping<E> m1;
|
||||
[[maybe_unused]] typename Layout<1>::mapping<E> m2;
|
||||
[[maybe_unused]] typename Layout<128>::mapping<E> m3;
|
||||
[[maybe_unused]] typename Layout<255>::mapping<E> m4;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename Layout, typename CanonicalExtents>
|
||||
constexpr void
|
||||
test_default_ctor_single(auto canonical_strides)
|
||||
{
|
||||
using Traits = LayoutTraits<DeducePaddingSide::from_typename<Layout>()>;
|
||||
using E = typename Traits::extents_type<CanonicalExtents>;
|
||||
auto strides = Traits::make_array(canonical_strides);
|
||||
|
||||
typename Layout::template mapping<E> msta;
|
||||
VERIFY(msta.stride(0) == strides[0]);
|
||||
VERIFY(msta.stride(1) == strides[1]);
|
||||
}
|
||||
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr bool
|
||||
test_default_ctor()
|
||||
{
|
||||
using E1 = std::extents<size_t, 3, 5>;
|
||||
test_default_ctor_single<Layout<2>, E1>(std::array<size_t, 2>{1, 4});
|
||||
test_default_ctor_single<Layout<dyn>, E1>(std::array<size_t, 2>{1, 3});
|
||||
|
||||
using E2 = std::extents<size_t, dyn, 5>;
|
||||
test_default_ctor_single<Layout<2>, E2>(std::array<size_t, 2>{1, 0});
|
||||
test_default_ctor_single<Layout<dyn>, E2>(std::array<size_t, 2>{1, 0});
|
||||
return true;
|
||||
}
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr bool
|
||||
test_from_exts()
|
||||
{
|
||||
using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
|
||||
auto exts = Traits::make_extents(std::dextents<size_t, 2>{3, 5});
|
||||
|
||||
typename Layout<0>::mapping m0_sta(exts);
|
||||
VERIFY(Traits::padded_stride(m0_sta) == Traits::padded_extent(exts));
|
||||
|
||||
typename Layout<1>::mapping m1_sta(exts);
|
||||
VERIFY(Traits::padded_stride(m1_sta) == Traits::padded_extent(exts));
|
||||
|
||||
typename Layout<2>::mapping m2_sta(exts);
|
||||
VERIFY(Traits::padded_stride(m2_sta) == 4);
|
||||
|
||||
typename Layout<dyn>::mapping mdyn(exts);
|
||||
VERIFY(Traits::padded_stride(mdyn) == Traits::padded_extent(exts));
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename Layout, typename CustomPadType>
|
||||
constexpr bool
|
||||
test_from_pad_single()
|
||||
{
|
||||
using Traits = LayoutTraits<DeducePaddingSide::from_typename<Layout>()>;
|
||||
auto pad = 3;
|
||||
auto exts = Traits::make_extents(std::dextents<size_t, 3>{pad + 1, 5, 7});
|
||||
typename Layout::mapping m(exts, CustomPadType{pad});
|
||||
VERIFY(std::cmp_equal(Traits::padded_stride(m), 2*pad));
|
||||
VERIFY(m.extents() == exts);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename Layout>
|
||||
constexpr void
|
||||
test_from_pad()
|
||||
{
|
||||
test_from_pad_single<Layout, int>();
|
||||
static_assert(test_from_pad_single<Layout, int>());
|
||||
|
||||
test_from_pad_single<Layout, IntLike>();
|
||||
test_from_pad_single<Layout, MutatingInt>();
|
||||
test_from_pad_single<Layout, RValueInt>();
|
||||
|
||||
using Extents = std::dims<3>;
|
||||
using Mapping = Layout::template mapping<Extents>;
|
||||
static_assert(!std::is_constructible_v<Mapping, Extents, ThrowingInt>);
|
||||
static_assert(!std::is_constructible_v<Mapping, Extents, NotIntLike>);
|
||||
}
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr void
|
||||
test_from_pad_all()
|
||||
{
|
||||
test_from_pad<Layout<3>>();
|
||||
test_from_pad<Layout<dyn>>();
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
is_same_mapping(const auto& lhs, const auto& rhs)
|
||||
{
|
||||
if (lhs.extents().rank() != rhs.extents().rank())
|
||||
return false;
|
||||
|
||||
if (lhs.extents() != rhs.extents())
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < lhs.extents().rank(); ++i)
|
||||
if (lhs.stride(i) != rhs.stride(i))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
enum class ConversionRule
|
||||
{
|
||||
Never,
|
||||
Always,
|
||||
Regular
|
||||
};
|
||||
|
||||
template<typename To, typename From>
|
||||
consteval bool
|
||||
should_convert(auto rule)
|
||||
{
|
||||
if constexpr (rule == ConversionRule::Never)
|
||||
return false;
|
||||
if constexpr (rule == ConversionRule::Always)
|
||||
return true;
|
||||
else
|
||||
return std::is_convertible_v<typename From::extents_type,
|
||||
typename To::extents_type>;
|
||||
}
|
||||
|
||||
template<typename To, typename From>
|
||||
constexpr void
|
||||
check_convertible(const From& m, auto conversion_rule)
|
||||
{
|
||||
VERIFY(is_same_mapping(m, To(m)));
|
||||
constexpr bool expected = should_convert<To, From>(conversion_rule);
|
||||
static_assert(std::is_convertible_v<From, To> == expected);
|
||||
}
|
||||
|
||||
template<typename LayoutTo, typename Esta, typename Edyn, typename Ewrong>
|
||||
constexpr void
|
||||
check_convertible_variants(auto msta, auto conversion_rule)
|
||||
{
|
||||
using LayoutFrom = decltype(msta)::layout_type;
|
||||
constexpr auto cregular = std::cw<ConversionRule::Regular>;
|
||||
|
||||
// There's a twist when both mappings are left-padded. There's two distinct
|
||||
// ctors: a defaulted copy ctor and a constrained template that enables
|
||||
// construction from left-padded mappings even if their layout_type is
|
||||
// different. The two ctors have different rules regarding conversion.
|
||||
|
||||
if constexpr (!std::same_as<LayoutTo, LayoutFrom>)
|
||||
check_convertible<typename LayoutTo::mapping<Esta>>(msta, conversion_rule);
|
||||
else
|
||||
check_convertible<typename LayoutTo::mapping<Esta>>(msta, cregular);
|
||||
|
||||
check_convertible<typename LayoutTo::mapping<Edyn>>(msta, conversion_rule);
|
||||
|
||||
auto mdyn = typename LayoutFrom::mapping<Edyn>(msta);
|
||||
check_convertible<typename LayoutTo::mapping<Esta>>(mdyn, conversion_rule);
|
||||
if constexpr (!std::same_as<LayoutTo, LayoutFrom>)
|
||||
check_convertible<typename LayoutTo::mapping<Edyn>>(mdyn, conversion_rule);
|
||||
else
|
||||
check_convertible<typename LayoutTo::mapping<Edyn>>(mdyn, cregular);
|
||||
|
||||
static_assert(!std::is_constructible_v<
|
||||
typename LayoutTo::mapping<Esta>, typename LayoutFrom::mapping<Ewrong>>);
|
||||
};
|
||||
|
||||
template<typename Layout>
|
||||
constexpr void
|
||||
test_from_same_1d()
|
||||
{
|
||||
using E1 = std::extents<int, 6>;
|
||||
using E2 = std::extents<int, dyn>;
|
||||
using E3 = std::extents<int, 5>;
|
||||
constexpr auto cr = std::cw<ConversionRule::Regular>;
|
||||
|
||||
using Traits = LayoutTraits<DeducePaddingSide::from_typename<Layout>()>;
|
||||
auto msta = typename Traits::layout_same::mapping(E1{});
|
||||
check_convertible_variants<Layout, E1, E2, E3>(msta, cr);
|
||||
}
|
||||
|
||||
template<typename Layout>
|
||||
constexpr void
|
||||
test_from_same_2d()
|
||||
{
|
||||
using Traits = LayoutTraits<DeducePaddingSide::from_typename<Layout>()>;
|
||||
using E1 = typename Traits::extents_type<std::extents<int, 6, 5>>;
|
||||
using E2 = typename Traits::extents_type<std::extents<int, dyn, 5>>;
|
||||
using E3 = typename Traits::extents_type<std::extents<int, 6, 6>>;
|
||||
constexpr auto cr = std::cw<ConversionRule::Regular>;
|
||||
|
||||
auto msta = typename Traits::layout_same::mapping(E1{});
|
||||
check_convertible_variants<Layout, E1, E2, E3>(msta, cr);
|
||||
}
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr bool
|
||||
test_from_same()
|
||||
{
|
||||
auto check = []<typename PaddedLayout>(PaddedLayout)
|
||||
{
|
||||
test_from_same_1d<PaddedLayout>();
|
||||
test_from_same_2d<PaddedLayout>();
|
||||
};
|
||||
|
||||
check(Layout<0>{});
|
||||
check(Layout<1>{});
|
||||
check(Layout<2>{});
|
||||
check(Layout<6>{});
|
||||
check(Layout<dyn>{});
|
||||
|
||||
// rank == 1 is more permissive:
|
||||
test_from_same_1d<Layout<5>>();
|
||||
return true;
|
||||
}
|
||||
|
||||
template<template<size_t> typename Layout, typename E1_, typename E2_,
|
||||
typename E3_>
|
||||
constexpr bool
|
||||
test_from_stride_nd(auto strides_)
|
||||
{
|
||||
using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
|
||||
using E1 = typename Traits::extents_type<E1_>;
|
||||
using E2 = typename Traits::extents_type<E2_>;
|
||||
using E3 = typename Traits::extents_type<E3_>;
|
||||
auto strides = Traits::make_array(strides_);
|
||||
|
||||
auto check = [&strides]<typename PaddedLayout>(PaddedLayout)
|
||||
{
|
||||
auto exts = E1{};
|
||||
constexpr auto cr = std::cw<ConversionRule::Never>;
|
||||
|
||||
auto m = std::layout_stride::mapping(exts, strides);
|
||||
check_convertible_variants<PaddedLayout, E1, E2, E3>(m, cr);
|
||||
};
|
||||
|
||||
check(Layout<0>{});
|
||||
check(Layout<1>{});
|
||||
check(Layout<2>{});
|
||||
check(Layout<6>{});
|
||||
check(Layout<dyn>{});
|
||||
return true;
|
||||
}
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr bool
|
||||
test_from_stride_2d()
|
||||
{
|
||||
using E1 = std::extents<size_t, 6, 5>;
|
||||
using E2 = std::dims<2>;
|
||||
using E3 = std::extents<size_t, 6, 6>;
|
||||
|
||||
auto strides = std::array<int, 2>{1, 6};
|
||||
test_from_stride_nd<Layout, E1, E2, E3>(strides);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr bool
|
||||
test_from_stride_3d()
|
||||
{
|
||||
using E1 = std::extents<size_t, 6, 5, 7>;
|
||||
using E2 = std::dims<3>;
|
||||
using E3 = std::extents<size_t, 6, 6, 7>;
|
||||
|
||||
auto strides = std::array<int, 3>{1, 6, 6*5};
|
||||
test_from_stride_nd<Layout, E1, E2, E3>(strides);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr bool
|
||||
test_from_stride()
|
||||
{
|
||||
test_from_stride_2d<Layout>();
|
||||
test_from_stride_3d<Layout>();
|
||||
return true;
|
||||
}
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr void
|
||||
test_from_samepad_0d()
|
||||
{
|
||||
using E1 = std::extents<uint16_t>;
|
||||
using E2 = std::extents<uint8_t>;
|
||||
using E3 = std::extents<uint8_t, 1>;
|
||||
|
||||
typename Layout<6>::mapping<E1> msta{E1{}};
|
||||
|
||||
auto check = []<typename To>(To, auto m)
|
||||
{
|
||||
constexpr auto cr = std::cw<ConversionRule::Always>;
|
||||
check_convertible_variants<To, E1, E2, E3>(m, cr);
|
||||
};
|
||||
|
||||
check(Layout<6>{}, msta);
|
||||
check(Layout<dyn>{}, msta);
|
||||
}
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr void
|
||||
test_from_samepad_1d()
|
||||
{
|
||||
using E1 = std::extents<int, 6>;
|
||||
using E2 = std::extents<int, dyn>;
|
||||
using E3 = std::extents<int, 6, 6>;
|
||||
|
||||
typename Layout<6>::mapping<E1> msta{E1{}};
|
||||
typename Layout<dyn>::mapping<E1> mdyn{E1{}};
|
||||
|
||||
auto check = []<typename To>(To, auto m)
|
||||
{
|
||||
constexpr auto cr = std::cw<ConversionRule::Always>;
|
||||
check_convertible_variants<To, E1, E2, E3>(m, cr);
|
||||
};
|
||||
|
||||
// Remember, for rank <= 1 the padding_value is irrelevant.
|
||||
check(Layout<6>{}, msta);
|
||||
check(Layout<6>{}, mdyn);
|
||||
check(Layout<dyn>{}, msta);
|
||||
check(Layout<dyn>{}, mdyn);
|
||||
}
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr void
|
||||
test_from_samepad_2d()
|
||||
{
|
||||
using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
|
||||
using E1 = typename Traits::extents_type<std::extents<int, 6, 5>>;
|
||||
using E2 = typename Traits::extents_type<std::extents<int, dyn, 5>>;
|
||||
using E3 = typename Traits::extents_type<std::extents<int, 6, 6>>;
|
||||
|
||||
typename Layout<6>::mapping<E1> msta{E1{}};
|
||||
typename Layout<dyn>::mapping<E1> mdyn{E1{}};
|
||||
|
||||
constexpr auto calways = std::cw<ConversionRule::Always>;
|
||||
constexpr auto cnever = std::cw<ConversionRule::Never>;
|
||||
|
||||
auto check = []<typename To>(To, auto m, auto cr)
|
||||
{ check_convertible_variants<To, E1, E2, E3>(m, cr); };
|
||||
|
||||
check(Layout<6>{}, msta, cnever);
|
||||
check(Layout<6>{}, mdyn, cnever);
|
||||
check(Layout<dyn>{}, msta, calways);
|
||||
check(Layout<dyn>{}, mdyn, cnever);
|
||||
}
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr bool
|
||||
test_from_samepad()
|
||||
{
|
||||
test_from_samepad_0d<Layout>();
|
||||
test_from_samepad_1d<Layout>();
|
||||
test_from_samepad_2d<Layout>();
|
||||
return true;
|
||||
}
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr bool
|
||||
test_from_other()
|
||||
{
|
||||
using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
|
||||
using E1 = std::extents<size_t, 3>;
|
||||
using E2 = std::dims<1>;
|
||||
using E3 = std::extents<size_t, 5>;
|
||||
|
||||
auto check = []<typename PaddedLayout>(PaddedLayout)
|
||||
{
|
||||
constexpr auto cr = std::cw<ConversionRule::Regular>;
|
||||
|
||||
using layout_other = typename Traits::layout_other;
|
||||
auto msta = typename layout_other::mapping(E1{});
|
||||
check_convertible_variants<PaddedLayout, E1, E2, E3>(msta, cr);
|
||||
};
|
||||
|
||||
|
||||
// Remember, the padding_value has no effect for rank <= 1.
|
||||
check(Layout<0>{});
|
||||
check(Layout<1>{});
|
||||
check(Layout<2>{});
|
||||
check(Layout<5>{});
|
||||
check(Layout<6>{});
|
||||
check(Layout<dyn>{});
|
||||
return true;
|
||||
}
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr bool
|
||||
test_to_same()
|
||||
{
|
||||
using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
|
||||
using E1 = typename Traits::extents_type<std::extents<int, 6, 5>>;
|
||||
using E2 = typename Traits::extents_type<std::extents<int, dyn, 5>>;
|
||||
using E3 = typename Traits::extents_type<std::extents<int, 6, 6>>;
|
||||
|
||||
auto check = [](auto msta)
|
||||
{
|
||||
constexpr auto cr = std::cw<ConversionRule::Regular>;
|
||||
using LayoutSame = typename Traits::layout_same;
|
||||
check_convertible_variants<LayoutSame, E1, E2, E3>(msta, cr);
|
||||
};
|
||||
|
||||
check(typename Layout<0>::mapping(E1{}));
|
||||
check(typename Layout<2>::mapping(E1{}));
|
||||
check(typename Layout<6>::mapping(E1{}));
|
||||
check(typename Layout<dyn>::mapping(E1{}, 0));
|
||||
check(typename Layout<dyn>::mapping(E1{}, 2));
|
||||
check(typename Layout<dyn>::mapping(E1{}, 6));
|
||||
return true;
|
||||
}
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr bool
|
||||
test_never_to_other()
|
||||
{
|
||||
using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
|
||||
using E1 = std::extents<size_t, 3>;
|
||||
using E2 = std::dims<1>;
|
||||
|
||||
auto check = []<typename PaddedLayout>(PaddedLayout, auto exts)
|
||||
{
|
||||
using LayoutOther = typename Traits::layout_other;
|
||||
auto mr = typename LayoutOther::mapping(exts);
|
||||
auto mlp = typename PaddedLayout::mapping<decltype(exts)>{mr};
|
||||
static_assert(!std::is_constructible_v<decltype(mr), decltype(mlp)>);
|
||||
};
|
||||
|
||||
check(Layout<2>{}, E1{});
|
||||
check(Layout<2>{}, E2{E1{}});
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename Layout>
|
||||
constexpr void
|
||||
test_strides()
|
||||
{
|
||||
auto check = [](auto exts)
|
||||
{
|
||||
auto m = typename Layout::mapping(exts);
|
||||
using IndexType = typename decltype(m)::index_type;
|
||||
constexpr size_t rank = decltype(m)::extents_type::rank();
|
||||
|
||||
auto strides = m.strides();
|
||||
static_assert(std::same_as<decltype(strides),
|
||||
std::array<IndexType, rank>>);
|
||||
VERIFY(strides.size() == rank);
|
||||
for (size_t i = 0; i < strides.size(); ++i)
|
||||
VERIFY(strides[i] == m.stride(i));
|
||||
};
|
||||
|
||||
check(std::extents());
|
||||
check(std::extents(0));
|
||||
check(std::extents(3));
|
||||
check(std::extents(3, 5, 7));
|
||||
check(std::extents(3, 0, 7));
|
||||
}
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr bool
|
||||
test_strides_all()
|
||||
{
|
||||
test_strides<Layout<0>>();
|
||||
test_strides<Layout<1>>();
|
||||
test_strides<Layout<3>>();
|
||||
test_strides<Layout<dyn>>();
|
||||
return true;
|
||||
}
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr void
|
||||
test_exhaustive_0d()
|
||||
{
|
||||
auto exts = std::extents<int>{};
|
||||
|
||||
auto check = [](auto m)
|
||||
{
|
||||
static_assert(m.is_always_exhaustive());
|
||||
VERIFY(m.is_exhaustive());
|
||||
};
|
||||
|
||||
check(typename Layout<0>::mapping(exts));
|
||||
check(typename Layout<1>::mapping(exts));
|
||||
check(typename Layout<2>::mapping(exts));
|
||||
check(typename Layout<dyn>::mapping(exts));
|
||||
}
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr void
|
||||
test_exhaustive_1d()
|
||||
{
|
||||
auto check_dyn_and_sta = []<typename PaddedLayout>(PaddedLayout)
|
||||
{
|
||||
auto check = [](auto exts)
|
||||
{
|
||||
auto m = typename PaddedLayout::mapping(exts);
|
||||
static_assert(m.is_always_exhaustive());
|
||||
VERIFY(m.is_exhaustive());
|
||||
};
|
||||
|
||||
check(std::extents(4));
|
||||
check(std::extents<int, 4>{});
|
||||
};
|
||||
|
||||
check_dyn_and_sta(Layout<1>{});
|
||||
check_dyn_and_sta(Layout<2>{});
|
||||
check_dyn_and_sta(Layout<6>{});
|
||||
check_dyn_and_sta(Layout<dyn>{});
|
||||
}
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr void
|
||||
test_exhaustive_3d()
|
||||
{
|
||||
using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
|
||||
auto exts_dyn = Traits::make_extents(std::extents(4, 5, 7));
|
||||
auto exts_sta = Traits::make_extents(std::extents<int, 4, 5, 7>{});
|
||||
auto ctrue = std::cw<true>;
|
||||
auto cfalse= std::cw<false>;
|
||||
|
||||
auto check = [](auto m, auto static_expected, auto runtime_expected)
|
||||
{
|
||||
static_assert(m.is_always_exhaustive() == static_expected);
|
||||
VERIFY(m.is_exhaustive() == runtime_expected);
|
||||
};
|
||||
|
||||
check(typename Layout<0>::mapping(exts_sta), ctrue, true);
|
||||
check(typename Layout<0>::mapping(exts_dyn), cfalse, true);
|
||||
check(typename Layout<1>::mapping(exts_sta), ctrue, true);
|
||||
check(typename Layout<1>::mapping(exts_dyn), cfalse, true);
|
||||
check(typename Layout<2>::mapping(exts_sta), ctrue, true);
|
||||
check(typename Layout<2>::mapping(exts_dyn), cfalse, true);
|
||||
check(typename Layout<6>::mapping(exts_dyn), cfalse, false);
|
||||
check(typename Layout<6>::mapping(exts_sta), cfalse, false);
|
||||
check(typename Layout<dyn>::mapping(exts_sta), cfalse, true);
|
||||
check(typename Layout<dyn>::mapping(exts_dyn, 2), cfalse, true);
|
||||
check(typename Layout<dyn>::mapping(exts_dyn, 3), cfalse, false);
|
||||
}
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr bool
|
||||
test_exhaustive()
|
||||
{
|
||||
test_exhaustive_0d<Layout>();
|
||||
test_exhaustive_1d<Layout>();
|
||||
test_exhaustive_3d<Layout>();
|
||||
return true;
|
||||
}
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr bool
|
||||
test_op_eq()
|
||||
{
|
||||
// The generic cases are handled in layouts/mapping.cc. Here we check
|
||||
// special cases related to non exhaustive layouts.
|
||||
using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
|
||||
|
||||
auto exts_sta = Traits::make_extents(std::extents<size_t, 6, 5, 7>{});
|
||||
auto exts_dyn = std::dims<3>(exts_sta);
|
||||
auto exts_other = Traits::make_extents(std::extents<size_t, 7, 5, 7>{});
|
||||
|
||||
auto m1 = typename Layout<0>::mapping(exts_sta);
|
||||
auto m2 = typename Layout<7>::mapping(exts_sta);
|
||||
|
||||
VERIFY(m1 == typename Layout<0>::mapping(exts_sta));
|
||||
VERIFY(m1 == typename Layout<1>::mapping(exts_sta));
|
||||
VERIFY(m1 == typename Layout<2>::mapping(exts_sta));
|
||||
VERIFY(m1 == typename Layout<6>::mapping(exts_sta));
|
||||
VERIFY(m1 != typename Layout<7>::mapping(exts_sta));
|
||||
VERIFY(m1 == typename Layout<dyn>::mapping(exts_sta));
|
||||
VERIFY(m1 != typename Layout<dyn>::mapping(exts_sta, 7));
|
||||
|
||||
VERIFY(m1 == typename Layout<0>::mapping(exts_dyn));
|
||||
VERIFY(m1 == typename Layout<1>::mapping(exts_dyn));
|
||||
VERIFY(m1 == typename Layout<2>::mapping(exts_dyn));
|
||||
VERIFY(m1 == typename Layout<6>::mapping(exts_dyn));
|
||||
VERIFY(m1 != typename Layout<7>::mapping(exts_dyn));
|
||||
VERIFY(m1 == typename Layout<dyn>::mapping(exts_dyn));
|
||||
VERIFY(m1 != typename Layout<dyn>::mapping(exts_dyn, 7));
|
||||
|
||||
VERIFY(m2 == typename Layout<7>::mapping(exts_sta));
|
||||
VERIFY(m2 == typename Layout<dyn>::mapping(exts_sta, 7));
|
||||
VERIFY(m2 == typename Layout<7>::mapping(exts_dyn));
|
||||
VERIFY(m2 == typename Layout<dyn>::mapping(exts_dyn, 7));
|
||||
|
||||
VERIFY(m2 != typename Layout<7>::mapping(exts_other));
|
||||
VERIFY(m2 != typename Layout<dyn>::mapping(exts_other, 7));
|
||||
return true;
|
||||
}
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr bool
|
||||
test_required_span_size_overflow()
|
||||
{
|
||||
using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
|
||||
using Extents = std::dextents<uint8_t, 2>;
|
||||
auto exts = Traits::make_extents(Extents{64, 2});
|
||||
auto strides = Traits::make_array(std::array<uint8_t, 2>{1, 128});
|
||||
auto ms = std::layout_stride::mapping(exts, strides);
|
||||
auto m = typename Layout<dyn>::mapping<Extents>(ms);
|
||||
VERIFY(is_same_mapping(m, ms));
|
||||
VERIFY(m.required_span_size() == ms.required_span_size());
|
||||
return true;
|
||||
}
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr bool
|
||||
test_all()
|
||||
{
|
||||
test_representable_padded_size<std::layout_left_padded>();
|
||||
test_default_ctor<Layout>();
|
||||
test_from_exts<Layout>();
|
||||
test_from_stride<Layout>();
|
||||
test_from_samepad<Layout>();
|
||||
test_from_same<Layout>();
|
||||
test_from_other<Layout>();
|
||||
test_to_same<Layout>();
|
||||
test_never_to_other<Layout>();
|
||||
test_strides_all<Layout>();
|
||||
test_exhaustive<Layout>();
|
||||
test_op_eq<Layout>();
|
||||
test_required_span_size_overflow<Layout>();
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
test_all<std::layout_left_padded>();
|
||||
static_assert(test_all<std::layout_left_padded>());
|
||||
|
||||
test_from_pad_all<std::layout_left_padded>();
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,324 @@
|
|||
// { dg-do compile { target c++26 } }
|
||||
#include <mdspan>
|
||||
|
||||
#include "padded_traits.h"
|
||||
#include <cstdint>
|
||||
|
||||
constexpr size_t dyn = std::dynamic_extent;
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr bool
|
||||
test_from_extens_representable_sta()
|
||||
{
|
||||
using E1 = std::extents<uint8_t, 8, 128>;
|
||||
auto m = typename Layout<dyn>::mapping(E1{}); // { dg-error "required from" }
|
||||
return true;
|
||||
}
|
||||
static_assert(test_from_extens_representable_sta<std::layout_left_padded>()); // { dg-error "from here" }
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr bool
|
||||
test_from_extents_representable_padded_size()
|
||||
{
|
||||
using E1 = std::extents<uint8_t, 8, 128>;
|
||||
using E2 = std::dextents<uint8_t, 2>;
|
||||
|
||||
auto m = typename Layout<dyn>::mapping(E2{E1{}}); // { dg-error "expansion of" }
|
||||
(void) m;
|
||||
return true;
|
||||
}
|
||||
static_assert(test_from_extents_representable_padded_size<std::layout_left_padded>()); // { dg-error "expansion of" }
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr bool
|
||||
test_from_extents_representable_stride()
|
||||
{
|
||||
using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
|
||||
using E1 = typename Traits::extents_type<std::extents<uint8_t, dyn, 1>>;
|
||||
auto m = typename Layout<128>::mapping(E1{129}); // { dg-error "expansion of" }
|
||||
(void) m;
|
||||
return true;
|
||||
}
|
||||
static_assert(test_from_extents_representable_stride<std::layout_left_padded>()); // { dg-error "expansion of" }
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr bool
|
||||
test_from_pad_representable_stride()
|
||||
{
|
||||
using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
|
||||
auto exts = Traits::make_extents(std::dextents<uint8_t, 2>(129, 2));
|
||||
auto m = typename Layout<dyn>::mapping(exts, 128); // { dg-error "expansion of" }
|
||||
return true;
|
||||
}
|
||||
static_assert(test_from_pad_representable_stride<std::layout_left_padded>()); // { dg-error "expansion of" }
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr bool
|
||||
test_from_pad_representable_padded_size()
|
||||
{
|
||||
using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
|
||||
auto exts = Traits::make_extents(std::dextents<uint8_t, 2>(64, 2));
|
||||
auto m = typename Layout<dyn>::mapping(exts, 128); // { dg-error "expansion of" }
|
||||
return true;
|
||||
}
|
||||
static_assert(test_from_pad_representable_padded_size<std::layout_left_padded>()); // { dg-error "expansion of" }
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr bool
|
||||
test_from_left()
|
||||
{
|
||||
using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
|
||||
using LayoutSame = typename Traits::layout_same;
|
||||
auto exts = Traits::make_extents(std::extents<uint8_t, 6, dyn>{4});
|
||||
auto ml = typename LayoutSame::mapping(exts);
|
||||
|
||||
typename Layout<4>::mapping<decltype(exts)> m(ml); // { dg-error "expansion of" }
|
||||
return true;
|
||||
}
|
||||
static_assert(test_from_left<std::layout_left_padded>()); // { dg-error "required from here" }
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr bool
|
||||
test_from_left_bad_runtime_stride()
|
||||
{
|
||||
using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
|
||||
auto exts = Traits::make_extents(std::extents<uint8_t, dyn, dyn>{6, 4});
|
||||
auto ml = typename Traits::layout_same::mapping(exts);
|
||||
|
||||
typename Layout<4>::mapping<decltype(exts)> m(ml); // { dg-error "expansion of" }
|
||||
(void) m;
|
||||
return true;
|
||||
}
|
||||
static_assert(test_from_left_bad_runtime_stride<std::layout_left_padded>()); // { dg-error "expansion of" }
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr bool
|
||||
test_from_left_representable_extents()
|
||||
{
|
||||
using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
|
||||
auto exts = Traits::make_extents(std::extents<uint16_t, dyn, dyn>{8, 128});
|
||||
auto ml = typename Traits::layout_same::mapping(exts);
|
||||
|
||||
typename Layout<8>::mapping<std::extents<uint8_t, dyn, dyn>> m(ml); // { dg-error "expansion of" }
|
||||
return true;
|
||||
}
|
||||
static_assert(test_from_left_representable_extents<std::layout_left_padded>()); // { dg-error "expansion of" }
|
||||
|
||||
template<template<size_t> typename Layout, size_t PaddingValue>
|
||||
constexpr bool
|
||||
test_pad_overflow()
|
||||
{
|
||||
auto exts = std::extents<uint8_t, dyn>{4};
|
||||
auto n = size_t(1) << 9;
|
||||
auto m = typename Layout<PaddingValue>::mapping(exts, n);
|
||||
(void) m;
|
||||
return true;
|
||||
}
|
||||
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" }
|
||||
|
||||
template<template<size_t> typename Layout, size_t PaddingValue>
|
||||
constexpr bool
|
||||
test_from_pad_negative()
|
||||
{
|
||||
auto exts = std::extents(4);
|
||||
auto m = typename Layout<PaddingValue>::mapping(exts, -1);
|
||||
(void) m;
|
||||
return true;
|
||||
}
|
||||
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" }
|
||||
|
||||
template<template<size_t> typename Layout, size_t Pad>
|
||||
constexpr bool
|
||||
test_static_pad_same()
|
||||
{
|
||||
using Extents = std::extents<int, dyn>;
|
||||
using Mapping = typename Layout<Pad>::mapping<Extents>;
|
||||
auto exts = Extents{4};
|
||||
auto m = Mapping(exts, Pad + 1); // { dg-error "expansion of" }
|
||||
(void) m;
|
||||
return true;
|
||||
}
|
||||
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" }
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr bool
|
||||
test_from_stride_wrong_stride0()
|
||||
{
|
||||
using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
|
||||
auto e = Traits::make_extents(std::extents{3, 5});
|
||||
auto s = Traits::make_array(std::array<int, 2>{2, 7});
|
||||
auto ms = std::layout_stride::mapping(e, s);
|
||||
auto m = typename Layout<dyn>::mapping<decltype(e)>(ms); // { dg-error "expansion of" }
|
||||
(void) m;
|
||||
return true;
|
||||
}
|
||||
static_assert(test_from_stride_wrong_stride0<std::layout_left_padded>()); // { dg-error "expansion of" }
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr bool
|
||||
test_from_stride_wrong_stride1()
|
||||
{
|
||||
using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
|
||||
auto e = Traits::make_extents(std::extents(3, 5));
|
||||
auto s = Traits::make_array(std::array<int, 2>{1, 3});
|
||||
auto ms = std::layout_stride::mapping(e, s);
|
||||
auto m = typename Layout<2>::mapping<decltype(e)>(ms); // { dg-error "expansion of" }
|
||||
(void) m;
|
||||
return true;
|
||||
}
|
||||
static_assert(test_from_stride_wrong_stride1<std::layout_left_padded>()); // { dg-error "expansion of" }
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr bool
|
||||
test_from_stride_wrong_stride2()
|
||||
{
|
||||
using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
|
||||
auto e = Traits::make_extents(std::extents(3, 5, 7));
|
||||
auto s = Traits::make_array(std::array<int, 3>{1, 4, 21});
|
||||
auto ms = std::layout_stride::mapping(e, s);
|
||||
auto m = typename Layout<dyn>::mapping<decltype(e)>(ms); // here (not implemented)
|
||||
(void) m;
|
||||
return true;
|
||||
}
|
||||
static_assert(test_from_stride_wrong_stride2<std::layout_left_padded>());
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr bool
|
||||
test_from_stride_oversized()
|
||||
{
|
||||
using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
|
||||
auto exts = Traits::make_extents(std::extents<uint16_t, dyn, dyn>{3, 6});
|
||||
auto s = Traits::make_array(std::array<uint16_t, 2>{1, 128});
|
||||
auto ms = std::layout_stride::mapping(exts, s);
|
||||
|
||||
using Mapping = typename Layout<dyn>::mapping<std::dextents<uint8_t, 2>>;
|
||||
Mapping m(ms); // { dg-error "expansion of" }
|
||||
(void) m;
|
||||
return true;
|
||||
}
|
||||
static_assert(test_from_stride_oversized<std::layout_left_padded>()); // { dg-error "expansion of" }
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr bool
|
||||
test_from_samepad_dyn()
|
||||
{
|
||||
using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
|
||||
auto e = Traits::make_extents(std::extents(3, 5));
|
||||
auto mlp = typename Layout<dyn>::mapping(e);
|
||||
auto m = typename Layout<2>::mapping<decltype(e)>(mlp); // { dg-error "expansion of" }
|
||||
(void) m;
|
||||
return true;
|
||||
}
|
||||
static_assert(test_from_samepad_dyn<std::layout_left_padded>()); // { dg-error "expansion of" }
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr bool
|
||||
test_from_samepad_sta()
|
||||
{
|
||||
using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
|
||||
auto e = Traits::make_extents(std::extents{3, 5});
|
||||
auto mlp = typename Layout<3>::mapping(e);
|
||||
auto m = typename Layout<2>::mapping<decltype(e)>(mlp); // { dg-error "expansion of" }
|
||||
(void) m;
|
||||
return true;
|
||||
}
|
||||
static_assert(test_from_samepad_sta<std::layout_left_padded>()); // { dg-error "expansion of" }
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr bool
|
||||
test_from_samepad_oversized()
|
||||
{
|
||||
using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
|
||||
using E1 = typename Traits::extents_type<std::extents<uint16_t, 8, 128>>;
|
||||
using E2 = typename Traits::extents_type<std::extents<uint8_t, dyn, dyn>>;
|
||||
auto mlp = typename Layout<dyn>::mapping<E1>(E1{});
|
||||
auto m = typename Layout<dyn>::mapping<E2>(mlp); // { dg-error "expansion of" }
|
||||
(void) m;
|
||||
return true;
|
||||
}
|
||||
static_assert(test_from_samepad_oversized<std::layout_left_padded>()); // { dg-error "expansion of" }
|
||||
|
||||
template<template<size_t> typename Layout, size_t RunId>
|
||||
constexpr bool
|
||||
test_to_same_not_exhaustive()
|
||||
{
|
||||
using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
|
||||
using E1 = typename Traits::extents_type<std::extents<int, 6, 5>>;
|
||||
using E2 = typename Traits::extents_type<std::extents<int, dyn, 5>>;
|
||||
|
||||
[[maybe_unused]] auto msta = typename Layout<7>::mapping(E1{});
|
||||
if constexpr (RunId == 0)
|
||||
{
|
||||
auto m = typename Traits::layout_same::mapping<E1>(msta); // { dg-error "required from" }
|
||||
(void) m;
|
||||
}
|
||||
if constexpr (RunId == 1)
|
||||
{
|
||||
auto m = typename Traits::layout_same::mapping<E2>(msta); // { dg-error "expansion of" }
|
||||
(void) m;
|
||||
}
|
||||
|
||||
[[maybe_unused]] auto mdyn = typename Layout<dyn>::mapping(E2{E1{}}, 7);
|
||||
if constexpr (RunId == 2)
|
||||
{
|
||||
auto m = typename Traits::layout_same::mapping<E1>(mdyn); // { dg-error "expansion of" }
|
||||
(void) m;
|
||||
}
|
||||
if constexpr (RunId == 3)
|
||||
{
|
||||
auto m = typename Traits::layout_same::mapping<E2>(mdyn); // { dg-error "expansion of" }
|
||||
(void) m;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
static_assert(test_to_same_not_exhaustive<std::layout_left_padded, 0>()); // { dg-error "expansion of" }
|
||||
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" }
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr bool
|
||||
test_statically_bad_padding_value1()
|
||||
{
|
||||
using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
|
||||
constexpr auto N = std::numeric_limits<size_t>::max() - 1;
|
||||
using Extents = typename Traits::extents_type<std::extents<size_t, N, 0>>;
|
||||
typename Layout<10>::mapping<Extents> m; // { dg-error "required from" }
|
||||
return true;
|
||||
}
|
||||
static_assert(test_statically_bad_padding_value1<std::layout_left_padded>()); // { dg-error "required from" }
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr bool
|
||||
test_statically_bad_padding_value2()
|
||||
{
|
||||
using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
|
||||
using Extents = typename Traits::extents_type<std::extents<uint8_t, 255, 0>>;
|
||||
typename Layout<2>::mapping<Extents> m; // { dg-error "required from" }
|
||||
return true;
|
||||
}
|
||||
static_assert(test_statically_bad_padding_value2<std::layout_left_padded>()); // { dg-error "required from" }
|
||||
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr bool
|
||||
test_statically_oversized()
|
||||
{
|
||||
using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
|
||||
using Extents = typename Traits::extents_type<std::extents<uint8_t, 127, 2>>;
|
||||
typename Layout<2>::mapping<Extents> m; // { dg-error "required from" }
|
||||
return true;
|
||||
}
|
||||
static_assert(test_statically_oversized<std::layout_left_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" }
|
||||
// { dg-prune-output "called in a constant expression" }
|
||||
// { dg-prune-output "no matching function" }
|
||||
// { dg-prune-output "static assertion failed" }
|
||||
// { dg-prune-output "__glibcxx_assert_fail()" }
|
||||
// { dg-prune-output "must be compatible with other.stride" }
|
||||
// { dg-prune-output "padding_value is dynamic_extent" }
|
||||
// { dg-prune-output "_S_rank <= 1" }
|
|
@ -0,0 +1,73 @@
|
|||
#ifndef TEST_MDSPAN_PADDED_TRAITS_H
|
||||
#define TEST_MDSPAN_PADDED_TRAITS_H
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
template<typename Layout>
|
||||
constexpr static bool is_left_padded = false;
|
||||
|
||||
#if __cplusplus > 202302L
|
||||
template<size_t PaddingValue>
|
||||
constexpr static bool is_left_padded<std::layout_left_padded<PaddingValue>>
|
||||
= true;
|
||||
#endif
|
||||
|
||||
template<typename Layout>
|
||||
constexpr bool
|
||||
is_padded_layout = is_left_padded<Layout>;
|
||||
|
||||
#if __cplusplus > 202302L
|
||||
|
||||
enum class PaddingSide
|
||||
{
|
||||
Left
|
||||
};
|
||||
|
||||
struct DeducePaddingSide
|
||||
{
|
||||
template<template<size_t> typename Layout>
|
||||
constexpr static PaddingSide
|
||||
from_template()
|
||||
{ return PaddingSide::Left; }
|
||||
|
||||
template<typename Layout>
|
||||
constexpr static PaddingSide
|
||||
from_typename()
|
||||
{ return PaddingSide::Left; }
|
||||
};
|
||||
|
||||
template<PaddingSide Side>
|
||||
struct LayoutTraits;
|
||||
|
||||
template<>
|
||||
struct LayoutTraits<PaddingSide::Left>
|
||||
{
|
||||
using layout_same = std::layout_left;
|
||||
using layout_other = std::layout_right;
|
||||
|
||||
template<typename Extents>
|
||||
using extents_type = Extents;
|
||||
|
||||
template<typename Extents>
|
||||
constexpr static extents_type<Extents>
|
||||
make_extents(const Extents& exts)
|
||||
{ return exts; }
|
||||
|
||||
template<typename T, size_t N>
|
||||
constexpr static std::array<T, N>
|
||||
make_array(const std::array<T, N>& expected)
|
||||
{ return expected; }
|
||||
|
||||
template<typename Mapping>
|
||||
constexpr static auto
|
||||
padded_stride(const Mapping& m)
|
||||
{ return m.stride(1); }
|
||||
|
||||
template<typename Extents>
|
||||
constexpr static auto
|
||||
padded_extent(const Extents& exts)
|
||||
{ return exts.extent(0); }
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
Loading…
Reference in New Issue