mirror of
https://github.com/openRuyi-Project/gcc.git
synced 2026-10-03 15:39:28 +00:00
libstdc++: Implement submdspan_extents. [PR110352]
Implement submdspan_extents as described in P3663 and adds it to the std module. PR libstdc++/110352 libstdc++-v3/ChangeLog: * include/std/mdspan (submdspan_extents): New function. * src/c++23/std.cc.in: Add submdspan_extents. * testsuite/23_containers/mdspan/int_like.h: Add StructuralInt. * testsuite/23_containers/mdspan/submdspan/submdspan_extents.cc: New test. * testsuite/23_containers/mdspan/submdspan/submdspan_extents_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:
committed by
Tomasz Kamiński
parent
f6f9aec0c6
commit
c915bfc0f7
@@ -865,6 +865,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
return extents<_IndexType, _Extents::static_extent(_Index)>{
|
||||
__exts.extent(_Index)};
|
||||
}
|
||||
|
||||
template<typename _IndexType, typename... _Slices>
|
||||
consteval auto
|
||||
__subrank()
|
||||
{
|
||||
return (static_cast<size_t>(!convertible_to<_Slices, _IndexType>)
|
||||
+ ... + 0);
|
||||
}
|
||||
|
||||
template<typename _IndexType, typename... _Slices>
|
||||
consteval auto
|
||||
__inv_map_rank()
|
||||
{
|
||||
constexpr auto __rank = sizeof...(_Slices);
|
||||
constexpr auto __sub_rank = __subrank<_IndexType, _Slices...>();
|
||||
auto __map = std::array<size_t, __sub_rank>{};
|
||||
auto __is_int_like = std::array<bool, __rank>{
|
||||
convertible_to<_Slices, _IndexType>...};
|
||||
|
||||
size_t __i = 0;
|
||||
for (size_t __k = 0; __k < __rank; ++__k)
|
||||
if (!__is_int_like[__k])
|
||||
__map[__i++] = __k;
|
||||
return __map;
|
||||
}
|
||||
#endif // __glibcxx_submdspan
|
||||
}
|
||||
|
||||
@@ -2664,8 +2689,86 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
};
|
||||
__impl(make_index_sequence<__rank>());
|
||||
}
|
||||
|
||||
template<typename _IndexType, size_t _Extent, typename _Slice>
|
||||
consteval size_t
|
||||
__static_slice_extent()
|
||||
{
|
||||
if constexpr (same_as<_Slice, full_extent_t>)
|
||||
return _Extent;
|
||||
else if constexpr (same_as<_Slice, constant_wrapper<_IndexType(0)>>)
|
||||
return 0;
|
||||
else if constexpr (__is_constant_wrapper<typename _Slice::extent_type>
|
||||
&& __is_constant_wrapper<typename _Slice::stride_type>)
|
||||
return 1 + ((typename _Slice::extent_type{}) - 1)
|
||||
/ (typename _Slice::stride_type{});
|
||||
else
|
||||
return dynamic_extent;
|
||||
}
|
||||
|
||||
template<size_t _K, typename _Extents, typename _Slice>
|
||||
constexpr typename _Extents::index_type
|
||||
__dynamic_slice_extent(const _Extents& __exts, _Slice __slice)
|
||||
{
|
||||
if constexpr (__is_strided_slice<_Slice>)
|
||||
return __slice.extent == 0 ? 0 : 1 + (__slice.extent - 1) / __slice.stride;
|
||||
else
|
||||
return __exts.extent(_K);
|
||||
}
|
||||
|
||||
template<typename _IndexType, size_t... _Extents, typename... _Slices>
|
||||
requires (sizeof...(_Slices) == sizeof...(_Extents))
|
||||
constexpr auto
|
||||
__subextents(const extents<_IndexType, _Extents...>& __exts,
|
||||
_Slices... __slices)
|
||||
{
|
||||
constexpr auto __inv_map = __mdspan::__inv_map_rank<_IndexType, _Slices...>();
|
||||
auto __impl = [&]<size_t... _Indices>(index_sequence<_Indices...>)
|
||||
{
|
||||
using _SubExtents = extents<_IndexType,
|
||||
(__mdspan::__static_slice_extent<_IndexType,
|
||||
_Extents...[__inv_map[_Indices]],
|
||||
_Slices...[__inv_map[_Indices]]>())...>;
|
||||
if constexpr (_SubExtents::rank_dynamic() == 0)
|
||||
return _SubExtents{};
|
||||
else
|
||||
{
|
||||
using _StaticSubExtents = __mdspan::_StaticExtents<
|
||||
__mdspan::__static_extents<_SubExtents>()>;
|
||||
auto __create = [&]<size_t... _Is>(index_sequence<_Is...>)
|
||||
{
|
||||
constexpr auto __slice_idx = [__inv_map](size_t __i) consteval
|
||||
{
|
||||
return __inv_map[_StaticSubExtents::_S_dynamic_index_inv(__i)];
|
||||
};
|
||||
|
||||
return _SubExtents{
|
||||
(__mdspan::__dynamic_slice_extent<__slice_idx(_Is)>(
|
||||
__exts, __slices...[__slice_idx(_Is)]))...};
|
||||
};
|
||||
constexpr auto __dyn_subrank = _SubExtents::rank_dynamic();
|
||||
return __create(make_index_sequence<__dyn_subrank>());
|
||||
}
|
||||
};
|
||||
|
||||
return __impl(make_index_sequence<__inv_map.size()>());
|
||||
}
|
||||
}
|
||||
|
||||
template<typename _IndexType, size_t... _Extents, typename... _RawSlices>
|
||||
requires (sizeof...(_RawSlices) == sizeof...(_Extents))
|
||||
constexpr auto
|
||||
submdspan_extents(const extents<_IndexType, _Extents...>& __exts,
|
||||
_RawSlices... __raw_slices)
|
||||
{
|
||||
auto __impl = [&__exts](auto... __slices)
|
||||
{
|
||||
__mdspan::__check_valid_slices(__exts, __slices...);
|
||||
return __mdspan::__subextents(__exts, __slices...);
|
||||
};
|
||||
return __impl(__mdspan::__slice_cast<_IndexType>(__raw_slices)...);
|
||||
}
|
||||
|
||||
template<typename _IndexType, size_t... _Extents, typename... _RawSlices>
|
||||
requires (sizeof...(_Extents) == sizeof...(_RawSlices))
|
||||
constexpr auto
|
||||
|
||||
@@ -1877,13 +1877,16 @@ export namespace std
|
||||
#if __glibcxx_padded_layouts
|
||||
using std::layout_left_padded;
|
||||
using std::layout_right_padded;
|
||||
#endif
|
||||
#if __glibcxx_submdspan
|
||||
using std::strided_slice;
|
||||
using std::full_extent_t;
|
||||
using std::full_extent;
|
||||
using std::submdspan_mapping_result;
|
||||
using std::submdspan_canonicalize_slices;
|
||||
using std::submdspan_extents;
|
||||
#endif
|
||||
// FIXME submdspan_extents, mdsubspan
|
||||
// FIXME mdsubspan
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -69,4 +69,13 @@ using RValueInt = CustomIndexType<CustomIndexKind::RValue>;
|
||||
struct NotIntLike
|
||||
{ };
|
||||
|
||||
struct StructuralInt
|
||||
{
|
||||
constexpr
|
||||
operator int() const noexcept
|
||||
{ return value; }
|
||||
|
||||
int value;
|
||||
};
|
||||
|
||||
#endif // TEST_MDSPAN_INT_LIKE_H
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
// { dg-do run { target c++26 } }
|
||||
#include <mdspan>
|
||||
|
||||
#include "../int_like.h"
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
constexpr size_t dyn = std::dynamic_extent;
|
||||
constexpr auto all = std::full_extent;
|
||||
|
||||
constexpr bool
|
||||
test_from_full_extent()
|
||||
{
|
||||
auto exts = std::extents<int, 3, dyn, 7>{};
|
||||
auto sub_exts = submdspan_extents(exts, 1, all, all);
|
||||
VERIFY(sub_exts.rank() == 2);
|
||||
VERIFY(sub_exts.static_extent(0) == dyn);
|
||||
VERIFY(sub_exts.extent(0) == exts.extent(1));
|
||||
VERIFY(std::cmp_equal(sub_exts.static_extent(1), exts.extent(2)));
|
||||
return true;
|
||||
}
|
||||
|
||||
template<template<typename, typename> typename Pair, template<int> typename Cw>
|
||||
constexpr bool
|
||||
test_from_tuple()
|
||||
{
|
||||
auto exts = std::extents<int, 3, 5, 7>{};
|
||||
auto s0 = Cw<1>{};
|
||||
auto s1 = Pair{Cw<1>{}, Cw<2>{}};
|
||||
auto s2 = Pair{Cw<1>{}, 4};
|
||||
auto sub_exts = submdspan_extents(exts, s0, s1, s2);
|
||||
VERIFY(sub_exts.rank() == 2);
|
||||
VERIFY(sub_exts.static_extent(0) == size_t(get<1>(s1) - get<0>(s1)));
|
||||
VERIFY(sub_exts.static_extent(1) == dyn);
|
||||
VERIFY(std::cmp_equal(sub_exts.extent(1), get<1>(s2) - get<0>(s2)));
|
||||
return true;
|
||||
}
|
||||
|
||||
template<template<int> typename Cw>
|
||||
constexpr bool
|
||||
test_from_tuple_all()
|
||||
{
|
||||
test_from_tuple<std::tuple, Cw>();
|
||||
test_from_tuple<std::pair, Cw>();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template<typename Int>
|
||||
void
|
||||
test_from_int_like_as_scalar()
|
||||
{
|
||||
auto exts = std::extents<int, 3, 5>{};
|
||||
auto sub_exts = submdspan_extents(exts, Int(1), std::tuple{1, 3});
|
||||
VERIFY(sub_exts.rank() == 1);
|
||||
VERIFY(sub_exts.static_extent(0) == dyn);
|
||||
VERIFY(sub_exts.extent(0) == 2);
|
||||
}
|
||||
|
||||
template<template<int> typename Cw>
|
||||
constexpr bool
|
||||
test_from_const_int()
|
||||
{
|
||||
auto exts = std::extents<int, 3, 5>{};
|
||||
auto sub_exts = submdspan_extents(exts, Cw<1>{}, std::tuple{1, 3});
|
||||
VERIFY(sub_exts.rank() == 1);
|
||||
VERIFY(sub_exts.static_extent(0) == dyn);
|
||||
VERIFY(sub_exts.extent(0) == 2);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename Int>
|
||||
constexpr bool
|
||||
test_from_int_like_in_tuple()
|
||||
{
|
||||
auto exts = std::extents<int, 3, 5>{};
|
||||
auto sub_exts = submdspan_extents(exts, Int(1), std::tuple{Int(1), Int(3)});
|
||||
VERIFY(sub_exts.rank() == 1);
|
||||
VERIFY(sub_exts.static_extent(0) == dyn);
|
||||
VERIFY(sub_exts.extent(0) == 2);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<template<int> typename Cw>
|
||||
constexpr bool
|
||||
test_from_strided_slice()
|
||||
{
|
||||
auto exts = std::extents<int, 5, 7, 11>{};
|
||||
{
|
||||
auto s0 = 1;
|
||||
auto s1 = std::strided_slice{0, 0, 0};
|
||||
auto s2 = std::strided_slice{1, Cw<0>{}, 0};
|
||||
auto sub_exts = submdspan_extents(exts, s0, s1, s2);
|
||||
VERIFY(sub_exts.rank() == 2);
|
||||
VERIFY(sub_exts.static_extent(0) == dyn);
|
||||
VERIFY(sub_exts.extent(0) == 0);
|
||||
VERIFY(sub_exts.static_extent(1) == 0);
|
||||
}
|
||||
|
||||
{
|
||||
auto s0 = 1;
|
||||
auto s1 = std::strided_slice{0, 2, Cw<1>{}};
|
||||
auto s2 = std::strided_slice{1, Cw<2>{}, 1};
|
||||
auto sub_exts = submdspan_extents(exts, s0, s1, s2);
|
||||
VERIFY(sub_exts.rank() == 2);
|
||||
VERIFY(sub_exts.static_extent(0) == dyn);
|
||||
VERIFY(sub_exts.extent(0) == 2);
|
||||
VERIFY(sub_exts.static_extent(1) == dyn);
|
||||
VERIFY(sub_exts.extent(1) == 2);
|
||||
}
|
||||
|
||||
{
|
||||
// selected = 1 x [1, 3] x [1, 4, 7, 10]
|
||||
auto s0 = 1;
|
||||
auto s1 = std::strided_slice{1, Cw<4>{}, 2};
|
||||
auto s2 = std::strided_slice{1, Cw<10>{}, Cw<3>{}};
|
||||
auto sub_exts = submdspan_extents(exts, s0, s1, s2);
|
||||
VERIFY(sub_exts.rank() == 2);
|
||||
VERIFY(sub_exts.static_extent(0) == dyn);
|
||||
VERIFY(sub_exts.extent(0) == 2);
|
||||
VERIFY(sub_exts.static_extent(1) == 4);
|
||||
}
|
||||
|
||||
{
|
||||
// selected = [0, 2] x [1, 3] x [0, 3, 6]
|
||||
auto s0 = std::strided_slice(0, 3, 2);
|
||||
auto s1 = std::strided_slice(1, 4, 2);
|
||||
auto s2 = std::strided_slice(0, 7, 3);
|
||||
auto sub_exts = submdspan_extents(exts, s0, s1, s2);
|
||||
VERIFY(sub_exts.rank() == 3);
|
||||
VERIFY(sub_exts.extent(0) == 2);
|
||||
VERIFY(sub_exts.extent(1) == 2);
|
||||
VERIFY(sub_exts.extent(2) == 3);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<int Value>
|
||||
using CW = std::constant_wrapper<Value, int>;
|
||||
|
||||
template<int Value>
|
||||
using IC = std::integral_constant<int, Value>;
|
||||
|
||||
constexpr bool
|
||||
test_all()
|
||||
{
|
||||
test_from_full_extent();
|
||||
test_from_tuple_all<CW>();
|
||||
test_from_tuple_all<IC>();
|
||||
test_from_const_int<CW>();
|
||||
test_from_const_int<IC>();
|
||||
test_from_strided_slice<CW>();
|
||||
test_from_strided_slice<IC>();
|
||||
test_from_int_like_in_tuple<StructuralInt>();
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
test_all();
|
||||
static_assert(test_all());
|
||||
|
||||
test_from_int_like_as_scalar<CustomIndexType<CustomIndexKind::Const, true>>();
|
||||
test_from_int_like_as_scalar<CustomIndexType<CustomIndexKind::Throwing, true>>();
|
||||
test_from_int_like_as_scalar<CustomIndexType<CustomIndexKind::Mutating, true>>();
|
||||
test_from_int_like_as_scalar<CustomIndexType<CustomIndexKind::RValue, true>>();
|
||||
test_from_int_like_as_scalar<StructuralInt>();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// { dg-do compile { target c++26 } }
|
||||
#include <mdspan>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
struct NotASlice
|
||||
{ };
|
||||
|
||||
constexpr bool
|
||||
test_unrelated_stride_type()
|
||||
{
|
||||
auto exts = std::extents(3, 5, 7);
|
||||
auto sub_exts = submdspan_extents(exts, 1, NotASlice{}, 2); // { dg-error "required from" }
|
||||
return true;
|
||||
}
|
||||
static_assert(test_unrelated_stride_type());
|
||||
|
||||
constexpr bool
|
||||
test_invalid_stride_zero()
|
||||
{
|
||||
auto exts = std::extents(3, 5, 7);
|
||||
auto s = std::strided_slice{0, 1, 0};
|
||||
auto sub_exts = submdspan_extents(exts, 1, s, 2); // { dg-error "expansion of" }
|
||||
return true;
|
||||
}
|
||||
static_assert(test_invalid_stride_zero());
|
||||
|
||||
template<typename Slice>
|
||||
constexpr bool
|
||||
test_out_of_bounds(const Slice& slice)
|
||||
{
|
||||
auto exts = std::extents<uint16_t, 3, 5, 7>{};
|
||||
auto sub_exts = submdspan_extents(exts, 1, slice, 2); // { dg-error "expansion of" }
|
||||
return true;
|
||||
}
|
||||
static_assert(test_out_of_bounds(std::strided_slice{0, 6, 1})); // { dg-error "expansion of" }
|
||||
static_assert(test_out_of_bounds(std::strided_slice{0, 7, 2})); // { dg-error "expansion of" }
|
||||
static_assert(test_out_of_bounds(std::strided_slice{1, 6, 1})); // { dg-error "expansion of" }
|
||||
static_assert(test_out_of_bounds(std::strided_slice{1, 6, 2})); // { dg-error "expansion of" }
|
||||
static_assert(test_out_of_bounds(std::tuple{1, 6})); // { dg-error "expansion of" }
|
||||
static_assert(test_out_of_bounds(std::tuple{std::cw<1>, std::cw<6>})); // { dg-error "expansion of" }
|
||||
static_assert(test_out_of_bounds(std::strided_slice{-1, 2, 1})); // { dg-error "expansion of" }
|
||||
static_assert(test_out_of_bounds(std::tuple{-1, 2})); // { dg-error "expansion of" }
|
||||
|
||||
// { dg-prune-output "cannot decompose class type 'NotASlice'" }
|
||||
// { dg-prune-output "static assertion failed" }
|
||||
// { dg-prune-output "__glibcxx_assert_fail" }
|
||||
// { dg-prune-output "non-constant condition" }
|
||||
Reference in New Issue
Block a user