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, span<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 <mdspan> |
31 | #include <cassert> |
32 | #include <cstdint> |
33 | |
34 | #include "test_macros.h" |
35 | #include "../ConvertibleToIntegral.h" |
36 | |
37 | template <class E, class S> |
38 | constexpr void test_construction(E e, S s) { |
39 | using M = std::layout_stride::mapping<E>; |
40 | ASSERT_NOEXCEPT(M{e, s}); |
41 | M m(e, s); |
42 | |
43 | // check correct extents are returned |
44 | ASSERT_NOEXCEPT(m.extents()); |
45 | assert(m.extents() == e); |
46 | |
47 | // check required_span_size() |
48 | typename E::index_type expected_size = 1; |
49 | for (typename E::rank_type r = 0; r < E::rank(); r++) { |
50 | if (e.extent(r) == 0) { |
51 | expected_size = 0; |
52 | break; |
53 | } |
54 | expected_size += (e.extent(r) - 1) * static_cast<typename E::index_type>(s[r]); |
55 | } |
56 | assert(m.required_span_size() == expected_size); |
57 | |
58 | // check strides: node stride function is constrained on rank>0, e.extent(r) is not |
59 | auto strides = m.strides(); |
60 | ASSERT_NOEXCEPT(m.strides()); |
61 | if constexpr (E::rank() > 0) { |
62 | for (typename E::rank_type r = 0; r < E::rank(); r++) { |
63 | assert(m.stride(r) == static_cast<typename E::index_type>(s[r])); |
64 | assert(strides[r] == m.stride(r)); |
65 | } |
66 | } |
67 | } |
68 | |
69 | constexpr bool test() { |
70 | constexpr size_t D = std::dynamic_extent; |
71 | { |
72 | std::array<int, 0> s{}; |
73 | test_construction(std::extents<int>(), std::span(s)); |
74 | } |
75 | { |
76 | std::array<int, 1> s{1}; |
77 | test_construction(std::extents<unsigned, D>(7), std::span(s)); |
78 | } |
79 | { |
80 | std::array<int, 1> s{1}; |
81 | test_construction(std::extents<unsigned, D>(0), std::span(s)); |
82 | } |
83 | { |
84 | std::array<int, 1> s{2}; |
85 | test_construction(std::extents<unsigned, 7>(), std::span(s)); |
86 | } |
87 | { |
88 | std::array<IntType, 1> s{1}; |
89 | test_construction(std::extents<int, D>(7), std::span(s)); |
90 | } |
91 | { |
92 | std::array<int, 2> s{3, 30}; |
93 | test_construction(std::extents<unsigned, 7, 8>(), std::span(s)); |
94 | } |
95 | { |
96 | std::array<int, 4> s{20, 2, 200, 2000}; |
97 | test_construction(std::extents<int64_t, D, 8, D, D>(7, 9, 10), std::span(s)); |
98 | } |
99 | { |
100 | std::array<int, 4> s{20, 2, 200, 2000}; |
101 | test_construction(std::extents<int64_t, D, 8, D, D>(7, 0, 10), std::span(s)); |
102 | test_construction(std::extents<int64_t, D, 8, D, D>(0, 9, 10), std::span(s)); |
103 | test_construction(std::extents<int64_t, D, 8, D, D>(0, 8, 0), std::span(s)); |
104 | } |
105 | { |
106 | std::array<int, 4> s{200, 20, 20, 2000}; |
107 | test_construction(std::extents<int64_t, D, D, D, D>(7, 0, 8, 9), std::span(s)); |
108 | test_construction(std::extents<int64_t, D, D, D, D>(7, 8, 0, 9), std::span(s)); |
109 | test_construction(std::extents<int64_t, D, D, D, D>(7, 1, 8, 9), std::span(s)); |
110 | test_construction(std::extents<int64_t, D, D, D, D>(7, 8, 1, 9), std::span(s)); |
111 | test_construction(std::extents<int64_t, D, D, D, D>(7, 1, 1, 9), std::span(s)); |
112 | test_construction(std::extents<int64_t, D, D, D, D>(7, 0, 0, 9), std::span(s)); |
113 | test_construction(std::extents<int64_t, D, D, D, D>(7, 1, 1, 9), std::span(s)); |
114 | test_construction(std::extents<int64_t, D, D, D, D>(7, 1, 0, 9), std::span(s)); |
115 | test_construction(std::extents<int64_t, D, D, D, D>(7, 0, 1, 9), std::span(s)); |
116 | } |
117 | |
118 | { |
119 | using mapping_t = std::layout_stride::mapping<std::dextents<unsigned, 2>>; |
120 | // wrong strides size |
121 | static_assert(!std::is_constructible_v<mapping_t, std::dextents<int, 2>, std::span<int, 3>>); |
122 | static_assert(!std::is_constructible_v<mapping_t, std::dextents<int, 2>, std::span<int, 1>>); |
123 | // wrong extents rank |
124 | static_assert(!std::is_constructible_v<mapping_t, std::dextents<int, 3>, std::span<int, 2>>); |
125 | // none-convertible strides |
126 | static_assert(!std::is_constructible_v<mapping_t, std::dextents<int, 2>, std::span<IntType, 2>>); |
127 | } |
128 | { |
129 | // not no-throw constructible index_type from stride |
130 | using mapping_t = std::layout_stride::mapping<std::dextents<unsigned char, 2>>; |
131 | static_assert(std::is_convertible_v<IntType, unsigned char>); |
132 | static_assert(!std::is_constructible_v<mapping_t, std::dextents<int, 2>, std::span<IntType, 2>>); |
133 | } |
134 | return true; |
135 | } |
136 | |
137 | int main(int, char**) { |
138 | test(); |
139 | static_assert(test()); |
140 | return 0; |
141 | } |
142 | |