blob: 33d6f947f0bcc4e800a6be53573e36e11d979949 [file] [log] [blame]
// { dg-do run { target c++23 } }
#include <mdspan>
#include <cstdint>
#include <testsuite_hooks.h>
constexpr size_t dyn = std::dynamic_extent;
// Check class traits.
static_assert(std::regular<std::extents<int>>);
static_assert(std::regular<std::extents<int, 1>>);
static_assert(std::regular<std::extents<int, dyn>>);
static_assert(std::is_trivially_copyable_v<std::extents<int>>);
static_assert(std::is_trivially_copyable_v<std::extents<int, 1>>);
static_assert(std::is_trivially_copyable_v<std::extents<int, dyn>>);
// Check member typedefs.
static_assert(std::is_same_v<std::extents<int, 1, 2>::rank_type, size_t>);
static_assert(std::is_unsigned_v<std::extents<int, 2>::size_type>);
static_assert(std::is_unsigned_v<std::extents<unsigned int, 2>::size_type>);
static_assert(std::is_same_v<std::extents<int, 2>::index_type, int>);
static_assert(std::is_same_v<std::extents<unsigned int, 2>::index_type,
unsigned int>);
// Check `rank`.
static_assert(std::extents<int, 1>::rank() == 1);
static_assert(std::extents<int, dyn>::rank() == 1);
static_assert(std::extents<int, 2, dyn>::rank() == 2);
// Check `rank_dynamic`.
static_assert(std::extents<int, 1>::rank_dynamic() == 0);
static_assert(std::extents<int, dyn>::rank_dynamic() == 1);
static_assert(std::extents<int, 2, dyn>::rank_dynamic() == 1);
static_assert(std::extents<int, dyn, dyn>::rank_dynamic() == 2);
template<typename T, size_t... Extents>
constexpr bool
check_rank_return_types()
{
auto e = std::extents<T, Extents...>();
return std::is_same_v<decltype(e.rank()), size_t>
&& std::is_same_v<decltype(e.rank_dynamic()), size_t>;
}
static_assert(check_rank_return_types<int, 1>());
// Check that the static extents don't take up space.
static_assert(sizeof(std::extents<int, 1, dyn>) == sizeof(int));
static_assert(sizeof(std::extents<short, 1, dyn>) == sizeof(short));
template<typename Extents>
class Container
{
int dummy;
[[no_unique_address]] std::extents<size_t> b0;
};
static_assert(sizeof(Container<std::extents<short, 1, 2>>) == sizeof(int));
static_assert(sizeof(Container<std::extents<size_t, 1, 2>>) == sizeof(int));
// operator=
static_assert(std::is_nothrow_assignable_v<std::extents<int, dyn, 2>,
std::extents<int, 1, 2>>);
constexpr bool
test_assign()
{
auto e1 = std::extents<int, 1, 2>();
auto e2 = std::extents<int, 1, 2>();
e2 = e1;
VERIFY(e2 == e1);
auto e5 = std::extents<int, 1, dyn>();
e5 = e1;
VERIFY(e5 == e1);
auto e3 = std::extents<int, dyn, dyn>(1, 2);
auto e4 = std::extents<int, dyn, dyn>(3, 4);
e3 = e4;
VERIFY(e3 == e4);
return true;
}
// Deduction guide
template<size_t Rank, typename... Extents>
constexpr void
test_deduction(Extents... exts)
{
std::array<size_t, sizeof...(exts)> shape{static_cast<size_t>(exts)...};
std::dextents<size_t, Rank> expected(shape);
std::extents e(exts...);
static_assert(std::is_same_v<decltype(e), std::dextents<size_t, Rank>>);
VERIFY(e == expected);
}
constexpr bool
test_deduction_from_constant()
{
auto verify = [](auto actual, auto expected)
{
static_assert(std::same_as<decltype(actual), decltype(expected)>);
VERIFY(actual == expected);
};
constexpr auto i1 = std::integral_constant<size_t, 1>{};
constexpr auto i2 = std::integral_constant<int, 2>{};
verify(std::extents(1), std::extents<size_t, dyn>{1});
verify(std::extents(i1), std::extents<size_t, 1>{});
verify(std::extents(i2), std::extents<size_t, 2>{});
verify(std::extents(std::true_type{}, 2), std::dextents<size_t, 2>{1, 2});
verify(std::extents(std::false_type{}, 2), std::dextents<size_t, 2>{0, 2});
#if __glibcxx_constant_wrapper
constexpr auto c2 = std::constant_wrapper<2>{};
verify(std::extents(c2), std::extents<size_t, 2>{});
verify(std::extents(1, c2), std::extents<size_t, dyn, 2>{1});
verify(std::extents(c2), std::extents<size_t, 2>{});
verify(std::extents(1, c2), std::extents<size_t, dyn, 2>{1});
verify(std::extents(std::cw<true>, c2), std::extents<size_t, dyn, 2>{1});
#endif
return true;
}
constexpr bool
test_deduction_all()
{
test_deduction<0>();
test_deduction<1>(1);
test_deduction<2>(1.0, 2.0f);
test_deduction<3>(int(1), short(2), size_t(3));
test_deduction_from_constant();
return true;
}
class A {};
template<typename... Extents>
concept deducible = requires
{
{ std::extents(Extents{}...) }
-> std::convertible_to<std::dextents<size_t, sizeof...(Extents)>>;
};
static_assert(deducible<int>);
static_assert(!deducible<A, A>);
// dextents
static_assert(std::is_same_v<std::dextents<int, 0>, std::extents<int>>);
static_assert(std::is_same_v<std::dextents<int, 1>, std::extents<int, dyn>>);
static_assert(std::is_same_v<std::dextents<int, 5>,
std::extents<int, dyn, dyn, dyn, dyn, dyn>>);
static_assert(std::dextents<int, 5>::rank() == 5);
static_assert(std::dextents<int, 5>::rank_dynamic() == 5);
static_assert(std::is_same_v<typename std::dextents<int, 5>::index_type, int>);
// static_extent
static_assert(std::extents<int, 1, 2>::static_extent(0) == 1);
static_assert(std::extents<int, 1, 2>::static_extent(1) == 2);
static_assert(std::extents<int, 1, dyn>::static_extent(0) == 1);
static_assert(std::extents<int, 1, dyn>::static_extent(1) == dyn);
static_assert(std::extents<int, dyn, dyn>::static_extent(0) == dyn);
static_assert(std::extents<int, dyn, dyn>::static_extent(1) == dyn);
// dims
#if __glibcxx_mdspan >= 202406L
static_assert(std::is_same_v<std::dims<0>, std::dextents<size_t, 0>>);
static_assert(std::is_same_v<std::dims<3>, std::dextents<size_t, 3>>);
static_assert(std::is_same_v<std::dims<3, int>, std::dextents<int, 3>>);
#endif
// extent
template<typename Extent>
constexpr void
test_extent(const Extent& e,
const std::array<typename Extent::index_type, Extent::rank()>& shape)
{
for(size_t i = 0; i < e.rank(); ++i)
VERIFY(e.extent(i) == shape[i]);
}
constexpr bool
test_extent_all()
{
test_extent(std::extents<int, 1, 2>{}, {1, 2});
test_extent(std::extents<int, 1, dyn>{2}, {1, 2});
test_extent(std::extents<int, dyn, dyn>{1, 2}, {1, 2});
return true;
}
// operator==
template<typename Lhs, typename Rhs>
constexpr void
test_ops_eq(const Lhs& lhs, const Rhs& rhs, bool expected)
{
VERIFY((lhs == rhs) == expected);
VERIFY((lhs != rhs) == !expected);
}
constexpr void
test_op_eq_rank_zero()
{
auto e1 = std::extents<int>();
auto e2 = std::extents<int>();
auto e3 = std::extents<unsigned int>();
test_ops_eq(e1, e2, true);
test_ops_eq(e1, e3, true);
}
constexpr void
test_op_eq_common()
{
auto e1 = std::extents<int, 1, 2, 3>();
auto e2 = std::extents<int, 1, 2, 3>();
auto e3 = std::extents<int, 1, dyn, 3>(2);
auto e4 = std::extents<int, 1, dyn, 3>(3);
auto e5 = std::extents<int, 1>();
auto e6 = std::extents<int, 1, 3, 3>();
test_ops_eq(e1, e2, true);
test_ops_eq(e1, e3, true);
test_ops_eq(e1, e4, false);
test_ops_eq(e1, e5, false);
test_ops_eq(e1, e6, false);
test_ops_eq(e3, e6, false);
}
constexpr bool
test_op_eq_all()
{
test_op_eq_rank_zero();
test_op_eq_common();
return true;
}
int
main()
{
test_assign();
static_assert(test_assign());
test_deduction_all();
static_assert(test_deduction_all());
test_extent_all();
static_assert(test_extent_all());
test_op_eq_all();
static_assert(test_op_eq_all());
return 0;
}