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 OtherIndexType> |
14 | // constexpr mapping(const extents_type& e, array<OtherIndexType, rank_> s) noexcept; |
15 | // |
16 | // Constraints: |
17 | // - is_convertible_v<const OtherIndexType&, index_type> is true, and |
18 | // - is_nothrow_constructible_v<index_type, const OtherIndexType&> is true. |
19 | // |
20 | // Preconditions: |
21 | // - s[i] > 0 is true for all i in the range [0, rank_). |
22 | // - REQUIRED-SPAN-SIZE(e, s) is representable as a value of type index_type ([basic.fundamental]). |
23 | // - If rank_ is greater than 0, then there exists a permutation P of the integers in the range [0, rank_), |
24 | // such that s[pi] >= s[pi_1] * e.extent(pi_1) is true for all i in the range [1, rank_), where pi is the ith element of P. |
25 | // Note 1: For layout_stride, this condition is necessary and sufficient for is_unique() to be true. |
26 | // |
27 | // Effects: Direct-non-list-initializes extents_ with e, and for all d in the range [0, rank_), |
28 | // direct-non-list-initializes strides_[d] with as_const(s[d]). |
29 | |
30 | #include <array> |
31 | #include <cassert> |
32 | #include <cstddef> |
33 | #include <cstdint> |
34 | #include <mdspan> |
35 | #include <type_traits> |
36 | |
37 | #include "test_macros.h" |
38 | #include "../ConvertibleToIntegral.h" |
39 | |
40 | template <class E, class S> |
41 | constexpr void test_construction(E e, S s) { |
42 | using M = std::layout_stride::mapping<E>; |
43 | ASSERT_NOEXCEPT(M{e, s}); |
44 | M m(e, s); |
45 | |
46 | // check correct extents are returned |
47 | ASSERT_NOEXCEPT(m.extents()); |
48 | assert(m.extents() == e); |
49 | |
50 | // check required_span_size() |
51 | typename E::index_type expected_size = 1; |
52 | for (typename E::rank_type r = 0; r < E::rank(); r++) { |
53 | if (e.extent(r) == 0) { |
54 | expected_size = 0; |
55 | break; |
56 | } |
57 | expected_size += (e.extent(r) - 1) * static_cast<typename E::index_type>(s[r]); |
58 | } |
59 | assert(m.required_span_size() == expected_size); |
60 | |
61 | // check strides: node stride function is constrained on rank>0, e.extent(r) is not |
62 | auto strides = m.strides(); |
63 | ASSERT_NOEXCEPT(m.strides()); |
64 | if constexpr (E::rank() > 0) { |
65 | for (typename E::rank_type r = 0; r < E::rank(); r++) { |
66 | assert(m.stride(r) == static_cast<typename E::index_type>(s[r])); |
67 | assert(strides[r] == m.stride(r)); |
68 | } |
69 | } |
70 | } |
71 | |
72 | constexpr bool test() { |
73 | constexpr size_t D = std::dynamic_extent; |
74 | { |
75 | std::array<int, 0> s{}; |
76 | test_construction(e: std::extents<int>(), s); |
77 | } |
78 | { |
79 | std::array<int, 1> s{1}; |
80 | test_construction(std::extents<unsigned, D>(7), s); |
81 | } |
82 | { |
83 | std::array<int, 1> s{1}; |
84 | test_construction(std::extents<unsigned, D>(0), s); |
85 | } |
86 | { |
87 | std::array<int, 1> s{2}; |
88 | test_construction(e: std::extents<unsigned, 7>(), s); |
89 | } |
90 | { |
91 | std::array<IntType, 1> s{1}; |
92 | test_construction(std::extents<int, D>(7), s); |
93 | } |
94 | { |
95 | std::array<int, 2> s{3, 30}; |
96 | test_construction(std::extents<unsigned, 7, 8>(), s); |
97 | } |
98 | { |
99 | std::array<int, 4> s{20, 2, 200, 2000}; |
100 | test_construction(std::extents<int64_t, D, 8, D, D>(7, 9, 10), s); |
101 | test_construction(std::extents<int64_t, D, 8, D, D>(0, 9, 10), s); |
102 | test_construction(std::extents<int64_t, D, 8, D, D>(0, 8, 0), s); |
103 | } |
104 | { |
105 | std::array<int, 4> s{200, 20, 20, 2000}; |
106 | test_construction(std::extents<int64_t, D, D, D, D>(7, 0, 8, 9), s); |
107 | test_construction(std::extents<int64_t, D, D, D, D>(7, 8, 0, 9), s); |
108 | test_construction(std::extents<int64_t, D, D, D, D>(7, 1, 8, 9), s); |
109 | test_construction(std::extents<int64_t, D, D, D, D>(7, 8, 1, 9), s); |
110 | test_construction(std::extents<int64_t, D, D, D, D>(7, 1, 1, 9), s); |
111 | test_construction(std::extents<int64_t, D, D, D, D>(7, 0, 0, 9), s); |
112 | test_construction(std::extents<int64_t, D, D, D, D>(7, 1, 1, 9), s); |
113 | test_construction(std::extents<int64_t, D, D, D, D>(7, 1, 0, 9), s); |
114 | test_construction(std::extents<int64_t, D, D, D, D>(7, 0, 1, 9), s); |
115 | } |
116 | |
117 | { |
118 | using mapping_t = std::layout_stride::mapping<std::dextents<unsigned, 2>>; |
119 | // wrong strides size |
120 | static_assert(!std::is_constructible_v<mapping_t, std::dextents<int, 2>, std::array<int, 3>>); |
121 | static_assert(!std::is_constructible_v<mapping_t, std::dextents<int, 2>, std::array<int, 1>>); |
122 | // wrong extents rank |
123 | static_assert(!std::is_constructible_v<mapping_t, std::dextents<int, 3>, std::array<int, 2>>); |
124 | // none-convertible strides |
125 | static_assert(!std::is_constructible_v<mapping_t, std::dextents<int, 2>, std::array<IntType, 2>>); |
126 | } |
127 | { |
128 | // not no-throw constructible index_type from stride |
129 | using mapping_t = std::layout_stride::mapping<std::dextents<unsigned char, 2>>; |
130 | static_assert(std::is_convertible_v<IntType, unsigned char>); |
131 | static_assert(!std::is_constructible_v<mapping_t, std::dextents<int, 2>, std::array<IntType, 2>>); |
132 | } |
133 | |
134 | return true; |
135 | } |
136 | |
137 | int main(int, char**) { |
138 | test(); |
139 | static_assert(test()); |
140 | return 0; |
141 | } |
142 | |