Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
<mdspan>: Test mdspan (#3749)
Browse files Browse the repository at this point in the history
Co-authored-by: Stephan T. Lavavej <stl@nuwen.net>
JMazurkiewicz and StephanTLavavej authored Jun 10, 2023
1 parent 7a680e5 commit ab7bb23
Showing 9 changed files with 1,439 additions and 85 deletions.
31 changes: 19 additions & 12 deletions stl/inc/mdspan
Original file line number Diff line number Diff line change
@@ -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>
@@ -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).");
@@ -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>
@@ -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 {
@@ -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{};
60 changes: 25 additions & 35 deletions tests/std/include/test_mdspan_support.hpp
Original file line number Diff line number Diff line change
@@ -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>
@@ -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 {
@@ -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) {
@@ -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>
1 change: 1 addition & 0 deletions tests/std/test.lst
Original file line number Diff line number Diff line change
@@ -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
4 changes: 2 additions & 2 deletions tests/std/tests/P0009R18_mdspan/test.cpp
Original file line number Diff line number Diff line change
@@ -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);
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
@@ -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) ^^^
}
}

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
@@ -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));
@@ -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));
@@ -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));
@@ -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));
@@ -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) ^^^
}
}

Loading

0 comments on commit ab7bb23

Please sign in to comment.