Skip to content

<mdspan>: Test mdspan #3749

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
31 changes: 19 additions & 12 deletions stl/inc/mdspan
Original file line number Diff line number Diff line change
Expand Up @@ -952,7 +952,7 @@ public:
&& is_nothrow_constructible_v<index_type, const _OtherIndexType&>
&& (_Size == rank() || _Size == rank_dynamic())
&& is_constructible_v<mapping_type, extents_type> && is_default_constructible_v<accessor_type>
constexpr explicit(_Size != rank_dynamic()) mdspan(data_handle_type _Ptr_, span<_OtherIndexType, _Size>& _Exts)
constexpr explicit(_Size != rank_dynamic()) mdspan(data_handle_type _Ptr_, span<_OtherIndexType, _Size> _Exts)
: _Ptr(_STD move(_Ptr_)), _Map(extents_type{_Exts}), _Acc() {}

template <class _OtherIndexType, size_t _Size>
Expand Down Expand Up @@ -982,7 +982,7 @@ public:
!is_convertible_v<const typename _OtherLayoutPolicy::template mapping<_OtherExtents>&, mapping_type>
|| !is_convertible_v<const _OtherAccessor&, accessor_type>)
mdspan(const mdspan<_OtherElementType, _OtherExtents, _OtherLayoutPolicy, _OtherAccessor>& _Other)
: _Ptr(_Other._Ptr), _Map(_Other._Map), _Acc(_Other._Acc) {
: _Ptr(_Other.data_handle()), _Map(_Other.mapping()), _Acc(_Other.accessor()) {
static_assert(is_constructible_v<data_handle_type, const typename _OtherAccessor::data_handle_type&>,
"The data_handle_type must be constructible from const typename OtherAccessor::data_handle_type& (N4950 "
"[mdspan.mdspan.cons]/20.1).");
Expand All @@ -993,15 +993,15 @@ public:
constexpr mdspan& operator=(const mdspan&) = default;
constexpr mdspan& operator=(mdspan&&) = default;

#ifdef __clang__ // TRANSITION, P2128R6
#ifdef __cpp_multidimensional_subscript // TRANSITION, P2128R6
template <class... _OtherIndexTypes>
requires (is_convertible_v<_OtherIndexTypes, index_type> && ...)
&& (is_nothrow_constructible_v<index_type, _OtherIndexTypes> && ...)
&& (sizeof...(_OtherIndexTypes) == rank())
_NODISCARD constexpr reference operator[](_OtherIndexTypes... _Indices) const {
return _Acc.access(_Ptr, static_cast<size_t>(_Map(static_cast<index_type>(_STD move(_Indices))...)));
}
#endif // __clang__
#endif // __cpp_multidimensional_subscript

template <class _OtherIndexType>
requires is_convertible_v<const _OtherIndexType&, index_type>
Expand Down Expand Up @@ -1032,9 +1032,9 @@ public:
}

friend constexpr void swap(mdspan& _Left, mdspan& _Right) noexcept {
swap(_Left._Ptr, _Right._Ptr);
swap(_Left._Map, _Right._Map);
swap(_Left._Acc, _Right._Acc);
swap(_Left._Ptr, _Right._Ptr); // intentional ADL
swap(_Left._Map, _Right._Map); // intentional ADL
swap(_Left._Acc, _Right._Acc); // intentional ADL
}

_NODISCARD constexpr const extents_type& extents() const noexcept {
Expand Down Expand Up @@ -1088,13 +1088,20 @@ public:
private:
template <class _OtherIndexType, size_t... _Seq>
_NODISCARD constexpr reference _Index_impl(span<_OtherIndexType, rank()> _Indices, index_sequence<_Seq...>) const {
#ifdef __clang__ // TRANSITION, P2128R6
return this->operator[](_STD as_const(_Indices[_Seq])...);
#else // ^^^ defined(__clang__) / !defined(__clang__) vvv
return _Acc.access(_Ptr, static_cast<size_t>(_Map(static_cast<index_type>(_STD as_const(_Indices[_Seq]))...)));
#endif // ^^^ !defined(__clang__) ^^^
#ifdef __cpp_multidimensional_subscript // TRANSITION, P2128R6
return operator[](_STD as_const(_Indices[_Seq])...);
#else // ^^^ defined(__cpp_multidimensional_subscript) / !defined(__cpp_multidimensional_subscript) vvv
return _Multidimensional_access(_STD as_const(_Indices[_Seq])...);
#endif // ^^^ !defined(__cpp_multidimensional_subscript) ^^^
}

#ifndef __cpp_multidimensional_subscript // TRANSITION, P2128R6
template <class... _OtherIndexTypes>
_NODISCARD constexpr reference _Multidimensional_access(_OtherIndexTypes... _Indices) const {
return _Acc.access(_Ptr, static_cast<size_t>(_Map(static_cast<index_type>(_STD move(_Indices))...)));
}
#endif // __cpp_multidimensional_subscript

data_handle_type _Ptr{};
mapping_type _Map{};
accessor_type _Acc{};
Expand Down
60 changes: 25 additions & 35 deletions tests/std/include/test_mdspan_support.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,10 @@ namespace detail {
constexpr void check_implicit_conversion(T); // not defined
}

// clang-format off
template <class T, class... Args>
concept NotImplicitlyConstructibleFrom =
std::constructible_from<T, Args...>
&& !requires(Args&&... args) { detail::check_implicit_conversion<T>({std::forward<Args>(args)...}); };
// clang-format on
concept NotImplicitlyConstructibleFrom = std::constructible_from<T, Args...> && !requires(Args&&... args) {
detail::check_implicit_conversion<T>({std::forward<Args>(args)...});
};

namespace detail {
template <class T>
Expand All @@ -51,17 +49,14 @@ namespace detail {
&& std::same_as<typename M::rank_type, typename M::extents_type::rank_type>
&& is_mapping_of_v<typename M::layout_type, M>;

// clang-format off
template <class M>
concept CheckMemberFunctionsOfLayoutMapping =
requires(const M m) {
{ m.extents() } -> std::same_as<const typename M::extents_type&>;
{ m.required_span_size() } -> std::same_as<typename M::index_type>;
{ m.is_unique() } -> std::same_as<bool>;
{ m.is_exhaustive() } -> std::same_as<bool>;
{ m.is_strided() } -> std::same_as<bool>;
};
// clang-format on
concept CheckMemberFunctionsOfLayoutMapping = requires(const M m) {
{ m.extents() } -> std::same_as<const typename M::extents_type&>;
{ m.required_span_size() } -> std::same_as<typename M::index_type>;
{ m.is_unique() } -> std::same_as<bool>;
{ m.is_exhaustive() } -> std::same_as<bool>;
{ m.is_strided() } -> std::same_as<bool>;
};

template <class M>
concept CheckStaticFunctionsOfLayoutMapping = requires {
Expand All @@ -74,14 +69,11 @@ namespace detail {
};
} // namespace detail

// clang-format off
template <class M, class... Indices>
concept CheckCallOperatorOfLayoutMapping =
requires(const M m, Indices... i) {
{ m(i...) } -> std::same_as<typename M::index_type>;
{ m(i...) == m(static_cast<M::index_type>(i)...) } -> std::same_as<bool>;
};
// clang-format on
concept CheckCallOperatorOfLayoutMapping = requires(const M m, Indices... i) {
{ m(i...) } -> std::same_as<typename M::index_type>;
{ m(i...) == m(static_cast<M::index_type>(i)...) } -> std::same_as<bool>;
};

template <class M>
concept CheckStrideMemberFunction = requires(M mapping, M::rank_type i) {
Expand Down Expand Up @@ -127,23 +119,21 @@ namespace detail {
template <class A>
concept CheckNestedTypesOfAccessorPolicy =
sizeof(typename A::element_type) > 0
&& (!std::is_abstract_v<typename A::element_type>) &&std::copyable<typename A::data_handle_type>&& std::
is_nothrow_move_constructible_v<typename A::data_handle_type>&& std::is_nothrow_move_assignable_v<
typename A::data_handle_type>&& std::is_nothrow_swappable_v<typename A::data_handle_type>&& std::
common_reference_with<typename A::reference, typename A::element_type&&>
&& !std::is_abstract_v<typename A::element_type> && std::copyable<typename A::data_handle_type>
&& std::is_nothrow_move_constructible_v<typename A::data_handle_type>
&& std::is_nothrow_move_assignable_v<typename A::data_handle_type>
&& std::is_nothrow_swappable_v<typename A::data_handle_type>
&& std::common_reference_with<typename A::reference, typename A::element_type&&>
&& (std::same_as<typename A::offset_policy, A>
|| check_accessor_policy_requirements<typename A::offset_policy>())
&& std::constructible_from<typename A::offset_policy,
const A&>&& std::is_same_v<typename A::offset_policy::element_type, typename A::element_type>;
&& std::constructible_from<typename A::offset_policy, const A&>
&& std::is_same_v<typename A::offset_policy::element_type, typename A::element_type>;

// clang-format off
template <class A>
concept CheckMemberFunctionsOfAccessorPolicy =
requires(const A a, const A::data_handle_type p, size_t i) {
{ a.access(p, i) } -> std::same_as<typename A::reference>;
{ a.offset(p, i) } -> std::same_as<typename A::offset_policy::data_handle_type>;
};
// clang-format on
concept CheckMemberFunctionsOfAccessorPolicy = requires(const A a, const A::data_handle_type p, size_t i) {
{ a.access(p, i) } -> std::same_as<typename A::reference>;
{ a.offset(p, i) } -> std::same_as<typename A::offset_policy::data_handle_type>;
};
} // namespace detail

template <class A>
Expand Down
1 change: 1 addition & 0 deletions tests/std/test.lst
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ tests\P0009R18_mdspan_layout_right
tests\P0009R18_mdspan_layout_right_death
tests\P0009R18_mdspan_layout_stride
tests\P0009R18_mdspan_layout_stride_death
tests\P0009R18_mdspan_mdspan
tests\P0019R8_atomic_ref
tests\P0024R2_parallel_algorithms_adjacent_difference
tests\P0024R2_parallel_algorithms_adjacent_find
Expand Down
4 changes: 2 additions & 2 deletions tests/std/tests/P0009R18_mdspan/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1029,10 +1029,10 @@ void mdspan_tests_observers() {
static_assert(!mds.is_exhaustive());
static_assert(mds.is_strided());

#ifdef __clang__ // TRANSITION, P2128R6
#ifdef __cpp_multidimensional_subscript // TRANSITION, P2128R6
static_assert(mds[1, 0] == 1);
static_assert(mds[1, 2] == 7);
#endif // __clang__
#endif // __cpp_multidimensional_subscript

static_assert(mds[array{0, 1}] == 3);
static_assert(mds[array{1, 1}] == 4);
Expand Down
24 changes: 12 additions & 12 deletions tests/std/tests/P0009R18_mdspan_layout_left/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -302,81 +302,81 @@ constexpr void check_correctness() {
const array values{0, 1, 2};
mdspan<const int, extents<int, 3>, layout_left> vec{values.data()};

#ifdef __clang__ // TRANSITION, P2128R6
#ifdef __cpp_multidimensional_subscript // TRANSITION, P2128R6
assert(vec[0] == 0);
assert(vec[1] == 1);
assert(vec[2] == 2);
#else // ^^^ defined(__clang__) / !defined(__clang__) vvv
#else // ^^^ defined(__cpp_multidimensional_subscript) / !defined(__cpp_multidimensional_subscript) vvv
assert(vec[array{0}] == 0);
assert(vec[array{1}] == 1);
assert(vec[array{2}] == 2);
#endif // ^^^ !defined(__clang__) ^^^
#endif // ^^^ !defined(__cpp_multidimensional_subscript) ^^^
}

{ // 3x2 matrix with column-major order
const array values{0, 1, 2, 3, 4, 5};
mdspan<const int, extents<int, 3, 2>, layout_left> matrix{values.data()};

#ifdef __clang__ // TRANSITION, P2128R6
#ifdef __cpp_multidimensional_subscript // TRANSITION, P2128R6
assert((matrix[0, 0] == 0));
assert((matrix[1, 0] == 1));
assert((matrix[2, 0] == 2));
assert((matrix[0, 1] == 3));
assert((matrix[1, 1] == 4));
assert((matrix[2, 1] == 5));
#else // ^^^ defined(__clang__) / !defined(__clang__) vvv
#else // ^^^ defined(__cpp_multidimensional_subscript) / !defined(__cpp_multidimensional_subscript) vvv
assert((matrix[array{0, 0}] == 0));
assert((matrix[array{1, 0}] == 1));
assert((matrix[array{2, 0}] == 2));
assert((matrix[array{0, 1}] == 3));
assert((matrix[array{1, 1}] == 4));
assert((matrix[array{2, 1}] == 5));
#endif // ^^^ !defined(__clang__) ^^^
#endif // ^^^ !defined(__cpp_multidimensional_subscript) ^^^
}

{ // 3x2x4 tensor
const array values{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23};
mdspan<const int, dextents<size_t, 3>, layout_left> tensor{values.data(), 3, 2, 4};

#ifdef __clang__ // TRANSITION, P2128R6
#ifdef __cpp_multidimensional_subscript // TRANSITION, P2128R6
assert((tensor[0, 0, 0] == 0));
assert((tensor[2, 0, 0] == 2));
assert((tensor[1, 1, 1] == 10));
assert((tensor[0, 0, 3] == 18));
assert((tensor[2, 1, 2] == 17));
assert((tensor[2, 1, 3] == 23));
#else // ^^^ defined(__clang__) / !defined(__clang__) vvv
#else // ^^^ defined(__cpp_multidimensional_subscript) / !defined(__cpp_multidimensional_subscript) vvv
assert((tensor[array{0, 0, 0}] == 0));
assert((tensor[array{2, 0, 0}] == 2));
assert((tensor[array{1, 1, 1}] == 10));
assert((tensor[array{0, 0, 3}] == 18));
assert((tensor[array{2, 1, 2}] == 17));
assert((tensor[array{2, 1, 3}] == 23));
#endif // ^^^ !defined(__clang__) ^^^
#endif // ^^^ !defined(__cpp_multidimensional_subscript) ^^^
}

{ // 2x3x2x3 tensor
const array values{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
26, 27, 28, 29, 30, 31, 32, 33, 34, 35};
mdspan<const int, extents<long, 2, 3, dynamic_extent, dynamic_extent>, layout_left> tensor{values.data(), 2, 3};

#ifdef __clang__ // TRANSITION, P2128R6
#ifdef __cpp_multidimensional_subscript // TRANSITION, P2128R6
assert((tensor[0, 0, 0, 0] == 0));
assert((tensor[1, 0, 0, 0] == 1));
assert((tensor[0, 1, 1, 0] == 8));
assert((tensor[0, 0, 0, 1] == 12));
assert((tensor[0, 0, 0, 2] == 24));
assert((tensor[0, 2, 0, 2] == 28));
assert((tensor[1, 2, 1, 2] == 35));
#else // ^^^ defined(__clang__) / !defined(__clang__) vvv
#else // ^^^ defined(__cpp_multidimensional_subscript) / !defined(__cpp_multidimensional_subscript) vvv
assert((tensor[array{0, 0, 0, 0}] == 0));
assert((tensor[array{1, 0, 0, 0}] == 1));
assert((tensor[array{0, 1, 1, 0}] == 8));
assert((tensor[array{0, 0, 0, 1}] == 12));
assert((tensor[array{0, 0, 0, 2}] == 24));
assert((tensor[array{0, 2, 0, 2}] == 28));
assert((tensor[array{1, 2, 1, 2}] == 35));
#endif // ^^^ !defined(__clang__) ^^^
#endif // ^^^ !defined(__cpp_multidimensional_subscript) ^^^
}
}

Expand Down
24 changes: 12 additions & 12 deletions tests/std/tests/P0009R18_mdspan_layout_right/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -303,43 +303,43 @@ constexpr void check_correctness() {
const array vals{2, 1, 0};
mdspan<const int, extents<int, 3>, layout_right> vec{vals.data()};

#ifdef __clang__ // TRANSITION, P2128R6
#ifdef __cpp_multidimensional_subscript // TRANSITION, P2128R6
assert(vec[0] == 2);
assert(vec[1] == 1);
assert(vec[2] == 0);
#else // ^^^ defined(__clang__) / !defined(__clang__) vvv
#else // ^^^ defined(__cpp_multidimensional_subscript) / !defined(__cpp_multidimensional_subscript) vvv
assert(vec[array{0}] == 2);
assert(vec[array{1}] == 1);
assert(vec[array{2}] == 0);
#endif // ^^^ !defined(__clang__) ^^^
#endif // ^^^ !defined(__cpp_multidimensional_subscript) ^^^
}

{ // 4x3 matrix with row-major order
const array vals{11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
mdspan<const int, extents<int, 4, 3>, layout_right> matrix{vals.data()};

#ifdef __clang__ // TRANSITION, P2128R6
#ifdef __cpp_multidimensional_subscript // TRANSITION, P2128R6
assert((matrix[0, 0] == 11));
assert((matrix[0, 2] == 9));
assert((matrix[1, 1] == 7));
assert((matrix[2, 0] == 5));
assert((matrix[2, 2] == 3));
assert((matrix[3, 1] == 1));
#else // ^^^ defined(__clang__) / !defined(__clang__) vvv
#else // ^^^ defined(__cpp_multidimensional_subscript) / !defined(__cpp_multidimensional_subscript) vvv
assert((matrix[array{0, 0}] == 11));
assert((matrix[array{0, 2}] == 9));
assert((matrix[array{1, 1}] == 7));
assert((matrix[array{2, 0}] == 5));
assert((matrix[array{2, 2}] == 3));
assert((matrix[array{3, 1}] == 1));
#endif // ^^^ !defined(__clang__) ^^^
#endif // ^^^ !defined(__cpp_multidimensional_subscript) ^^^
}

{ // 4x3x2 tensor
const array vals{23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
mdspan<const int, dextents<size_t, 3>, layout_right> tensor{vals.data(), 4, 3, 2};

#ifdef __clang__ // TRANSITION, P2128R6
#ifdef __cpp_multidimensional_subscript // TRANSITION, P2128R6
assert((tensor[0, 0, 0] == 23));
assert((tensor[0, 0, 1] == 22));
assert((tensor[0, 1, 0] == 21));
Expand All @@ -350,7 +350,7 @@ constexpr void check_correctness() {
assert((tensor[1, 1, 1] == 14));
assert((tensor[2, 2, 1] == 6));
assert((tensor[3, 2, 1] == 0));
#else // ^^^ defined(__clang__) / !defined(__clang__) vvv
#else // ^^^ defined(__cpp_multidimensional_subscript) / !defined(__cpp_multidimensional_subscript) vvv
assert((tensor[array{0, 0, 0}] == 23));
assert((tensor[array{0, 0, 1}] == 22));
assert((tensor[array{0, 1, 0}] == 21));
Expand All @@ -361,15 +361,15 @@ constexpr void check_correctness() {
assert((tensor[array{1, 1, 1}] == 14));
assert((tensor[array{2, 2, 1}] == 6));
assert((tensor[array{3, 2, 1}] == 0));
#endif // ^^^ !defined(__clang__) ^^^
#endif // ^^^ !defined(__cpp_multidimensional_subscript) ^^^
}

{ // 3x2x3x2 tensor
const array vals{35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12,
11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
mdspan<const int, extents<long, 3, dynamic_extent, 3, dynamic_extent>, layout_right> tensor{vals.data(), 2, 2};

#ifdef __clang__ // TRANSITION, P2128R6
#ifdef __cpp_multidimensional_subscript // TRANSITION, P2128R6
assert((tensor[0, 0, 0, 0] == 35));
assert((tensor[0, 0, 0, 1] == 34));
assert((tensor[0, 0, 1, 0] == 33));
Expand All @@ -388,7 +388,7 @@ constexpr void check_correctness() {
assert((tensor[1, 1, 1, 1] == 14));
assert((tensor[2, 0, 2, 0] == 7));
assert((tensor[2, 1, 2, 1] == 0));
#else // ^^^ defined(__clang__) / !defined(__clang__) vvv
#else // ^^^ defined(__cpp_multidimensional_subscript) / !defined(__cpp_multidimensional_subscript) vvv
assert((tensor[array{0, 0, 0, 0}] == 35));
assert((tensor[array{0, 0, 0, 1}] == 34));
assert((tensor[array{0, 0, 1, 0}] == 33));
Expand All @@ -407,7 +407,7 @@ constexpr void check_correctness() {
assert((tensor[array{1, 1, 1, 1}] == 14));
assert((tensor[array{2, 0, 2, 0}] == 7));
assert((tensor[array{2, 1, 2, 1}] == 0));
#endif // ^^^ !defined(__clang__) ^^^
#endif // ^^^ !defined(__cpp_multidimensional_subscript) ^^^
}
}

Expand Down
Loading