blob: 8d2fad2936f67278b26ccb3eecf000e6e1611d6d [file] [log] [blame]
// { dg-do run { target c++23 } }
#include <mdspan>
#include "../int_like.h"
#include <testsuite_hooks.h>
constexpr size_t dyn = std::dynamic_extent;
template<typename MappingStride>
constexpr void
test_ctor_default_stride()
{
using Extents = typename MappingStride::extents_type;
MappingStride actual;
typename std::layout_right::mapping<Extents> expected;
constexpr auto rank = MappingStride::extents_type::rank();
if constexpr (rank > 0)
for(size_t i = 0; i < rank; ++i)
VERIFY(actual.stride(i) == expected.stride(i));
}
constexpr bool
test_ctor_default_stride_all()
{
test_ctor_default_stride<
std::layout_stride::mapping<std::extents<int, 3>>>();
test_ctor_default_stride<
std::layout_stride::mapping<std::extents<int, 3, 5, 7>>>();
test_ctor_default_stride<
std::layout_stride::mapping<std::dextents<int, 3>>>();
test_ctor_default_stride<
std::layout_stride::mapping<std::extents<int, 0, 5, 7>>>();
test_ctor_default_stride<
std::layout_stride::mapping<std::extents<int, 3, dyn, dyn>>>();
test_ctor_default_stride<
std::layout_stride::mapping<std::extents<int, dyn, dyn, 3>>>();
return true;
}
template<typename E, typename E_arg, typename T, size_t N, bool Expected>
constexpr void
test_stride_constructible()
{
static_assert(std::is_nothrow_constructible_v<
std::layout_stride::mapping<E>, E_arg, std::span<T, N>> == Expected);
static_assert(std::is_nothrow_constructible_v<
std::layout_stride::mapping<E>, E_arg, std::array<T, N>> == Expected);
static_assert(!std::is_constructible_v<std::layout_stride::mapping<E>,
E_arg>);
}
constexpr void
test_stride_constructible_all()
{
using E0 = std::extents<int>;
using E1 = std::extents<int, 2>;
using E2 = std::extents<int, dyn>;
test_stride_constructible<E0, E0, int, 0, true>();
test_stride_constructible<E0, E0, IntLike, 0, true>();
test_stride_constructible<E0, E0, ThrowingInt, 0, false>();
test_stride_constructible<E0, E0, MutatingInt, 0, false>();
test_stride_constructible<E0, E0, NotIntLike, 0, false>();
test_stride_constructible<E1, E1, int, 1, true>();
test_stride_constructible<E2, E1, int, 1, true>();
test_stride_constructible<E1, E1, int, 2, false>();
test_stride_constructible<E1, E0, int, 1, false>();
}
template<typename Extents, typename Shape>
constexpr void
test_ctor_shape_strides(Extents exts, Shape strides)
{
using M = std::layout_stride::mapping<Extents>;
M m(exts, strides);
if constexpr (Extents::rank() > 0)
for(size_t i = 0; i < exts.rank(); ++i)
{
VERIFY(m.stride(i) == strides[i]);
VERIFY(m.extents().extent(i) == exts.extent(i));
}
}
constexpr bool
test_ctor_shape_stride_all()
{
test_ctor_shape_strides(std::extents<int>{}, std::array<int, 0>{});
test_ctor_shape_strides(std::extents<int, 2>{}, std::array<int, 1>{3});
test_ctor_shape_strides(std::extents<int, 2, 4, 6>{},
std::array<int, 3>{20, 5, 45});
return true;
}
template<typename Extents, std::array<bool, 2> Strided,
std::array<bool, 2> Unique, std::array<bool, 2> Exhautive,
typename Extents::index_type Offset = 0>
struct MappingLike
{
using extents_type = Extents;
using index_type = typename Extents::index_type;
constexpr
MappingLike(extents_type extents,
std::array<index_type, Extents::rank()> strides)
: _extents(extents), _strides(strides)
{ }
static constexpr bool
is_always_strided() requires (Strided[0])
{ return Strided[1]; }
static constexpr bool
is_always_unique() requires (Unique[0])
{ return Unique[1]; }
static constexpr bool
is_always_exhaustive() requires (Exhautive[0])
{ return Exhautive[1]; }
constexpr Extents
extents() const { return _extents; }
constexpr index_type
stride(size_t i) const { return _strides[i]; }
template<typename... Indices>
constexpr index_type
operator()(Indices... indices) const
{
if (empty())
VERIFY(false);
std::array<index_type, Extents::rank()> ind_arr{indices...};
index_type ret = Offset;
for(size_t i = 0; i < Extents::rank(); ++i)
ret += ind_arr[i]*_strides[i];
return ret;
}
private:
constexpr bool
empty() const
{
for (size_t i = 0; i < extents_type::rank(); ++i)
if (_extents.extent(i) == 0)
return true;
return false;
}
Extents _extents;
std::array<index_type, Extents::rank()> _strides;
};
template<size_t Rank>
struct ExtentLike
{
using index_type = int;
static constexpr size_t
rank() { return Rank; }
};
template<typename E1>
constexpr void
test_mapping_like_constructible()
{
using M = std::layout_stride::mapping<E1>;
using E2 = std::dextents<typename E1::index_type, E1::rank()>;
using E3 = std::dextents<typename E1::index_type, E1::rank() + 1>;
using E4 = ExtentLike<E1::rank()>;
constexpr auto TT = std::array{true, true};
constexpr auto FT = std::array{false, true};
constexpr auto TF = std::array{true, false};
static_assert(std::is_constructible_v<M, MappingLike<E1, TT, TT, TT>>);
static_assert(std::is_constructible_v<M, MappingLike<E2, TT, TT, TT>>);
static_assert(!std::is_constructible_v<M, MappingLike<E3, TT, TT, TT>>);
static_assert(!std::is_constructible_v<M, MappingLike<E1, FT, TT, TT>>);
static_assert(!std::is_constructible_v<M, MappingLike<E1, TF, TT, TT>>);
static_assert(!std::is_constructible_v<M, MappingLike<E1, TT, FT, TT>>);
static_assert(!std::is_constructible_v<M, MappingLike<E1, TT, TF, TT>>);
static_assert(!std::is_constructible_v<M, MappingLike<E1, TT, TT, FT>>);
static_assert(std::is_constructible_v<M, MappingLike<E1, TT, TT, TF>>);
static_assert(!std::is_constructible_v<M, MappingLike<E4, TT, TT, TF>>);
static_assert(!std::is_constructible_v<M, MappingLike<E4, TT, TT, TT>>);
}
constexpr void
test_mapping_like_constructible_all()
{
test_mapping_like_constructible<std::extents<int>>();
test_mapping_like_constructible<std::extents<int, 2>>();
test_mapping_like_constructible<std::extents<int, 2, 3>>();
}
template<typename E1, typename E2>
constexpr void
test_mapping_like_convertible()
{
using M1 = std::layout_stride::mapping<E1>;
using M2 = std::layout_stride::mapping<E2>;
constexpr auto TT = std::array{true, true};
static_assert(!std::is_convertible_v<MappingLike<E1, TT, TT, TT>, M1>);
static_assert(!std::is_convertible_v<MappingLike<E2, TT, TT, TT>, M1>);
static_assert(!std::is_convertible_v<MappingLike<E1, TT, TT, TT>, M2>);
static_assert(std::is_convertible_v<std::layout_stride::mapping<E2>, M1>);
static_assert(std::is_convertible_v<std::layout_left::mapping<E2>, M1>);
static_assert(std::is_convertible_v<std::layout_right::mapping<E2>, M1>);
static_assert(!std::is_convertible_v<std::layout_stride::mapping<E1>, M2>);
static_assert(!std::is_convertible_v<std::layout_left::mapping<E1>, M2>);
static_assert(!std::is_convertible_v<std::layout_right::mapping<E1>, M2>);
}
constexpr void
test_mapping_like_convertible_all()
{
test_mapping_like_convertible<std::extents<unsigned int>,
std::extents<int>>();
test_mapping_like_convertible<std::extents<unsigned int, 2>,
std::extents<int, 2>>();
test_mapping_like_convertible<std::extents<int, dyn, 3>,
std::extents<int, 2, 3>>();
}
template<typename Extents>
constexpr void
test_ctor_stride_like(Extents exts, std::array<int, Extents::rank()> strides)
{
auto other_right = std::layout_right::mapping(exts);
auto other_left = std::layout_left::mapping(exts);
auto other_stride = std::layout_stride::mapping(exts, strides);
VERIFY(std::layout_stride::mapping<Extents>(other_right) == other_right);
VERIFY(std::layout_stride::mapping<Extents>(other_left) == other_left);
VERIFY(std::layout_stride::mapping<Extents>(other_stride) == other_stride);
}
constexpr void
test_ctor_stride_like_all()
{
using E1 = std::extents<int>;
auto s1 = std::array<int, 0>{};
test_ctor_stride_like(E1{}, s1);
using E2 = std::extents<int, 3>;
auto s2 = std::array<int, 1>{2};
test_ctor_stride_like(E2{}, s2);
using E3 = std::extents<int, 3, 5, 7>;
auto s3 = std::array<int, 3>{5, 1, 15};
test_ctor_stride_like(E3{}, s3);
}
constexpr bool
test_ctor_strides_all()
{
test_ctor_default_stride_all();
test_ctor_shape_stride_all();
test_ctor_stride_like_all();
return true;
}
// Check is_exhaustive.
template<typename Extents, typename Strides>
constexpr void
test_is_exhaustive(Extents extents, Strides strides, bool expected)
{
std::layout_stride::mapping<Extents> m(extents, strides);
VERIFY(m.is_exhaustive() == expected);
bool always_exhaustive = extents.rank() == 0 || m.required_span_size() == 0;
VERIFY(m.is_always_exhaustive() == always_exhaustive);
}
constexpr void
test_is_exhaustive_zero_1d()
{
std::extents<int, 0> extents;
test_is_exhaustive(extents, std::array{1}, true);
test_is_exhaustive(extents, std::array{2}, true);
}
constexpr void
test_is_exhaustive_zero_3d()
{
std::extents<int, 3, 0, 7> extents;
test_is_exhaustive(extents, std::array{1, 1, 1}, true);
test_is_exhaustive(extents, std::array{1, 2*21, 2*3}, true);
test_is_exhaustive(extents, std::array{7, 2*21, 1}, true);
test_is_exhaustive(extents, std::array{1, 21, 3}, true);
test_is_exhaustive(extents, std::array{7, 21, 1}, true);
}
constexpr void
test_is_exhaustive_0d()
{
std::extents<int> extents;
test_is_exhaustive(extents, std::array<int, 0>{}, true);
}
constexpr void
test_is_exhaustive_1d()
{
std::extents<int, 3> extents;
test_is_exhaustive(extents, std::array{1}, true);
test_is_exhaustive(extents, std::array{3}, false);
}
constexpr void
test_is_exhaustive_3d()
{
std::extents<int, 3, dyn, 7> extents(5);
test_is_exhaustive(extents, std::array{1, 3, 3*5}, true);
test_is_exhaustive(extents, std::array{5*7, 1, 5}, true);
test_is_exhaustive(extents, std::array{7, 3*7, 1}, true);
test_is_exhaustive(extents, std::array{1, 3, 2*3*5}, false);
test_is_exhaustive(extents, std::array{2*5*7, 1, 2*5}, false);
test_is_exhaustive(extents, std::array{2*7, 2*3*7, 2}, false);
}
constexpr void
test_is_exhaustive_ones()
{
std::extents<int, 1, 1, 3, 1> extents;
test_is_exhaustive(extents, std::array{1, 1, 1, 1}, true);
test_is_exhaustive(extents, std::array{1, 1, 1, 3}, true);
test_is_exhaustive(extents, std::array{3, 3, 1, 3}, true);
test_is_exhaustive(extents, std::array{3, 1, 1, 3}, true);
}
constexpr bool
test_is_exhaustive_all()
{
test_is_exhaustive_zero_1d();
test_is_exhaustive_zero_3d();
test_is_exhaustive_ones();
test_is_exhaustive_0d();
test_is_exhaustive_1d();
test_is_exhaustive_3d();
return true;
}
template<typename Extents, int Offset>
using OffsetMapping = MappingLike<Extents, {true, true}, {true, true},
{true, false}, Offset>;
template<typename Extents>
constexpr void
test_eq(Extents exts,
std::array<typename Extents::index_type, Extents::rank()> left_strides,
std::array<typename Extents::index_type, Extents::rank()> right_strides,
std::array<typename Extents::index_type, Extents::rank()> padded_strides)
{
using DExtents = std::dextents<int, Extents::rank()>;
std::layout_left::mapping<Extents> ml;
std::layout_right::mapping<DExtents> mr(exts);
std::layout_stride::mapping<Extents> msd;
std::layout_stride::mapping<Extents> msl(exts, left_strides);
std::layout_stride::mapping<Extents> msr(exts, right_strides);
std::layout_stride::mapping<Extents> msp(exts, padded_strides);
OffsetMapping<Extents, 0> mor{exts, right_strides};
OffsetMapping<Extents, 0> mol{exts, left_strides};
OffsetMapping<Extents, 0> mop{exts, padded_strides};
OffsetMapping<Extents, 1> moo{exts, right_strides};
VERIFY(msd == mr);
VERIFY(msd == mor);
VERIFY(msd != msp);
VERIFY(msd != mop);
VERIFY(msl == ml);
VERIFY(msl == mol);
VERIFY(msd != msp);
VERIFY(msl != mop);
VERIFY(msp == mop);
VERIFY(msp != ml);
VERIFY(msp != mr);
VERIFY(msd != moo);
}
constexpr void
test_eq_0d()
{
using Extents = std::extents<int>;
Extents exts;
std::layout_left::mapping<Extents> ml;
std::layout_right::mapping<Extents> mr;
std::layout_stride::mapping<Extents> ms;
OffsetMapping<Extents, 0> mor{exts, {}};
OffsetMapping<Extents, 1> moo{exts, {}};
VERIFY(ms == ml);
VERIFY(ms == mr);
VERIFY(ms == mor);
VERIFY(ms != moo);
}
constexpr void
test_eq_1d()
{
using Extents = std::extents<int, 2>;
auto exhaustive_strides = std::array{1};
auto padded_strides = std::array{2};
test_eq(Extents{}, exhaustive_strides, exhaustive_strides, padded_strides);
}
constexpr void
test_eq_2d()
{
using Extents = std::extents<int, 1, 2>;
auto left_strides = std::array{1, 1};
auto right_strides = std::array{2, 1};
auto padded_strides = std::array{2, 8};
test_eq(Extents{}, left_strides, right_strides, padded_strides);
}
constexpr void
test_eq_zero()
{
using Extents = std::extents<int, 0, 2>;
using Mapping = std::layout_stride::mapping<Extents>;
Extents exts;
std::array<int, 2> sl{1, 5};
std::array<int, 2> sr{5, 1};
Mapping m1(exts, sl);
Mapping m2(exts, sl);
Mapping m3(exts, sr);
OffsetMapping<Extents, 0> m4(exts, sl);
VERIFY(m1 == m2);
VERIFY(m1 != m3);
VERIFY(m1 == m4);
}
constexpr bool
test_eq_all()
{
test_eq_0d();
test_eq_1d();
test_eq_2d();
test_eq_zero();
return true;
}
template<typename M1, typename M2>
concept has_op_eq = requires (M1 m1, M2 m2)
{
{ m1 == m2 } -> std::same_as<bool>;
{ m2 == m1 } -> std::same_as<bool>;
{ m1 != m2 } -> std::same_as<bool>;
{ m2 != m1 } -> std::same_as<bool>;
};
constexpr void
test_has_op_eq()
{
using E1 = std::extents<int>;
using E2 = std::extents<int, 2>;
using E3 = std::extents<int, 1, 2>;
constexpr auto FT = std::array{false, true};
static_assert(!has_op_eq<
std::layout_stride::mapping<E1>, MappingLike<E1, FT, FT, FT>>);
static_assert(!has_op_eq<
std::layout_stride::mapping<E2>, MappingLike<E2, FT, FT, FT>>);
static_assert(!has_op_eq<
std::layout_stride::mapping<E3>, MappingLike<E3, FT, FT, FT>>);
}
int
main()
{
test_ctor_strides_all();
static_assert(test_ctor_strides_all());
test_mapping_like_convertible_all();
test_mapping_like_constructible_all();
test_stride_constructible_all();
test_is_exhaustive_all();
static_assert(test_is_exhaustive_all());
test_eq_all();
static_assert(test_eq_all());
test_has_op_eq();
return 0;
}