mirror of
https://github.com/gcc-mirror/gcc.git
synced 2025-07-21 23:52:54 +00:00

The second bug report in PR121061 is that the conversion of custom OtherIndexType to IndexType is incorrectly not done via r-value references. This commit fixes the forwarding issue, adds a custom IndexType called RValueInt, which only allows conversion to int via r-value reference. PR libstdc++/121061 libstdc++-v3/ChangeLog: * include/std/mdspan (extents::extents): Perform conversion to index_type of an r-value reference. (layout_left::mapping::operator()): Ditto. (layout_right::mapping::operator()): Ditto. (layout_stride::mapping::operator()): Ditto. * testsuite/23_containers/mdspan/extents/custom_integer.cc: Add tests for RValueInt and MutatingInt. * testsuite/23_containers/mdspan/int_like.h (RValueInt): Add. * testsuite/23_containers/mdspan/layouts/mapping.cc: Test with RValueInt. * testsuite/23_containers/mdspan/mdspan.cc: Ditto. Reviewed-by: Jonathan Wakely <jwakely@redhat.com> Reviewed-by: Tomasz Kamiński <tkaminsk@redhat.com> Signed-off-by: Luc Grosheintz <luc.grosheintz@gmail.com>
718 lines
19 KiB
C++
718 lines
19 KiB
C++
// { dg-do run { target c++23 } }
|
|
#include <mdspan>
|
|
|
|
#include <testsuite_hooks.h>
|
|
#include "int_like.h"
|
|
#include "layout_like.h"
|
|
|
|
constexpr auto dyn = std::dynamic_extent;
|
|
|
|
template<typename MDSpan, typename T, typename E, typename L = std::layout_right,
|
|
typename A = std::default_accessor<T>>
|
|
constexpr void
|
|
assert_typedefs()
|
|
{
|
|
static_assert(std::same_as<typename MDSpan::extents_type, E>);
|
|
static_assert(std::same_as<typename MDSpan::layout_type, L>);
|
|
static_assert(std::same_as<typename MDSpan::accessor_type, A>);
|
|
static_assert(std::same_as<typename MDSpan::mapping_type,
|
|
typename L::mapping<E>>);
|
|
static_assert(std::same_as<typename MDSpan::element_type, T>);
|
|
static_assert(std::same_as<typename MDSpan::value_type,
|
|
std::remove_const_t<T>>);
|
|
static_assert(std::same_as<typename MDSpan::index_type,
|
|
typename E::index_type>);
|
|
static_assert(std::same_as<typename MDSpan::size_type,
|
|
typename E::size_type>);
|
|
static_assert(std::same_as<typename MDSpan::rank_type,
|
|
typename E::rank_type>);
|
|
static_assert(std::same_as<typename MDSpan::data_handle_type,
|
|
typename A::data_handle_type>);
|
|
static_assert(std::same_as<typename MDSpan::reference,
|
|
typename A::reference>);
|
|
}
|
|
|
|
template<typename T, typename E, typename L, template<typename U> typename A>
|
|
constexpr void
|
|
test_typedefs()
|
|
{ assert_typedefs<std::mdspan<T, E, L, A<T>>, T, E, L, A<T>>(); }
|
|
|
|
constexpr void
|
|
test_typedefs_all()
|
|
{
|
|
using E = std::extents<int, 1, 2>;
|
|
using L = std::layout_left;
|
|
|
|
test_typedefs<double, E, L, std::default_accessor>();
|
|
test_typedefs<const double, E, L, std::default_accessor>();
|
|
}
|
|
|
|
template<typename MDSpan>
|
|
constexpr void
|
|
test_rank()
|
|
{
|
|
using Extents = typename MDSpan::extents_type;
|
|
static_assert(MDSpan::rank() == Extents::rank());
|
|
static_assert(MDSpan::rank_dynamic() == Extents::rank_dynamic());
|
|
}
|
|
|
|
constexpr bool
|
|
test_rank_all()
|
|
{
|
|
test_rank<std::mdspan<double, std::extents<int>>>();
|
|
test_rank<std::mdspan<double, std::extents<int, 1>>>();
|
|
test_rank<std::mdspan<double, std::extents<int, dyn>>>();
|
|
return true;
|
|
}
|
|
|
|
template<typename Extents>
|
|
constexpr void
|
|
test_extent(Extents exts)
|
|
{
|
|
double data = 1.0;
|
|
auto md = std::mdspan(&data, exts);
|
|
using MDSpan = decltype(md);
|
|
|
|
for(size_t i = 0; i < MDSpan::rank(); ++i)
|
|
{
|
|
VERIFY(MDSpan::static_extent(i) == Extents::static_extent(i));
|
|
VERIFY(md.extent(i) == exts.extent(i));
|
|
}
|
|
}
|
|
|
|
constexpr bool
|
|
test_extent_all()
|
|
{
|
|
// For rank == 0, check existence of the methods without calling them.
|
|
test_extent(std::extents<int>{});
|
|
test_extent(std::extents<int, 0>{});
|
|
test_extent(std::extents<int, dyn>{});
|
|
return true;
|
|
}
|
|
|
|
template<typename MDSpan>
|
|
constexpr void
|
|
test_class_properties()
|
|
{
|
|
static_assert(std::copyable<MDSpan>);
|
|
static_assert(std::is_nothrow_move_constructible_v<MDSpan>);
|
|
static_assert(std::is_nothrow_move_assignable_v<MDSpan>);
|
|
static_assert(std::is_nothrow_swappable_v<MDSpan>);
|
|
constexpr bool trivially_copyable =
|
|
std::is_trivially_copyable_v<typename MDSpan::accessor_type>
|
|
&& std::is_trivially_copyable_v<typename MDSpan::mapping_type>
|
|
&& std::is_trivially_copyable_v<typename MDSpan::data_handle_type>;
|
|
static_assert(std::is_trivially_copyable_v<MDSpan> == trivially_copyable);
|
|
}
|
|
|
|
constexpr bool
|
|
test_class_properties_all()
|
|
{
|
|
test_class_properties<std::mdspan<double, std::extents<int>>>();
|
|
test_class_properties<std::mdspan<double, std::extents<int, 1>>>();
|
|
test_class_properties<std::mdspan<double, std::extents<int, dyn>>>();
|
|
return true;
|
|
}
|
|
|
|
constexpr bool
|
|
test_default_ctor()
|
|
{
|
|
static_assert(!std::is_default_constructible_v<std::mdspan<double,
|
|
std::extents<int>>>);
|
|
static_assert(!std::is_default_constructible_v<std::mdspan<double,
|
|
std::extents<int, 1>>>);
|
|
static_assert(std::is_default_constructible_v<std::mdspan<double,
|
|
std::extents<int, dyn>>>);
|
|
|
|
std::mdspan<double, std::extents<int, dyn>> md;
|
|
VERIFY(md.data_handle() == nullptr);
|
|
VERIFY(md.empty());
|
|
return true;
|
|
}
|
|
|
|
constexpr bool
|
|
test_from_other()
|
|
{
|
|
using Extents = std::extents<int, 3, 5, 7>;
|
|
auto exts = Extents{};
|
|
|
|
auto mapping = std::layout_right::mapping(exts);
|
|
constexpr size_t n = mapping.required_span_size();
|
|
std::array<double, n> storage{};
|
|
|
|
auto md1 = std::mdspan(storage.data(), exts);
|
|
auto md2 = std::mdspan<double, std::dextents<int, 3>>(md1);
|
|
|
|
VERIFY(md1.data_handle() == md2.data_handle());
|
|
VERIFY(md1.size() == md2.size());
|
|
|
|
static_assert(!std::is_convertible_v<
|
|
std::mdspan<double, std::extents<unsigned int, 2>>,
|
|
std::mdspan<double, std::extents<int, 2>>>);
|
|
|
|
static_assert(std::is_convertible_v<
|
|
std::mdspan<double, std::extents<int, 2>>,
|
|
std::mdspan<const double, std::extents<int, 2>>>);
|
|
|
|
static_assert(!std::is_constructible_v<
|
|
std::mdspan<double, std::extents<int, 2>>,
|
|
std::mdspan<const double, std::extents<int, 2>>>);
|
|
|
|
return true;
|
|
}
|
|
|
|
template<typename T, typename E, typename L = std::layout_right,
|
|
typename A = std::default_accessor<T>>
|
|
constexpr void
|
|
assert_deduced_typedefs(auto md)
|
|
{ assert_typedefs<decltype(md), T, E, L, A>(); }
|
|
|
|
constexpr bool
|
|
test_from_carray()
|
|
{
|
|
constexpr size_t n = 5;
|
|
double data[n] = {1.1, 2.2, 3.3, 4.4, 5.5};
|
|
|
|
auto md = std::mdspan(data);
|
|
assert_deduced_typedefs<double, std::extents<size_t, n>>(md);
|
|
VERIFY(md.rank() == 1);
|
|
VERIFY(md.rank_dynamic() == 0);
|
|
VERIFY(md[2] == data[2]);
|
|
return true;
|
|
}
|
|
|
|
constexpr bool
|
|
test_from_pointer()
|
|
{
|
|
double value = 12.3;
|
|
auto md = std::mdspan(&value);
|
|
assert_deduced_typedefs<double, std::extents<size_t>>(md);
|
|
VERIFY(md.rank() == 0);
|
|
VERIFY(md.rank_dynamic() == 0);
|
|
VERIFY(md[] == value);
|
|
return true;
|
|
}
|
|
|
|
constexpr bool
|
|
test_from_pointer_and_shape()
|
|
{
|
|
constexpr size_t n = 6;
|
|
std::array<double, n> data{1.1, 2.2, 3.3, 4.4, 5.5, 6.6};
|
|
std::array<int, 2> shape{2, 3};
|
|
std::span<const int, 2> shape_view(shape);
|
|
|
|
auto verify = [&data](auto md)
|
|
{
|
|
assert_deduced_typedefs<double, std::dextents<size_t, 2>>(md);
|
|
VERIFY(md.rank() == 2);
|
|
VERIFY(md.rank_dynamic() == 2);
|
|
VERIFY((md[0, 0]) == data[0]);
|
|
VERIFY((md[0, 1]) == data[1]);
|
|
VERIFY((md[1, 0]) == data[3]);
|
|
};
|
|
|
|
verify(std::mdspan(data.data(), shape[0], shape[1]));
|
|
verify(std::mdspan(data.data(), shape));
|
|
verify(std::mdspan(data.data(), shape_view));
|
|
|
|
std::mdspan<double, std::dextents<size_t, 2>> md1 = {data.data(), shape};
|
|
verify(md1);
|
|
|
|
std::mdspan<double, std::dextents<size_t, 2>> md2 = {data.data(), shape_view};
|
|
verify(md2);
|
|
|
|
static_assert(std::is_constructible_v<
|
|
std::mdspan<float, std::extents<int, 3, 5>>, float*>);
|
|
static_assert(!std::is_constructible_v<
|
|
std::mdspan<float, std::extents<int, 3, 5>>, float*, int>);
|
|
static_assert(std::is_constructible_v<
|
|
std::mdspan<float, std::extents<int, 3, 5>>, float*, int, int>);
|
|
static_assert(std::is_constructible_v<
|
|
std::mdspan<float, std::extents<int, 3, 5>>, float*, std::span<int, 0>>);
|
|
static_assert(std::is_constructible_v<
|
|
std::mdspan<float, std::extents<int, 3, 5>>, float*, std::span<int, 2>>);
|
|
static_assert(!std::is_convertible_v<
|
|
float*, std::mdspan<float, std::extents<int, 3, 5>>>);
|
|
|
|
static_assert(std::is_constructible_v<
|
|
std::mdspan<float, std::dextents<int, 2>>, float*, std::span<int, 2>>);
|
|
static_assert(!std::is_constructible_v<
|
|
std::mdspan<float, std::dextents<int, 2>>, float*, std::span<int, 1>>);
|
|
static_assert(!std::is_constructible_v<
|
|
std::mdspan<float, std::dextents<int, 2>>, float*, std::span<int, 3>>);
|
|
static_assert(!std::is_constructible_v<
|
|
std::mdspan<float, std::dextents<int, 2>>, float*, std::span<int, dyn>>);
|
|
return true;
|
|
}
|
|
|
|
constexpr bool
|
|
test_from_pointer_and_integral_constant()
|
|
{
|
|
std::array<double, 6> buffer{};
|
|
double * ptr = buffer.data();
|
|
|
|
auto verify = [ptr](auto actual, auto exts)
|
|
{
|
|
auto expected = std::mdspan<double, decltype(exts)>(ptr, exts);
|
|
static_assert(std::same_as<decltype(actual), decltype(expected)>);
|
|
VERIFY(actual.extents() == expected.extents());
|
|
};
|
|
|
|
auto c3 = std::integral_constant<int, 3>{};
|
|
auto c6 = std::integral_constant<int, 6>{};
|
|
|
|
verify(std::mdspan(ptr, 6), std::extents(6));
|
|
verify(std::mdspan(ptr, c6), std::extents(c6));
|
|
verify(std::mdspan(ptr, 2, c3), std::extents(2, c3));
|
|
return true;
|
|
}
|
|
|
|
constexpr bool
|
|
test_from_extents()
|
|
{
|
|
constexpr size_t n = 3*5*7;
|
|
std::array<double, n> storage{};
|
|
using Extents = std::extents<int, 3, 5, 7>;
|
|
auto exts = Extents{};
|
|
auto md = std::mdspan(storage.data(), exts);
|
|
|
|
assert_deduced_typedefs<double, Extents>(md);
|
|
VERIFY(md.data_handle() == storage.data());
|
|
VERIFY(md.extents() == exts);
|
|
return true;
|
|
}
|
|
|
|
constexpr bool
|
|
test_from_mapping()
|
|
{
|
|
constexpr size_t n = 3*5*7;
|
|
std::array<double, n> storage{};
|
|
using Extents = std::extents<int, 3, 5, 7>;
|
|
|
|
auto exts = Extents{};
|
|
auto m = std::layout_left::mapping(exts);
|
|
auto md = std::mdspan(storage.data(), m);
|
|
|
|
assert_deduced_typedefs<double, Extents, std::layout_left>(md);
|
|
VERIFY(md.data_handle() == storage.data());
|
|
VERIFY(md.mapping() == m);
|
|
return true;
|
|
}
|
|
|
|
constexpr bool
|
|
test_from_accessor()
|
|
{
|
|
constexpr size_t n = 3*5*7;
|
|
std::array<double, n> storage{};
|
|
using Extents = std::extents<int, 3, 5, 7>;
|
|
|
|
auto exts = Extents{};
|
|
auto m = std::layout_left::mapping(exts);
|
|
auto a = std::default_accessor<double>{};
|
|
auto md = std::mdspan(storage.data(), m, a);
|
|
|
|
assert_deduced_typedefs<double, Extents, std::layout_left>(md);
|
|
VERIFY(md.data_handle() == storage.data());
|
|
VERIFY(md.mapping() == m);
|
|
return true;
|
|
}
|
|
|
|
template<typename MDSpan, typename Pointer, typename... Ints>
|
|
concept has_pack_ctor = requires
|
|
{
|
|
{ MDSpan(Pointer{}, Ints(0)...) } -> std::same_as<MDSpan>;
|
|
};
|
|
|
|
template<typename CustomInt, bool ValidForPacks, bool ValidForArrays>
|
|
constexpr bool
|
|
test_from_int_like()
|
|
{
|
|
constexpr size_t n = 3*5*7;
|
|
std::array<double, n> storage{};
|
|
|
|
auto verify = [&](auto md)
|
|
{
|
|
VERIFY(md.data_handle() == storage.data());
|
|
VERIFY(md.extent(0) == 3);
|
|
VERIFY(md.extent(1) == 5);
|
|
VERIFY(md.extent(2) == 7);
|
|
};
|
|
|
|
static_assert(has_pack_ctor<std::mdspan<float, std::dextents<int, 3>>,
|
|
float*, CustomInt, int, CustomInt> == ValidForPacks);
|
|
|
|
static_assert(std::is_constructible_v<
|
|
std::mdspan<float, std::dextents<int, 3>>, float*,
|
|
std::span<CustomInt, 3>> == ValidForArrays);
|
|
|
|
static_assert(std::is_constructible_v<
|
|
std::mdspan<float, std::dextents<int, 3>>, float*,
|
|
std::array<CustomInt, 3>> == ValidForArrays);
|
|
|
|
if constexpr (ValidForPacks)
|
|
verify(std::mdspan(storage.data(), CustomInt(3), 5, CustomInt(7)));
|
|
|
|
if constexpr (ValidForArrays)
|
|
{
|
|
auto shape = std::array{CustomInt(3), CustomInt(5), CustomInt(7)};
|
|
auto shape_view = std::span<CustomInt, 3>{shape};
|
|
verify(std::mdspan(storage.data(), shape));
|
|
verify(std::mdspan(storage.data(), shape_view));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
template<typename T, bool NothrowConstructible = true,
|
|
bool NothrowAssignable = true>
|
|
class OpaqueAccessor
|
|
{
|
|
struct Handle
|
|
{
|
|
constexpr
|
|
Handle(T * other)
|
|
: ptr(other)
|
|
{ }
|
|
|
|
constexpr
|
|
Handle(const Handle&) noexcept(NothrowConstructible) = default;
|
|
|
|
constexpr
|
|
Handle(Handle&&) noexcept(NothrowConstructible) = default;
|
|
|
|
constexpr Handle&
|
|
operator=(const Handle&) noexcept(NothrowAssignable) = default;
|
|
|
|
constexpr Handle&
|
|
operator=(Handle&&) noexcept(NothrowAssignable) = default;
|
|
|
|
T * ptr;
|
|
};
|
|
|
|
public:
|
|
using element_type = T;
|
|
using reference = T&;
|
|
using data_handle_type = Handle;
|
|
using offset_policy = OpaqueAccessor;
|
|
|
|
reference
|
|
access(data_handle_type p, size_t i) const
|
|
{
|
|
++access_count;
|
|
return p.ptr[i];
|
|
}
|
|
|
|
typename offset_policy::data_handle_type
|
|
offset(data_handle_type p, size_t i) const
|
|
{
|
|
++offset_count;
|
|
return typename offset_policy::data_handle_type{(void*)(p.ptr + i)};
|
|
}
|
|
|
|
mutable size_t access_count = 0;
|
|
mutable size_t offset_count = 0;
|
|
};
|
|
|
|
void
|
|
test_from_opaque_accessor()
|
|
{
|
|
constexpr size_t n = 3*5*7;
|
|
std::array<double, n> storage{};
|
|
using Extents = std::extents<int, 3, 5, 7>;
|
|
|
|
auto exts = Extents{};
|
|
auto m = std::layout_left::mapping(exts);
|
|
auto a = OpaqueAccessor<double>{};
|
|
auto handle = OpaqueAccessor<double>::data_handle_type{storage.data()};
|
|
auto md = std::mdspan(handle, m, a);
|
|
|
|
using MDSpan = decltype(md);
|
|
static_assert(std::same_as<MDSpan::accessor_type, decltype(a)>);
|
|
|
|
VERIFY((md[0, 0, 0]) == 0.0);
|
|
VERIFY(md.accessor().access_count == 1);
|
|
|
|
VERIFY((md[2, 4, 6]) == 0.0);
|
|
VERIFY(md.accessor().access_count == 2);
|
|
}
|
|
|
|
template<typename T, typename Base>
|
|
class BaseClassAccessor
|
|
{
|
|
public:
|
|
using element_type = T;
|
|
using reference = Base&;
|
|
using data_handle_type = T*;
|
|
using offset_policy = BaseClassAccessor;
|
|
|
|
static_assert(std::common_reference_with<reference&&, element_type&>);
|
|
|
|
reference
|
|
access(data_handle_type p, size_t i) const
|
|
{ return p[i]; }
|
|
|
|
typename offset_policy::data_handle_type
|
|
offset(data_handle_type p, size_t i) const
|
|
{ return typename offset_policy::data_handle_type{p + i}; }
|
|
};
|
|
|
|
struct Base
|
|
{
|
|
double value = 1.0;
|
|
};
|
|
|
|
struct Derived : Base
|
|
{
|
|
double value = 2.0;
|
|
};
|
|
|
|
void
|
|
test_from_base_class_accessor()
|
|
{
|
|
constexpr size_t n = 3*5*7;
|
|
std::array<Derived, n> storage{};
|
|
using Extents = std::extents<int, 3, 5, 7>;
|
|
|
|
auto exts = Extents{};
|
|
auto m = std::layout_left::mapping(exts);
|
|
auto a = BaseClassAccessor<Derived, Base>{};
|
|
auto md = std::mdspan(storage.data(), m, a);
|
|
|
|
using MDSpan = decltype(md);
|
|
static_assert(std::same_as<MDSpan::accessor_type, decltype(a)>);
|
|
static_assert(std::same_as<decltype(md[0, 0, 0]), Base&>);
|
|
VERIFY((md[0, 0, 0].value) == 1.0);
|
|
VERIFY((md[2, 4, 6].value) == 1.0);
|
|
}
|
|
|
|
constexpr bool
|
|
test_from_mapping_like()
|
|
{
|
|
double data = 1.1;
|
|
auto m = LayoutLike::mapping<std::extents<int, 1, 2, 3>>{};
|
|
auto md = std::mdspan(&data, m);
|
|
VERIFY((md[0, 0, 0]) == data);
|
|
VERIFY((md[0, 1, 2]) == data);
|
|
return true;
|
|
}
|
|
|
|
template<typename MDSpan>
|
|
constexpr void
|
|
test_empty(MDSpan md)
|
|
{
|
|
VERIFY(md.empty() == (md.size() == 0));
|
|
}
|
|
|
|
constexpr bool
|
|
test_empty_all()
|
|
{
|
|
test_empty(std::mdspan<double, std::extents<int, dyn>>{});
|
|
return true;
|
|
}
|
|
|
|
template<typename MDSpan, typename... Args>
|
|
concept indexable = requires (MDSpan md, Args... args)
|
|
{
|
|
{ md[args...] } -> std::same_as<typename MDSpan::reference>;
|
|
};
|
|
|
|
template<typename Int, bool ValidForPacks, bool ValidForArrays>
|
|
constexpr bool
|
|
test_access()
|
|
{
|
|
using Extents = std::extents<int, 3, 5, 7>;
|
|
auto exts = Extents{};
|
|
|
|
auto mapping = std::layout_left::mapping(exts);
|
|
constexpr size_t n = mapping.required_span_size();
|
|
std::array<double, n> storage{};
|
|
|
|
auto md = std::mdspan(storage.data(), mapping);
|
|
using MDSpan = decltype(md);
|
|
|
|
for(int i = 0; i < exts.extent(0); ++i)
|
|
for(int j = 0; j < exts.extent(1); ++j)
|
|
for(int k = 0; k < exts.extent(2); ++k)
|
|
{
|
|
storage[mapping(i, j, k)] = 1.0;
|
|
if constexpr (ValidForPacks)
|
|
VERIFY((md[Int(i), Int(j), Int(k)]) == 1.0);
|
|
|
|
if constexpr (ValidForArrays)
|
|
{
|
|
std::array<Int, 3> ijk{Int(i), Int(j), Int(k)};
|
|
VERIFY((md[ijk]) == 1.0);
|
|
VERIFY((md[std::span(ijk)]) == 1.0);
|
|
}
|
|
storage[mapping(i, j, k)] = 0.0;
|
|
}
|
|
|
|
if constexpr (!ValidForPacks)
|
|
static_assert(!indexable<MDSpan, Int, int, Int>);
|
|
|
|
if constexpr (!ValidForArrays)
|
|
{
|
|
static_assert(!indexable<MDSpan, std::array<Int, 3>>);
|
|
static_assert(!indexable<MDSpan, std::span<Int, 3>>);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
constexpr bool
|
|
test_swap()
|
|
{
|
|
using Extents = std::dextents<int, 2>;
|
|
auto e1 = Extents{3, 5};
|
|
auto e2 = Extents{7, 11};
|
|
|
|
std::array<double, 3*5> s1{};
|
|
std::array<double, 7*11> s2{};
|
|
|
|
auto md1 = std::mdspan(s1.data(), e1);
|
|
auto md2 = std::mdspan(s2.data(), e2);
|
|
|
|
std::swap(md1, md2);
|
|
|
|
VERIFY(md1.data_handle() == s2.data());
|
|
VERIFY(md2.data_handle() == s1.data());
|
|
|
|
VERIFY(md1.size() == s2.size());
|
|
VERIFY(md2.size() == s1.size());
|
|
return true;
|
|
}
|
|
|
|
namespace adl
|
|
{
|
|
template<typename T>
|
|
struct SwappableAccessor
|
|
{
|
|
using element_type = T;
|
|
using reference = T&;
|
|
using data_handle_type = T*;
|
|
using offset_policy = SwappableAccessor;
|
|
|
|
reference
|
|
access(data_handle_type p, size_t i) const
|
|
{ return p[i]; }
|
|
|
|
typename offset_policy::data_handle_type
|
|
offset(data_handle_type p, size_t i) const
|
|
{ return p + i; }
|
|
|
|
friend void
|
|
swap(SwappableAccessor&, SwappableAccessor&)
|
|
{ ++swap_count; }
|
|
|
|
static inline size_t swap_count = 0;
|
|
};
|
|
}
|
|
|
|
void
|
|
test_swap_adl()
|
|
{
|
|
using Extents = std::extents<int, dyn>;
|
|
using Layout = std::layout_left;
|
|
using Accessor = adl::SwappableAccessor<double>;
|
|
Accessor::swap_count = 0;
|
|
|
|
std::mdspan<double, Extents, Layout, Accessor> m1, m2;
|
|
swap(m1, m2);
|
|
VERIFY(Accessor::swap_count == 1);
|
|
}
|
|
|
|
template<bool Constructible, bool Assignable>
|
|
constexpr void
|
|
test_nothrow_movable()
|
|
{
|
|
using Layout = std::layout_left;
|
|
using Extents = std::dextents<int, 3>;
|
|
using Accessor = OpaqueAccessor<int, Constructible, Assignable>;
|
|
using Handle = Accessor::data_handle_type;
|
|
static_assert(std::is_nothrow_move_assignable_v<Accessor>);
|
|
static_assert(std::is_nothrow_move_constructible_v<Accessor>);
|
|
static_assert(std::is_nothrow_move_assignable_v<Handle> == Assignable);
|
|
static_assert(std::is_nothrow_move_constructible_v<Handle> == Constructible);
|
|
|
|
using MDSpan = std::mdspan<int, Extents, Layout, Accessor>;
|
|
static_assert(std::is_nothrow_move_assignable_v<MDSpan> == Assignable);
|
|
static_assert(std::is_nothrow_move_constructible_v<MDSpan> == Constructible);
|
|
}
|
|
|
|
constexpr void
|
|
test_nothrow_movable_all()
|
|
{
|
|
using MDSpan = std::mdspan<double, std::dextents<int, 3>>;
|
|
static_assert(std::is_nothrow_move_assignable_v<MDSpan>);
|
|
static_assert(std::is_nothrow_move_constructible_v<MDSpan>);
|
|
|
|
test_nothrow_movable<true, true>();
|
|
test_nothrow_movable<true, false>();
|
|
test_nothrow_movable<false, true>();
|
|
test_nothrow_movable<false, false>();
|
|
}
|
|
|
|
int
|
|
main()
|
|
{
|
|
test_typedefs_all();
|
|
|
|
test_rank_all();
|
|
test_extent_all();
|
|
static_assert(test_extent_all());
|
|
|
|
test_class_properties_all();
|
|
static_assert(test_class_properties_all());
|
|
|
|
test_empty_all();
|
|
static_assert(test_empty_all());
|
|
|
|
test_default_ctor();
|
|
static_assert(test_default_ctor());
|
|
|
|
test_from_other();
|
|
static_assert(test_from_other());
|
|
|
|
test_from_carray();
|
|
static_assert(test_from_carray());
|
|
|
|
test_from_pointer_and_shape();
|
|
static_assert(test_from_pointer_and_shape());
|
|
|
|
test_from_pointer_and_integral_constant();
|
|
static_assert(test_from_pointer_and_integral_constant());
|
|
|
|
test_from_extents();
|
|
static_assert(test_from_extents());
|
|
|
|
test_from_mapping();
|
|
static_assert(test_from_mapping());
|
|
|
|
test_from_accessor();
|
|
static_assert(test_from_accessor());
|
|
|
|
test_from_int_like<int, true, true>();
|
|
static_assert(test_from_int_like<int, true, true>());
|
|
test_from_int_like<IntLike, true, true>();
|
|
test_from_int_like<ThrowingInt, false, false>();
|
|
test_from_int_like<MutatingInt, true, false>();
|
|
test_from_int_like<RValueInt, true, false>();
|
|
|
|
test_from_opaque_accessor();
|
|
test_from_base_class_accessor();
|
|
test_from_mapping_like();
|
|
static_assert(test_from_mapping_like());
|
|
|
|
test_access<int, true, true>();
|
|
static_assert(test_access<int, true, true>());
|
|
test_access<IntLike, true, true>();
|
|
test_access<ThrowingInt, false, false>();
|
|
test_access<MutatingInt, true, false>();
|
|
test_access<RValueInt, true, false>();
|
|
|
|
test_swap();
|
|
static_assert(test_swap());
|
|
test_swap_adl();
|
|
|
|
test_nothrow_movable_all();
|
|
return 0;
|
|
}
|