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 OtherExtents> 14 // constexpr explicit(!is_convertible_v<OtherExtents, extents_type>) 15 // mapping(const mapping<OtherExtents>&) noexcept; 16 17 // Constraints: is_constructible_v<extents_type, OtherExtents> is true. 18 // 19 // Preconditions: other.required_span_size() is representable as a value of type index_type 20 21 #include <mdspan> 22 #include <type_traits> 23 #include <cassert> 24 #include <limits> 25 26 #include "test_macros.h" 27 28 template <class To, class From> 29 constexpr void test_implicit_conversion(To dest, From src) { 30 assert(dest == src); 31 } 32 33 template <bool implicit, class ToE, class FromE> 34 constexpr void test_conversion(FromE src_exts) { 35 using To = std::layout_left::mapping<ToE>; 36 using From = std::layout_left::mapping<FromE>; 37 From src(src_exts); 38 39 ASSERT_NOEXCEPT(To(src)); 40 To dest(src); 41 42 assert(dest == src); 43 if constexpr (implicit) { 44 dest = src; 45 assert(dest == src); 46 test_implicit_conversion<To, From>(src, src); 47 } 48 } 49 50 template <class T1, class T2> 51 constexpr void test_conversion() { 52 constexpr size_t D = std::dynamic_extent; 53 constexpr bool idx_convertible = 54 static_cast<size_t>(std::numeric_limits<T1>::max()) >= static_cast<size_t>(std::numeric_limits<T2>::max()); 55 56 // clang-format off 57 test_conversion<idx_convertible && true, std::extents<T1>>(std::extents<T2>()); 58 test_conversion<idx_convertible && true, std::extents<T1, D>>(std::extents<T2, D>(5)); 59 test_conversion<idx_convertible && false, std::extents<T1, 5>>(std::extents<T2, D>(5)); 60 test_conversion<idx_convertible && true, std::extents<T1, 5>>(std::extents<T2, 5>()); 61 test_conversion<idx_convertible && false, std::extents<T1, 5, D>>(std::extents<T2, D, D>(5, 5)); 62 test_conversion<idx_convertible && true, std::extents<T1, D, D>>(std::extents<T2, D, D>(5, 5)); 63 test_conversion<idx_convertible && true, std::extents<T1, D, D>>(std::extents<T2, D, 7>(5)); 64 test_conversion<idx_convertible && true, std::extents<T1, 5, 7>>(std::extents<T2, 5, 7>()); 65 test_conversion<idx_convertible && false, std::extents<T1, 5, D, 8, D, D>>(std::extents<T2, D, D, 8, 9, 1>(5, 7)); 66 test_conversion<idx_convertible && true, std::extents<T1, D, D, D, D, D>>( 67 std::extents<T2, D, D, D, D, D>(5, 7, 8, 9, 1)); 68 test_conversion<idx_convertible && true, std::extents<T1, D, D, 8, 9, D>>(std::extents<T2, D, 7, 8, 9, 1>(5)); 69 test_conversion<idx_convertible && true, std::extents<T1, 5, 7, 8, 9, 1>>(std::extents<T2, 5, 7, 8, 9, 1>()); 70 // clang-format on 71 } 72 73 template <class IdxT, size_t... Extents> 74 using mapping_t = typename std::layout_left::template mapping<std::extents<IdxT, Extents...>>; 75 76 constexpr void test_no_implicit_conversion() { 77 constexpr size_t D = std::dynamic_extent; 78 79 // Sanity check that one static to dynamic conversion works 80 static_assert(std::is_constructible_v<mapping_t<int, D>, mapping_t<int, 5>>); 81 static_assert(std::is_convertible_v<mapping_t<int, 5>, mapping_t<int, D>>); 82 83 // Check that dynamic to static conversion only works explicitly 84 static_assert(std::is_constructible_v<mapping_t<int, 5>, mapping_t<int, D>>); 85 static_assert(!std::is_convertible_v<mapping_t<int, D>, mapping_t<int, 5>>); 86 87 // Sanity check that one static to dynamic conversion works 88 static_assert(std::is_constructible_v<mapping_t<int, D, 7>, mapping_t<int, 5, 7>>); 89 static_assert(std::is_convertible_v<mapping_t<int, 5, 7>, mapping_t<int, D, 7>>); 90 91 // Check that dynamic to static conversion only works explicitly 92 static_assert(std::is_constructible_v<mapping_t<int, 5, 7>, mapping_t<int, D, 7>>); 93 static_assert(!std::is_convertible_v<mapping_t<int, D, 7>, mapping_t<int, 5, 7>>); 94 95 // Sanity check that smaller index_type to larger index_type conversion works 96 static_assert(std::is_constructible_v<mapping_t<size_t, 5>, mapping_t<int, 5>>); 97 static_assert(std::is_convertible_v<mapping_t<int, 5>, mapping_t<size_t, 5>>); 98 99 // Check that larger index_type to smaller index_type conversion works explicitly only 100 static_assert(std::is_constructible_v<mapping_t<int, 5>, mapping_t<size_t, 5>>); 101 static_assert(!std::is_convertible_v<mapping_t<size_t, 5>, mapping_t<int, 5>>); 102 } 103 104 constexpr void test_rank_mismatch() { 105 constexpr size_t D = std::dynamic_extent; 106 107 static_assert(!std::is_constructible_v<mapping_t<int, D>, mapping_t<int>>); 108 static_assert(!std::is_constructible_v<mapping_t<int>, mapping_t<int, D, D>>); 109 static_assert(!std::is_constructible_v<mapping_t<int, D>, mapping_t<int, D, D>>); 110 static_assert(!std::is_constructible_v<mapping_t<int, D, D, D>, mapping_t<int, D, D>>); 111 } 112 113 constexpr void test_static_extent_mismatch() { 114 constexpr size_t D = std::dynamic_extent; 115 116 static_assert(!std::is_constructible_v<mapping_t<int, D, 5>, mapping_t<int, D, 4>>); 117 static_assert(!std::is_constructible_v<mapping_t<int, 5>, mapping_t<int, 4>>); 118 static_assert(!std::is_constructible_v<mapping_t<int, 5, D>, mapping_t<int, 4, D>>); 119 } 120 121 constexpr bool test() { 122 test_conversion<int, int>(); 123 test_conversion<int, size_t>(); 124 test_conversion<size_t, int>(); 125 test_conversion<size_t, long>(); 126 test_no_implicit_conversion(); 127 test_rank_mismatch(); 128 test_static_extent_mismatch(); 129 return true; 130 } 131 132 int main(int, char**) { 133 test(); 134 static_assert(test()); 135 return 0; 136 } 137