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