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 <cassert> 27 #include <concepts> 28 #include <span> // dynamic_extent 29 #include <type_traits> 30 31 #include "test_macros.h" 32 33 #include "../CustomTestLayouts.h" 34 35 template <class E1, class E2> 36 concept layout_mapping_comparable = requires( 37 E1 e1, 38 E2 e2, 39 std::array<typename E1::index_type, E1::rank()> s1, 40 std::array<typename E1::index_type, E1::rank()> s2) { 41 std::layout_stride::mapping<E1>(e1, s1) == std::layout_stride::mapping<E2>(e2, s2); 42 }; 43 44 template <class T1, class T2> 45 constexpr void test_comparison_different_rank() { 46 constexpr size_t D = std::dynamic_extent; 47 48 // sanity check same rank 49 static_assert(layout_mapping_comparable<std::extents<T1, D>, std::extents<T2, D>>); 50 static_assert(layout_mapping_comparable<std::extents<T1, 5>, std::extents<T2, D>>); 51 static_assert(layout_mapping_comparable<std::extents<T1, D>, std::extents<T2, 5>>); 52 static_assert(layout_mapping_comparable<std::extents<T1, 5>, std::extents<T2, 5>>); 53 54 // not equality comparable when rank is not the same 55 static_assert(!layout_mapping_comparable<std::extents<T1>, std::extents<T2, D>>); 56 static_assert(!layout_mapping_comparable<std::extents<T1>, std::extents<T2, 1>>); 57 static_assert(!layout_mapping_comparable<std::extents<T1, D>, std::extents<T2>>); 58 static_assert(!layout_mapping_comparable<std::extents<T1, 1>, std::extents<T2>>); 59 static_assert(!layout_mapping_comparable<std::extents<T1, D>, std::extents<T2, D, D>>); 60 static_assert(!layout_mapping_comparable<std::extents<T1, 5>, std::extents<T2, 5, D>>); 61 static_assert(!layout_mapping_comparable<std::extents<T1, 5>, std::extents<T2, 5, 1>>); 62 static_assert(!layout_mapping_comparable<std::extents<T1, D, D>, std::extents<T2, D>>); 63 static_assert(!layout_mapping_comparable<std::extents<T1, 5, D>, std::extents<T2, 5>>); 64 static_assert(!layout_mapping_comparable<std::extents<T1, 5, 1>, std::extents<T2, 5>>); 65 } 66 67 template <class To, class From> 68 constexpr void test_comparison( 69 bool equal, 70 To dest_exts, 71 From src_exts, 72 std::array<int, To::rank()> dest_strides, 73 std::array<int, From::rank()> src_strides) { 74 std::layout_stride::mapping<To> dest(dest_exts, dest_strides); 75 std::layout_stride::mapping<From> src(src_exts, src_strides); 76 ASSERT_NOEXCEPT(dest == src); 77 assert((dest == src) == equal); 78 assert((dest != src) == !equal); 79 } 80 81 template <class T1, class T2> 82 constexpr void test_comparison_same_rank() { 83 constexpr size_t D = std::dynamic_extent; 84 85 test_comparison(true, std::extents<T1>(), std::extents<T2>(), std::array<int, 0>{}, std::array<int, 0>{}); 86 87 test_comparison(true, std::extents<T1, D>(5), std::extents<T2, D>(5), std::array<int, 1>{1}, std::array<int, 1>{1}); 88 test_comparison(true, std::extents<T1, D>(0), std::extents<T2, D>(0), std::array<int, 1>{1}, std::array<int, 1>{1}); 89 test_comparison(true, std::extents<T1, 5>(), std::extents<T2, D>(5), std::array<int, 1>{3}, std::array<int, 1>{3}); 90 test_comparison(true, std::extents<T1, D>(5), std::extents<T2, 5>(), std::array<int, 1>{1}, std::array<int, 1>{1}); 91 test_comparison(true, std::extents<T1, 5>(), std::extents< T2, 5>(), std::array<int, 1>{1}, std::array<int, 1>{1}); 92 test_comparison(false, std::extents<T1, 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>(5), std::array<int, 1>{2}, std::array<int, 1>{1}); 94 test_comparison(false, std::extents<T1, D>(5), std::extents<T2, D>(7), std::array<int, 1>{1}, std::array<int, 1>{1}); 95 test_comparison(false, std::extents<T1, 5>(), std::extents<T2, D>(7), std::array<int, 1>{1}, std::array<int, 1>{1}); 96 test_comparison(false, std::extents<T1, D>(5), std::extents<T2, 7>(), std::array<int, 1>{1}, std::array<int, 1>{1}); 97 test_comparison(false, std::extents<T1, 5>(), std::extents<T2, 7>(), std::array<int, 1>{1}, std::array<int, 1>{1}); 98 99 test_comparison( 100 true, 101 std::extents<T1, D, D, D, D, D>(5, 6, 7, 8, 9), 102 std::extents<T2, D, D, D, D, D>(5, 6, 7, 8, 9), 103 std::array<int, 5>{2, 20, 200, 2000, 20000}, 104 std::array<int, 5>{2, 20, 200, 2000, 20000}); 105 test_comparison( 106 true, 107 std::extents<T1, D, 6, D, 8, D>(5, 7, 9), 108 std::extents<T2, 5, D, D, 8, 9>(6, 7), 109 std::array<int, 5>{2, 20, 200, 2000, 20000}, 110 std::array<int, 5>{2, 20, 200, 2000, 20000}); 111 test_comparison( 112 true, 113 std::extents<T1, 5, 6, 7, 8, 9>(5, 6, 7, 8, 9), 114 std::extents<T2, 5, 6, 7, 8, 9>(), 115 std::array<int, 5>{2, 20, 200, 2000, 20000}, 116 std::array<int, 5>{2, 20, 200, 2000, 20000}); 117 test_comparison( 118 false, 119 std::extents<T1, 5, 6, 7, 8, 9>(5, 6, 7, 8, 9), 120 std::extents<T2, 5, 6, 7, 8, 9>(), 121 std::array<int, 5>{2, 20, 200, 20000, 2000}, 122 std::array<int, 5>{2, 20, 200, 2000, 20000}); 123 test_comparison( 124 false, 125 std::extents<T1, D, D, D, D, D>(5, 6, 7, 8, 9), 126 std::extents<T2, D, D, D, D, D>(5, 6, 3, 8, 9), 127 std::array<int, 5>{2, 20, 200, 2000, 20000}, 128 std::array<int, 5>{2, 20, 200, 2000, 20000}); 129 test_comparison( 130 false, 131 std::extents<T1, D, 6, D, 8, D>(5, 7, 9), 132 std::extents<T2, 5, D, D, 3, 9>(6, 7), 133 std::array<int, 5>{2, 20, 200, 2000, 20000}, 134 std::array<int, 5>{2, 20, 200, 2000, 20000}); 135 test_comparison( 136 false, 137 std::extents<T1, 5, 6, 7, 8, 9>(5, 6, 7, 8, 9), 138 std::extents<T2, 5, 6, 7, 3, 9>(), 139 std::array<int, 5>{2, 20, 200, 2000, 20000}, 140 std::array<int, 5>{2, 20, 200, 2000, 20000}); 141 } 142 143 template <class OtherLayout, class E1, class E2, class... OtherArgs> 144 constexpr void test_comparison_with( 145 bool expect_equal, E1 e1, std::array<typename E1::index_type, E1::rank()> strides, E2 e2, OtherArgs... other_args) { 146 std::layout_stride::mapping<E1> map(e1, strides); 147 typename OtherLayout::template mapping<E2> other_map(e2, other_args...); 148 149 assert((map == other_map) == expect_equal); 150 } 151 152 template <class OtherLayout> 153 constexpr void test_comparison_with() { 154 constexpr size_t D = std::dynamic_extent; 155 bool is_left_based = 156 std::is_same_v<OtherLayout, std::layout_left> || std::is_same_v<OtherLayout, always_convertible_layout>; 157 test_comparison_with<OtherLayout>(true, std::extents<int>(), std::array<int, 0>{}, std::extents<unsigned>()); 158 test_comparison_with<OtherLayout>(true, std::extents<int, 5>(), std::array<int, 1>{1}, std::extents<unsigned, 5>()); 159 test_comparison_with<OtherLayout>(true, std::extents<int, D>(5), std::array<int, 1>{1}, std::extents<unsigned, 5>()); 160 test_comparison_with<OtherLayout>(false, std::extents<int, D>(5), std::array<int, 1>{2}, std::extents<unsigned, 5>()); 161 test_comparison_with<OtherLayout>( 162 is_left_based, std::extents<int, D, D>(5, 7), std::array<int, 2>{1, 5}, std::extents<unsigned, D, D>(5, 7)); 163 test_comparison_with<OtherLayout>( 164 !is_left_based, std::extents<int, D, D>(5, 7), std::array<int, 2>{7, 1}, std::extents<unsigned, D, D>(5, 7)); 165 test_comparison_with<OtherLayout>( 166 false, std::extents<int, D, D>(5, 7), std::array<int, 2>{8, 1}, std::extents<unsigned, D, D>(5, 7)); 167 168 if constexpr (std::is_same_v<OtherLayout, always_convertible_layout>) { 169 // test layout with strides not equal to product of extents 170 test_comparison_with<OtherLayout>( 171 true, std::extents<int, D, D>(5, 7), std::array<int, 2>{2, 10}, std::extents<unsigned, D, D>(5, 7), 0, 2); 172 // make sure that offset != 0 results in false 173 test_comparison_with<OtherLayout>( 174 false, std::extents<int, D, D>(5, 7), std::array<int, 2>{2, 10}, std::extents<unsigned, D, D>(5, 7), 1, 2); 175 } 176 } 177 178 template <class T1, class T2> 179 constexpr void test_comparison_index_type() { 180 test_comparison_same_rank<T1, T2>(); 181 test_comparison_different_rank<T1, T2>(); 182 test_comparison_with<std::layout_right>(); 183 test_comparison_with<std::layout_left>(); 184 test_comparison_with<always_convertible_layout>(); 185 } 186 187 constexpr bool test() { 188 test_comparison_index_type<int, int>(); 189 test_comparison_index_type<int, size_t>(); 190 test_comparison_index_type<size_t, int>(); 191 test_comparison_index_type<size_t, long>(); 192 return true; 193 } 194 195 int main(int, char**) { 196 test(); 197 static_assert(test()); 198 return 0; 199 } 200