1 | //===----------------------------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 |
10 | |
11 | // <mdspan> |
12 | |
13 | // template<class OtherMapping> |
14 | // friend constexpr bool operator==(const mapping& x, const OtherMapping& y) noexcept; |
15 | // |
16 | // Constraints: |
17 | // - layout-mapping-alike<OtherMapping> is satisfied. |
18 | // - rank_ == OtherMapping::extents_type::rank() is true. |
19 | // - OtherMapping::is_always_strided() is true. |
20 | // |
21 | // Preconditions: OtherMapping meets the layout mapping requirements ([mdspan.layout.policy.reqmts]). |
22 | // |
23 | // Returns: true if x.extents() == y.extents() is true, OFFSET(y) == 0 is true, and each of x.stride(r) == y.stride(r) is true for r in the range [0, x.extents().rank()). Otherwise, false. |
24 | |
25 | #include <mdspan> |
26 | #include <type_traits> |
27 | #include <concepts> |
28 | #include <cassert> |
29 | |
30 | #include "test_macros.h" |
31 | |
32 | #include "../CustomTestLayouts.h" |
33 | |
34 | template <class E1, class E2> |
35 | concept layout_mapping_comparable = requires( |
36 | E1 e1, |
37 | E2 e2, |
38 | std::array<typename E1::index_type, E1::rank()> s1, |
39 | std::array<typename E1::index_type, E1::rank()> s2) { |
40 | std::layout_stride::mapping<E1>(e1, s1) == std::layout_stride::mapping<E2>(e2, s2); |
41 | }; |
42 | |
43 | template <class T1, class T2> |
44 | constexpr void test_comparison_different_rank() { |
45 | constexpr size_t D = std::dynamic_extent; |
46 | |
47 | // sanity check same rank |
48 | static_assert(layout_mapping_comparable<std::extents<T1, D>, std::extents<T2, D>>); |
49 | static_assert(layout_mapping_comparable<std::extents<T1, 5>, std::extents<T2, D>>); |
50 | static_assert(layout_mapping_comparable<std::extents<T1, D>, std::extents<T2, 5>>); |
51 | static_assert(layout_mapping_comparable<std::extents<T1, 5>, std::extents<T2, 5>>); |
52 | |
53 | // not equality comparable when rank is not the same |
54 | static_assert(!layout_mapping_comparable<std::extents<T1>, std::extents<T2, D>>); |
55 | static_assert(!layout_mapping_comparable<std::extents<T1>, std::extents<T2, 1>>); |
56 | static_assert(!layout_mapping_comparable<std::extents<T1, D>, std::extents<T2>>); |
57 | static_assert(!layout_mapping_comparable<std::extents<T1, 1>, std::extents<T2>>); |
58 | static_assert(!layout_mapping_comparable<std::extents<T1, D>, std::extents<T2, D, D>>); |
59 | static_assert(!layout_mapping_comparable<std::extents<T1, 5>, std::extents<T2, 5, D>>); |
60 | static_assert(!layout_mapping_comparable<std::extents<T1, 5>, std::extents<T2, 5, 1>>); |
61 | static_assert(!layout_mapping_comparable<std::extents<T1, D, D>, std::extents<T2, D>>); |
62 | static_assert(!layout_mapping_comparable<std::extents<T1, 5, D>, std::extents<T2, 5>>); |
63 | static_assert(!layout_mapping_comparable<std::extents<T1, 5, 1>, std::extents<T2, 5>>); |
64 | } |
65 | |
66 | template <class To, class From> |
67 | constexpr void test_comparison( |
68 | bool equal, |
69 | To dest_exts, |
70 | From src_exts, |
71 | std::array<int, To::rank()> dest_strides, |
72 | std::array<int, From::rank()> src_strides) { |
73 | std::layout_stride::mapping<To> dest(dest_exts, dest_strides); |
74 | std::layout_stride::mapping<From> src(src_exts, src_strides); |
75 | ASSERT_NOEXCEPT(dest == src); |
76 | assert((dest == src) == equal); |
77 | assert((dest != src) == !equal); |
78 | } |
79 | |
80 | template <class T1, class T2> |
81 | constexpr void test_comparison_same_rank() { |
82 | constexpr size_t D = std::dynamic_extent; |
83 | |
84 | test_comparison(true, std::extents<T1>(), std::extents<T2>(), std::array<int, 0>{}, std::array<int, 0>{}); |
85 | |
86 | test_comparison(true, std::extents<T1, D>(5), std::extents<T2, D>(5), std::array<int, 1>{1}, std::array<int, 1>{1}); |
87 | test_comparison(true, std::extents<T1, D>(0), std::extents<T2, D>(0), std::array<int, 1>{1}, std::array<int, 1>{1}); |
88 | test_comparison(true, std::extents<T1, 5>(), std::extents<T2, D>(5), std::array<int, 1>{3}, std::array<int, 1>{3}); |
89 | test_comparison(true, std::extents<T1, D>(5), std::extents<T2, 5>(), std::array<int, 1>{1}, std::array<int, 1>{1}); |
90 | test_comparison(true, std::extents<T1, 5>(), std::extents< T2, 5>(), std::array<int, 1>{1}, std::array<int, 1>{1}); |
91 | test_comparison(false, std::extents<T1, 5>(), std::extents<T2, D>(5), std::array<int, 1>{2}, std::array<int, 1>{1}); |
92 | test_comparison(false, std::extents<T1, D>(5), std::extents<T2, D>(5), std::array<int, 1>{2}, std::array<int, 1>{1}); |
93 | test_comparison(false, std::extents<T1, D>(5), std::extents<T2, D>(7), std::array<int, 1>{1}, std::array<int, 1>{1}); |
94 | test_comparison(false, std::extents<T1, 5>(), std::extents<T2, D>(7), std::array<int, 1>{1}, std::array<int, 1>{1}); |
95 | test_comparison(false, std::extents<T1, D>(5), std::extents<T2, 7>(), std::array<int, 1>{1}, std::array<int, 1>{1}); |
96 | test_comparison(false, std::extents<T1, 5>(), std::extents<T2, 7>(), std::array<int, 1>{1}, std::array<int, 1>{1}); |
97 | |
98 | test_comparison( |
99 | true, |
100 | std::extents<T1, D, D, D, D, D>(5, 6, 7, 8, 9), |
101 | std::extents<T2, D, D, D, D, D>(5, 6, 7, 8, 9), |
102 | std::array<int, 5>{2, 20, 200, 2000, 20000}, |
103 | std::array<int, 5>{2, 20, 200, 2000, 20000}); |
104 | test_comparison( |
105 | true, |
106 | std::extents<T1, D, 6, D, 8, D>(5, 7, 9), |
107 | std::extents<T2, 5, D, D, 8, 9>(6, 7), |
108 | std::array<int, 5>{2, 20, 200, 2000, 20000}, |
109 | std::array<int, 5>{2, 20, 200, 2000, 20000}); |
110 | test_comparison( |
111 | true, |
112 | std::extents<T1, 5, 6, 7, 8, 9>(5, 6, 7, 8, 9), |
113 | std::extents<T2, 5, 6, 7, 8, 9>(), |
114 | std::array<int, 5>{2, 20, 200, 2000, 20000}, |
115 | std::array<int, 5>{2, 20, 200, 2000, 20000}); |
116 | test_comparison( |
117 | false, |
118 | std::extents<T1, 5, 6, 7, 8, 9>(5, 6, 7, 8, 9), |
119 | std::extents<T2, 5, 6, 7, 8, 9>(), |
120 | std::array<int, 5>{2, 20, 200, 20000, 2000}, |
121 | std::array<int, 5>{2, 20, 200, 2000, 20000}); |
122 | test_comparison( |
123 | false, |
124 | std::extents<T1, D, D, D, D, D>(5, 6, 7, 8, 9), |
125 | std::extents<T2, D, D, D, D, D>(5, 6, 3, 8, 9), |
126 | std::array<int, 5>{2, 20, 200, 2000, 20000}, |
127 | std::array<int, 5>{2, 20, 200, 2000, 20000}); |
128 | test_comparison( |
129 | false, |
130 | std::extents<T1, D, 6, D, 8, D>(5, 7, 9), |
131 | std::extents<T2, 5, D, D, 3, 9>(6, 7), |
132 | std::array<int, 5>{2, 20, 200, 2000, 20000}, |
133 | std::array<int, 5>{2, 20, 200, 2000, 20000}); |
134 | test_comparison( |
135 | false, |
136 | std::extents<T1, 5, 6, 7, 8, 9>(5, 6, 7, 8, 9), |
137 | std::extents<T2, 5, 6, 7, 3, 9>(), |
138 | std::array<int, 5>{2, 20, 200, 2000, 20000}, |
139 | std::array<int, 5>{2, 20, 200, 2000, 20000}); |
140 | } |
141 | |
142 | template <class OtherLayout, class E1, class E2, class... OtherArgs> |
143 | constexpr void test_comparison_with( |
144 | bool expect_equal, E1 e1, std::array<typename E1::index_type, E1::rank()> strides, E2 e2, OtherArgs... other_args) { |
145 | std::layout_stride::mapping<E1> map(e1, strides); |
146 | typename OtherLayout::template mapping<E2> other_map(e2, other_args...); |
147 | |
148 | assert((map == other_map) == expect_equal); |
149 | } |
150 | |
151 | template <class OtherLayout> |
152 | constexpr void test_comparison_with() { |
153 | constexpr size_t D = std::dynamic_extent; |
154 | bool is_left_based = |
155 | std::is_same_v<OtherLayout, std::layout_left> || std::is_same_v<OtherLayout, always_convertible_layout>; |
156 | test_comparison_with<OtherLayout>(true, std::extents<int>(), std::array<int, 0>{}, std::extents<unsigned>()); |
157 | test_comparison_with<OtherLayout>(true, std::extents<int, 5>(), std::array<int, 1>{1}, std::extents<unsigned, 5>()); |
158 | test_comparison_with<OtherLayout>(true, std::extents<int, D>(5), std::array<int, 1>{1}, std::extents<unsigned, 5>()); |
159 | test_comparison_with<OtherLayout>(false, std::extents<int, D>(5), std::array<int, 1>{2}, std::extents<unsigned, 5>()); |
160 | test_comparison_with<OtherLayout>( |
161 | is_left_based, std::extents<int, D, D>(5, 7), std::array<int, 2>{1, 5}, std::extents<unsigned, D, D>(5, 7)); |
162 | test_comparison_with<OtherLayout>( |
163 | !is_left_based, std::extents<int, D, D>(5, 7), std::array<int, 2>{7, 1}, std::extents<unsigned, D, D>(5, 7)); |
164 | test_comparison_with<OtherLayout>( |
165 | false, std::extents<int, D, D>(5, 7), std::array<int, 2>{8, 1}, std::extents<unsigned, D, D>(5, 7)); |
166 | |
167 | if constexpr (std::is_same_v<OtherLayout, always_convertible_layout>) { |
168 | // test layout with strides not equal to product of extents |
169 | test_comparison_with<OtherLayout>( |
170 | true, std::extents<int, D, D>(5, 7), std::array<int, 2>{2, 10}, std::extents<unsigned, D, D>(5, 7), 0, 2); |
171 | // make sure that offset != 0 results in false |
172 | test_comparison_with<OtherLayout>( |
173 | false, std::extents<int, D, D>(5, 7), std::array<int, 2>{2, 10}, std::extents<unsigned, D, D>(5, 7), 1, 2); |
174 | } |
175 | } |
176 | |
177 | template <class T1, class T2> |
178 | constexpr void test_comparison_index_type() { |
179 | test_comparison_same_rank<T1, T2>(); |
180 | test_comparison_different_rank<T1, T2>(); |
181 | test_comparison_with<std::layout_right>(); |
182 | test_comparison_with<std::layout_left>(); |
183 | test_comparison_with<always_convertible_layout>(); |
184 | } |
185 | |
186 | constexpr bool test() { |
187 | test_comparison_index_type<int, int>(); |
188 | test_comparison_index_type<int, size_t>(); |
189 | test_comparison_index_type<size_t, int>(); |
190 | test_comparison_index_type<size_t, long>(); |
191 | return true; |
192 | } |
193 | |
194 | int main(int, char**) { |
195 | test(); |
196 | static_assert(test()); |
197 | return 0; |
198 | } |
199 | |