mirror of git://gcc.gnu.org/git/gcc.git
libstdc++: Implement submdspan_canonicalize_slices. [PR110352]
Implements submdspan_canonicalize_slices as described in P3663 and adds it to the std module. There's one deviation from the standard. Doesn't (under all circumstances) require: 0 <= begin[k] <= end[k] <= exts.extent(k) where the k-th slice range is [begin[k], end[k]). Instead, it requires that the k-th slice ranges is contained in the k-th extent interval. If the slice range is empty, then that condition is always satisfied, even if begin[k] == end[k] > exts.extent(k) The deviation is that we enforce the above inequality through preconditions. This is analogous to what the standard requires if begin[k] is a constant wrapper. PR libstdc++/110352 libstdc++-v3/ChangeLog: * include/std/mdspan (submdspan_canonicalize_slices): New function. * src/c++23/std.cc.in (submdspan_canonicalize_slices): Add. * testsuite/23_containers/mdspan/submdspan/submdspan_canonicalize_slices.cc: New test. * testsuite/23_containers/mdspan/submdspan/submdspan_canonicalize_slices_neg.cc: New test. Reviewed-by: Tomasz Kamiński <tkaminsk@redhat.com> Signed-off-by: Luc Grosheintz <luc.grosheintz@gmail.com>
This commit is contained in:
parent
24a1085072
commit
f6f9aec0c6
|
|
@ -38,15 +38,20 @@
|
|||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#if __cplusplus > 202302L
|
||||
#include <bits/align.h>
|
||||
#endif
|
||||
|
||||
#define __glibcxx_want_mdspan
|
||||
#define __glibcxx_want_aligned_accessor
|
||||
#define __glibcxx_want_submdspan
|
||||
#include <bits/version.h>
|
||||
|
||||
#if __glibcxx_aligned_accessor
|
||||
#include <bits/align.h>
|
||||
#endif
|
||||
|
||||
#if __glibcxx_submdspan
|
||||
#include <tuple>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __glibcxx_mdspan
|
||||
|
||||
namespace std _GLIBCXX_VISIBILITY(default)
|
||||
|
|
@ -826,6 +831,41 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
return __impl(make_index_sequence<__rank>());
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __glibcxx_submdspan
|
||||
template<typename _Tp>
|
||||
constexpr bool __is_strided_slice = false;
|
||||
|
||||
template<typename _OffsetType, typename _ExtentType, typename _StrideType>
|
||||
constexpr bool __is_strided_slice<strided_slice<_OffsetType,
|
||||
_ExtentType, _StrideType>> = true;
|
||||
|
||||
template<typename _IndexType, typename _OIndexType>
|
||||
consteval bool
|
||||
__is_representable_integer(_OIndexType __value)
|
||||
{
|
||||
constexpr auto __min = __gnu_cxx::__int_traits<_IndexType>::__min;
|
||||
constexpr auto __max = __gnu_cxx::__int_traits<_IndexType>::__max;
|
||||
return std::cmp_less_equal(__min, __value)
|
||||
&& std::cmp_less_equal(__value, __max);
|
||||
}
|
||||
|
||||
template<typename _Tp>
|
||||
constexpr bool __is_constant_wrapper = false;
|
||||
|
||||
template<_CwFixedValue _Xv, typename _Tp>
|
||||
constexpr bool __is_constant_wrapper<constant_wrapper<_Xv, _Tp>>
|
||||
= true;
|
||||
|
||||
template<size_t _Index, typename _Extents>
|
||||
constexpr auto
|
||||
__extract_extent(const _Extents& __exts)
|
||||
{
|
||||
using _IndexType = typename _Extents::index_type;
|
||||
return extents<_IndexType, _Extents::static_extent(_Index)>{
|
||||
__exts.extent(_Index)};
|
||||
}
|
||||
#endif // __glibcxx_submdspan
|
||||
}
|
||||
|
||||
template<typename _Extents>
|
||||
|
|
@ -2498,6 +2538,149 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
typename _MappingType::extents_type,
|
||||
typename _MappingType::layout_type, _AccessorType>;
|
||||
|
||||
#if __glibcxx_submdspan
|
||||
namespace __mdspan
|
||||
{
|
||||
template<typename _IndexType, typename _Slice>
|
||||
constexpr auto
|
||||
__canonical_index(_Slice&& __slice)
|
||||
{
|
||||
if constexpr (__detail::__integral_constant_like<_Slice>)
|
||||
{
|
||||
static_assert(__is_representable_integer<_IndexType>(_Slice::value));
|
||||
static_assert(_Slice::value >= 0);
|
||||
return std::cw<_IndexType(_Slice::value)>;
|
||||
}
|
||||
else
|
||||
return __mdspan::__index_type_cast<_IndexType>(std::move(__slice));
|
||||
}
|
||||
|
||||
template<typename _IndexType, typename _Slice>
|
||||
constexpr auto
|
||||
__slice_cast(_Slice&& __slice)
|
||||
{
|
||||
using _SliceType = remove_cvref_t<_Slice>;
|
||||
if constexpr (is_convertible_v<_SliceType, full_extent_t>)
|
||||
return static_cast<full_extent_t>(std::move(__slice));
|
||||
else if constexpr (is_convertible_v<_SliceType, _IndexType>)
|
||||
return __mdspan::__canonical_index<_IndexType>(std::move(__slice));
|
||||
else if constexpr (__is_strided_slice<_SliceType>)
|
||||
{
|
||||
auto __extent
|
||||
= __mdspan::__canonical_index<_IndexType>(std::move(__slice.extent));
|
||||
auto __offset
|
||||
= __mdspan::__canonical_index<_IndexType>(std::move(__slice.offset));
|
||||
if constexpr (is_same_v<decltype(__extent),
|
||||
constant_wrapper<_IndexType(0)>>)
|
||||
return strided_slice{
|
||||
.offset = __offset,
|
||||
.extent = __extent,
|
||||
.stride = cw<_IndexType(1)>
|
||||
};
|
||||
else
|
||||
return strided_slice{
|
||||
.offset = __offset,
|
||||
.extent = __extent,
|
||||
.stride
|
||||
= __mdspan::__canonical_index<_IndexType>(std::move(__slice.stride))
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
auto [__sbegin, __send] = std::move(__slice);
|
||||
auto __offset
|
||||
= __mdspan::__canonical_index<_IndexType>(std::move(__sbegin));
|
||||
auto __end
|
||||
= __mdspan::__canonical_index<_IndexType>(std::move(__send));
|
||||
return strided_slice{
|
||||
.offset = __offset,
|
||||
.extent = __mdspan::__canonical_index<_IndexType>(__end - __offset),
|
||||
.stride = cw<_IndexType(1)>
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
template<typename _IndexType, size_t _Extent, typename _OIndexType>
|
||||
constexpr void
|
||||
__check_valid_index(const extents<_IndexType, _Extent>& __ext,
|
||||
const _OIndexType& __idx)
|
||||
{
|
||||
if constexpr (__is_constant_wrapper<_OIndexType>
|
||||
&& _Extent != dynamic_extent)
|
||||
{
|
||||
static_assert(_OIndexType::value >= 0);
|
||||
static_assert(std::cmp_less_equal(_OIndexType::value, _Extent));
|
||||
}
|
||||
else
|
||||
__glibcxx_assert(__idx <= __ext.extent(0));
|
||||
}
|
||||
|
||||
template<typename _IndexType, size_t _Extent, typename _Slice>
|
||||
constexpr void
|
||||
__check_valid_slice(const extents<_IndexType, _Extent>& __ext,
|
||||
const _Slice& __slice)
|
||||
{
|
||||
if constexpr (__is_strided_slice<_Slice>)
|
||||
{
|
||||
// DEVIATION: For empty slices, P3663r3 does not allow us to check
|
||||
// that this is less than or equal to the k-th extent (at runtime).
|
||||
// We're only allowed to check if __slice.offset, __slice.extent
|
||||
// are constant wrappers and __ext is a static extent.
|
||||
__mdspan::__check_valid_index(__ext, __slice.offset);
|
||||
__mdspan::__check_valid_index(__ext, __slice.extent);
|
||||
|
||||
if constexpr (__is_constant_wrapper<typename _Slice::extent_type>
|
||||
&& __is_constant_wrapper<typename _Slice::stride_type>)
|
||||
static_assert(_Slice::stride_type::value > 0);
|
||||
else
|
||||
__glibcxx_assert(__slice.extent == 0 || __slice.stride > 0);
|
||||
|
||||
if constexpr (__is_constant_wrapper<typename _Slice::offset_type>
|
||||
&& __is_constant_wrapper<typename _Slice::extent_type>
|
||||
&& _Extent != dynamic_extent)
|
||||
static_assert(std::cmp_greater_equal(
|
||||
_Extent - _Slice::offset_type::value,
|
||||
_Slice::extent_type::value));
|
||||
else
|
||||
__glibcxx_assert(__ext.extent(0) - __slice.offset
|
||||
>= __slice.extent);
|
||||
}
|
||||
else if constexpr (__is_constant_wrapper<_Slice>
|
||||
&& _Extent != dynamic_extent)
|
||||
static_assert(std::cmp_less(_Slice::value, _Extent));
|
||||
else if constexpr (convertible_to<_Slice, _IndexType>)
|
||||
__glibcxx_assert(__slice < __ext.extent(0));
|
||||
}
|
||||
|
||||
template<typename _Extents, typename... _Slices>
|
||||
constexpr void
|
||||
__check_valid_slices(const _Extents& __exts, const _Slices&... __slices)
|
||||
{
|
||||
constexpr auto __rank = _Extents::rank();
|
||||
auto __impl = [&]<size_t... _Is>(index_sequence<_Is...>)
|
||||
{
|
||||
((__mdspan::__check_valid_slice(__extract_extent<_Is>(__exts),
|
||||
__slices...[_Is])),...);
|
||||
};
|
||||
__impl(make_index_sequence<__rank>());
|
||||
}
|
||||
}
|
||||
|
||||
template<typename _IndexType, size_t... _Extents, typename... _RawSlices>
|
||||
requires (sizeof...(_Extents) == sizeof...(_RawSlices))
|
||||
constexpr auto
|
||||
submdspan_canonicalize_slices(const extents<_IndexType, _Extents...>& __exts,
|
||||
_RawSlices... __raw_slices)
|
||||
{
|
||||
auto __impl = [&__exts](auto... __slices)
|
||||
{
|
||||
__mdspan::__check_valid_slices(__exts, __slices...);
|
||||
return std::make_tuple(__slices...);
|
||||
};
|
||||
return __impl(__mdspan::__slice_cast<_IndexType>(__raw_slices)...);
|
||||
}
|
||||
#endif // __glibcxx_submdspan
|
||||
|
||||
_GLIBCXX_END_NAMESPACE_VERSION
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1881,6 +1881,7 @@ export namespace std
|
|||
using std::full_extent_t;
|
||||
using std::full_extent;
|
||||
using std::submdspan_mapping_result;
|
||||
using std::submdspan_canonicalize_slices;
|
||||
#endif
|
||||
// FIXME submdspan_extents, mdsubspan
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,220 @@
|
|||
// { dg-do run { target c++26 } }
|
||||
#include <mdspan>
|
||||
|
||||
#include <testsuite_hooks.h>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
constexpr size_t dyn = std::dynamic_extent;
|
||||
|
||||
template<typename Extents, typename CInt>
|
||||
constexpr bool
|
||||
check_collapsing(Extents exts, CInt ci_raw)
|
||||
{
|
||||
using IndexType = typename Extents::index_type;
|
||||
auto ci_expected = std::cw<IndexType{ci_raw.value}>;
|
||||
auto [ci] = std::submdspan_canonicalize_slices(exts, ci_raw);
|
||||
static_assert(std::same_as<decltype(ci), decltype(ci_expected)>);
|
||||
VERIFY(std::cmp_equal(ci.value, ci_raw.value));
|
||||
|
||||
auto [i] = std::submdspan_canonicalize_slices(exts, ci_raw.value);
|
||||
static_assert(std::same_as<decltype(i), IndexType>);
|
||||
VERIFY(std::cmp_equal(i, ci_raw.value));
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename Extents>
|
||||
constexpr bool
|
||||
test_scalar(Extents exts)
|
||||
{
|
||||
using IndexType = typename Extents::index_type;
|
||||
|
||||
check_collapsing(exts, std::cw<uint8_t{0}>);
|
||||
check_collapsing(exts, std::cw<IndexType{0}>);
|
||||
|
||||
check_collapsing(exts, std::cw<uint8_t{4}>);
|
||||
check_collapsing(exts, std::cw<IndexType{4}>);
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
test_scalar()
|
||||
{
|
||||
test_scalar(std::extents<int, dyn>{5});
|
||||
test_scalar(std::extents<int, 5>{});
|
||||
test_scalar(std::extents<unsigned int, dyn>{5});
|
||||
test_scalar(std::extents<unsigned int, 5>{});
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr void
|
||||
assert_same(auto lhs, auto rhs)
|
||||
{
|
||||
static_assert(std::same_as<decltype(lhs), decltype(rhs)>);
|
||||
VERIFY(lhs == rhs);
|
||||
}
|
||||
|
||||
template<template<typename, typename> typename Pair>
|
||||
constexpr bool
|
||||
test_pair(auto exts, auto cbegin, auto cend, auto coffset, auto cextent)
|
||||
{
|
||||
using IndexType = typename decltype(exts)::index_type;
|
||||
auto c1 = std::cw<IndexType{1}>;
|
||||
|
||||
auto raw_cc = Pair{cbegin, cend};
|
||||
auto [cc] = std::submdspan_canonicalize_slices(exts, raw_cc);
|
||||
assert_same(cc.offset, coffset);
|
||||
assert_same(cc.extent, cextent);
|
||||
assert_same(cc.stride, c1);
|
||||
|
||||
auto raw_cd = Pair{cbegin, cend.value};
|
||||
auto [cd] = std::submdspan_canonicalize_slices(exts, raw_cd);
|
||||
assert_same(cd.offset, coffset);
|
||||
assert_same(cd.extent, cextent.value);
|
||||
assert_same(cd.stride, c1);
|
||||
|
||||
auto raw_dc = Pair{cbegin.value, cend};
|
||||
auto [dc] = std::submdspan_canonicalize_slices(exts, raw_dc);
|
||||
assert_same(dc.offset, coffset.value);
|
||||
assert_same(dc.extent, cextent.value);
|
||||
assert_same(dc.stride, c1);
|
||||
|
||||
auto raw_dd = Pair{cbegin.value, cend.value};
|
||||
auto [dd] = std::submdspan_canonicalize_slices(exts, raw_dd);
|
||||
assert_same(dd.offset, coffset.value);
|
||||
assert_same(dd.extent, cextent.value);
|
||||
assert_same(dd.stride, c1);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<template<typename, typename> typename Pair>
|
||||
constexpr bool
|
||||
test_pair()
|
||||
{
|
||||
test_pair<Pair>(std::extents<int, dyn>{5}, std::cw<uint8_t{2}>,
|
||||
std::cw<uint8_t{5}>, std::cw<2>, std::cw<3>);
|
||||
test_pair<Pair>(std::extents<int, 5>{}, std::cw<uint8_t{2}>,
|
||||
std::cw<uint8_t{5}>, std::cw<2>, std::cw<3>);
|
||||
test_pair<Pair>(std::extents<int, 0>{}, std::cw<uint8_t{0}>,
|
||||
std::cw<uint8_t{0}>, std::cw<0>, std::cw<0>);
|
||||
test_pair<Pair>(std::extents<int, dyn>{0}, std::cw<uint8_t{0}>,
|
||||
std::cw<uint8_t{0}>, std::cw<0>, std::cw<0>);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename Lower, typename Upper>
|
||||
struct Range
|
||||
{
|
||||
Lower lower;
|
||||
Upper upper;
|
||||
};
|
||||
|
||||
constexpr bool
|
||||
test_pair_all()
|
||||
{
|
||||
test_pair<std::pair>();
|
||||
test_pair<std::tuple>();
|
||||
test_pair<Range>();
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
test_strided_slice(auto exts, auto co, auto ce, auto cs)
|
||||
{
|
||||
using IndexType = decltype(exts)::index_type;
|
||||
|
||||
auto coffset = std::cw<IndexType{co.value}>;
|
||||
auto cextent = std::cw<IndexType{ce.value}>;
|
||||
auto cstride = std::cw<IndexType{cs.value}>;
|
||||
|
||||
auto raw_ccc = std::strided_slice{co, ce, cs};
|
||||
auto [ccc] = std::submdspan_canonicalize_slices(exts, raw_ccc);
|
||||
assert_same(ccc.offset, coffset);
|
||||
assert_same(ccc.extent, cextent);
|
||||
assert_same(ccc.stride, cstride);
|
||||
|
||||
auto raw_dcc = std::strided_slice{co.value, ce, cs};
|
||||
auto [dcc] = std::submdspan_canonicalize_slices(exts, raw_dcc);
|
||||
assert_same(dcc.offset, coffset.value);
|
||||
assert_same(dcc.extent, cextent);
|
||||
assert_same(dcc.stride, cstride);
|
||||
|
||||
auto raw_cdc = std::strided_slice{co, ce.value, cs};
|
||||
auto [cdc] = std::submdspan_canonicalize_slices(exts, raw_cdc);
|
||||
assert_same(cdc.offset, coffset);
|
||||
assert_same(cdc.extent, cextent.value);
|
||||
assert_same(cdc.stride, cstride);
|
||||
|
||||
auto raw_ccd = std::strided_slice{co, ce, cs.value};
|
||||
auto [ccd] = std::submdspan_canonicalize_slices(exts, raw_ccd);
|
||||
assert_same(ccd.offset, coffset);
|
||||
assert_same(ccd.extent, cextent);
|
||||
assert_same(ccd.stride, cstride.value);
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
test_strided_slice()
|
||||
{
|
||||
auto run = [](auto exts)
|
||||
{
|
||||
auto cs = std::cw<uint8_t{9}>;
|
||||
test_strided_slice(exts, std::cw<uint8_t{2}>, std::cw<uint8_t{3}>, cs);
|
||||
test_strided_slice(exts, std::cw<uint8_t{0}>, std::cw<uint8_t{5}>, cs);
|
||||
};
|
||||
|
||||
run(std::extents<int, 5>{});
|
||||
run(std::extents<int, dyn>{5});
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
test_strided_slice_zero_extent(auto exts, auto cs)
|
||||
{
|
||||
using IndexType = typename decltype(exts)::index_type;
|
||||
auto c0 = std::cw<uint8_t{0}>;
|
||||
auto raw_ccc = std::strided_slice{c0, c0, cs};
|
||||
auto [ccc] = std::submdspan_canonicalize_slices(exts, raw_ccc);
|
||||
assert_same(ccc.stride, std::cw<IndexType{1}>);
|
||||
|
||||
auto raw_ccd = std::strided_slice{c0, c0, cs.value};
|
||||
auto [ccd] = std::submdspan_canonicalize_slices(exts, raw_ccd);
|
||||
assert_same(ccd.stride, std::cw<IndexType{1}>);
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
test_strided_slice_zero_extent(auto exts)
|
||||
{
|
||||
test_strided_slice_zero_extent(exts, std::cw<uint8_t{0}>);
|
||||
test_strided_slice_zero_extent(exts, std::cw<uint8_t{9}>);
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
test_strided_slice_zero_extent()
|
||||
{
|
||||
test_strided_slice_zero_extent(std::extents<int, 0>{});
|
||||
test_strided_slice_zero_extent(std::extents<int, dyn>{0});
|
||||
test_strided_slice_zero_extent(std::extents<int, 5>{});
|
||||
test_strided_slice_zero_extent(std::extents<int, dyn>{5});
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
test_all()
|
||||
{
|
||||
test_scalar();
|
||||
test_pair_all();
|
||||
test_strided_slice();
|
||||
test_strided_slice_zero_extent();
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
test_all();
|
||||
static_assert(test_all());
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,208 @@
|
|||
// { dg-do compile { target c++26 } }
|
||||
#include <mdspan>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
constexpr size_t dyn = std::dynamic_extent;
|
||||
|
||||
constexpr auto dyn_empty = std::extents<int32_t, dyn>{0};
|
||||
constexpr auto sta_empty = std::extents<uint32_t, 0>{};
|
||||
|
||||
constexpr auto dyn_uexts = std::extents<uint8_t, dyn>{5};
|
||||
constexpr auto sta_uexts = std::extents<uint16_t, 5>{5};
|
||||
constexpr auto dyn_sexts = std::extents<int8_t, dyn>{5};
|
||||
constexpr auto sta_sexts = std::extents<int16_t, 5>{5};
|
||||
|
||||
constexpr bool
|
||||
test_rank_mismatch()
|
||||
{
|
||||
auto exts = std::extents(1);
|
||||
std::submdspan_canonicalize_slices(exts, 0, 0); // { dg-error "no matching" }
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename Int, typename Extents>
|
||||
constexpr bool
|
||||
test_under1(Int i1, Extents exts)
|
||||
{
|
||||
auto [s1] = std::submdspan_canonicalize_slices(exts, i1);
|
||||
return true;
|
||||
}
|
||||
|
||||
static_assert(test_under1(-1, dyn_sexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_under1(-1, dyn_uexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_under1(-1, sta_sexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_under1(-1, sta_uexts)); // { dg-error "expansion of" }
|
||||
|
||||
static_assert(test_under1(std::cw<-1>, dyn_sexts)); // { dg-error "required from" }
|
||||
static_assert(test_under1(std::cw<-1>, dyn_uexts)); // { dg-error "required from" }
|
||||
static_assert(test_under1(std::cw<-1>, sta_sexts)); // { dg-error "required from" }
|
||||
static_assert(test_under1(std::cw<-1>, sta_uexts)); // { dg-error "required from" }
|
||||
|
||||
template<typename Int, typename Extents>
|
||||
constexpr bool
|
||||
test_over1(Int i1, Extents exts)
|
||||
{
|
||||
auto [s1] = std::submdspan_canonicalize_slices(exts, i1);
|
||||
return true;
|
||||
}
|
||||
|
||||
static_assert(test_over1(0, dyn_empty)); // { dg-error "expansion of" }
|
||||
static_assert(test_over1(0, sta_empty)); // { dg-error "expansion of" }
|
||||
static_assert(test_over1(5, dyn_sexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_over1(5, dyn_uexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_over1(5, sta_sexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_over1(5, sta_uexts)); // { dg-error "expansion of" }
|
||||
|
||||
static_assert(test_over1(std::cw<0>, dyn_empty)); // { dg-error "expansion of" }
|
||||
static_assert(test_over1(std::cw<0>, sta_empty)); // { dg-error "expansion of" }
|
||||
static_assert(test_over1(std::cw<5>, dyn_sexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_over1(std::cw<5>, dyn_uexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_over1(std::cw<5>, sta_sexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_over1(std::cw<5>, sta_uexts)); // { dg-error "expansion of" }
|
||||
|
||||
template<typename Offset, typename Extent, typename Stride, typename Extents>
|
||||
constexpr bool
|
||||
test_under2(Offset o, Extent e, Stride s, Extents exts)
|
||||
{
|
||||
std::submdspan_canonicalize_slices(exts, std::strided_slice{o, e, s});
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr auto i8_1 = int8_t{1};
|
||||
|
||||
static_assert(test_under2(-i8_1, 0, 1, dyn_uexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_under2(0, -i8_1, 1, dyn_uexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_under2(0, 1, -i8_1, dyn_uexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_under2(-i8_1, 0, 1, dyn_sexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_under2(0, -i8_1, 1, dyn_sexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_under2(0, 1, -i8_1, dyn_sexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_under2(-i8_1, 0, 1, sta_uexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_under2(0, -i8_1, 1, sta_uexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_under2(0, 1, -i8_1, sta_uexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_under2(-i8_1, 0, 1, sta_sexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_under2(0, -i8_1, 1, sta_sexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_under2(0, 1, -i8_1, sta_sexts)); // { dg-error "expansion of" }
|
||||
|
||||
constexpr auto c_i8_m1 = std::cw<int8_t{-1}>;
|
||||
constexpr auto c_i16_m1 = std::cw<int16_t{-1}>;
|
||||
constexpr auto c_i64_m1 = std::cw<int64_t{-1}>;
|
||||
|
||||
static_assert(test_under2(c_i8_m1, 0, 1, dyn_uexts)); // { dg-error "required from" }
|
||||
static_assert(test_under2(0, c_i16_m1, 1, dyn_uexts)); // { dg-error "required from" }
|
||||
static_assert(test_under2(0, 1, c_i64_m1, dyn_uexts)); // { dg-error "required from" }
|
||||
static_assert(test_under2(c_i8_m1, 0, 1, dyn_sexts)); // { dg-error "required from" }
|
||||
static_assert(test_under2(0, c_i16_m1, 1, dyn_sexts)); // { dg-error "required from" }
|
||||
static_assert(test_under2(0, 1, c_i64_m1, dyn_sexts)); // { dg-error "required from" }
|
||||
static_assert(test_under2(c_i8_m1, 0, 1, sta_uexts)); // { dg-error "required from" }
|
||||
static_assert(test_under2(0, c_i16_m1, 1, sta_uexts)); // { dg-error "required from" }
|
||||
static_assert(test_under2(0, 1, c_i64_m1, sta_uexts)); // { dg-error "required from" }
|
||||
static_assert(test_under2(c_i8_m1, 0, 1, sta_sexts)); // { dg-error "required from" }
|
||||
static_assert(test_under2(0, c_i16_m1, 1, sta_sexts)); // { dg-error "required from" }
|
||||
static_assert(test_under2(0, 1, c_i64_m1, sta_sexts)); // { dg-error "required from" }
|
||||
|
||||
template<typename Offset, typename Extent, typename Stride, typename Extents>
|
||||
constexpr bool
|
||||
test_over2(Offset o, Extent e, Stride s, Extents exts)
|
||||
{
|
||||
std::submdspan_canonicalize_slices(exts, std::strided_slice{o, e, s});
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr auto i8_6 = int8_t{6};
|
||||
constexpr auto c_i8_6 = std::cw<int8_t{6}>;
|
||||
constexpr auto c2 = std::cw<2>;
|
||||
constexpr auto c4 = std::cw<4>;
|
||||
|
||||
static_assert(test_over2(i8_6, 0, 1, dyn_uexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_over2(0, i8_6, 1, dyn_uexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_over2(2, 4, 0, dyn_uexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_over2(c_i8_6, 0, 1, dyn_uexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_over2(0, c_i8_6, 1, dyn_uexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_over2(c2, 4, 1, dyn_uexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_over2(2, c4, 1, dyn_uexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_over2(c2, c4, 1, dyn_uexts)); // { dg-error "expansion of" }
|
||||
|
||||
static_assert(test_over2(i8_6, 0, 1, dyn_sexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_over2(0, i8_6, 1, dyn_sexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_over2(2, 4, 0, dyn_sexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_over2(c_i8_6, 0, 1, dyn_sexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_over2(0, c_i8_6, 1, dyn_sexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_over2(c2, 4, 1, dyn_sexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_over2(2, c4, 1, dyn_sexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_over2(c2, c4, 1, dyn_sexts)); // { dg-error "expansion of" }
|
||||
|
||||
static_assert(test_over2(i8_6, 0, 1, sta_uexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_over2(0, i8_6, 1, sta_uexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_over2(2, 4, 0, sta_uexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_over2(c_i8_6, 0, 1, sta_uexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_over2(0, c_i8_6, 1, sta_uexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_over2(c2, 4, 1, sta_uexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_over2(2, c4, 1, sta_uexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_over2(c2, c4, 1, sta_uexts)); // { dg-error "expansion of" }
|
||||
|
||||
static_assert(test_over2(i8_6, 0, 1, sta_sexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_over2(0, i8_6, 1, sta_sexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_over2(2, 4, 0, sta_sexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_over2(c_i8_6, 0, 1, sta_sexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_over2(0, c_i8_6, 1, sta_sexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_over2(c2, 4, 1, sta_sexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_over2(2, c4, 1, sta_sexts)); // { dg-error "expansion of" }
|
||||
static_assert(test_over2(c2, c4, 1, sta_sexts)); // { dg-error "expansion of" }
|
||||
|
||||
// Checks the precondition: offset + extent <= exts.extent(0) for unsigned
|
||||
// index_type when offset + extent overflows.
|
||||
constexpr bool
|
||||
test_overflow1(auto o, auto e)
|
||||
{
|
||||
auto exts = std::extents<uint8_t, dyn>{255};
|
||||
auto slice = std::strided_slice{o, e, 1};
|
||||
std::submdspan_canonicalize_slices(exts, slice);
|
||||
return true;
|
||||
}
|
||||
|
||||
static_assert(test_overflow1(128, 128)); // { dg-error "expansion of" }
|
||||
static_assert(test_overflow1(std::cw<128>, 128)); // { dg-error "expansion of" }
|
||||
static_assert(test_overflow1(128, std::cw<128>)); // { dg-error "expansion of" }
|
||||
static_assert(test_overflow1(std::cw<128>, std::cw<128>)); // { dg-error "expansion of" }
|
||||
|
||||
constexpr bool
|
||||
test_overflow2(auto b, auto e)
|
||||
{
|
||||
auto exts = std::extents<uint8_t, dyn>{255};
|
||||
auto slice = std::pair{b, e};
|
||||
std::submdspan_canonicalize_slices(exts, slice);
|
||||
return true;
|
||||
}
|
||||
|
||||
static_assert(test_overflow2(5, 4)); // { dg-error "expansion of" }
|
||||
static_assert(test_overflow2(std::cw<5>, 4)); // { dg-error "expansion of" }
|
||||
static_assert(test_overflow2(5, std::cw<4>)); // { dg-error "expansion of" }
|
||||
static_assert(test_overflow2(std::cw<5>, std::cw<4>)); // { dg-error "expansion of" }
|
||||
|
||||
constexpr auto u8_4 = uint8_t{4};
|
||||
constexpr auto u8_5 = uint8_t{5};
|
||||
static_assert(test_overflow2(u8_5, u8_4)); // { dg-error "expansion of" }
|
||||
static_assert(test_overflow2(std::cw<u8_5>, u8_4)); // { dg-error "expansion of" }
|
||||
static_assert(test_overflow2(u8_5, std::cw<u8_4>)); // { dg-error "expansion of" }
|
||||
static_assert(test_overflow2(std::cw<u8_5>, std::cw<u8_4>)); // { dg-error "expansion of" }
|
||||
|
||||
constexpr bool
|
||||
test_invalid(auto e, auto s)
|
||||
{
|
||||
auto exts = std::extents(5);
|
||||
auto slice = std::strided_slice(0, e, s);
|
||||
std::submdspan_canonicalize_slices(exts, slice);
|
||||
return true;
|
||||
}
|
||||
|
||||
static_assert(test_invalid(3, 0)); // { dg-error "expansion of" }
|
||||
static_assert(test_invalid(3, std::cw<0>)); // { dg-error "expansion of" }
|
||||
static_assert(test_invalid(3, std::cw<0>)); // { dg-error "expansion of" }
|
||||
static_assert(test_invalid(std::cw<3>, std::cw<0>)); // { dg-error "expansion of" }
|
||||
|
||||
|
||||
// { dg-prune-output "static assertion failed" }
|
||||
// { dg-prune-output "__glibcxx_assert_fail" }
|
||||
// { dg-prune-output "__glibcxx_assert" }
|
||||
// { dg-prune-output "non-constant condition" }
|
||||
Loading…
Reference in New Issue