1 | #ifndef BOOST_MULTI_ARRAY_GENERATIVE_TESTS_HPP |
2 | #define BOOST_MULTI_ARRAY_GENERATIVE_TESTS_HPP |
3 | |
4 | // Copyright 2002 The Trustees of Indiana University. |
5 | |
6 | // Use, modification and distribution is subject to the Boost Software |
7 | // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at |
8 | // http://www.boost.org/LICENSE_1_0.txt) |
9 | |
10 | // Boost.MultiArray Library |
11 | // Authors: Ronald Garcia |
12 | // Jeremy Siek |
13 | // Andrew Lumsdaine |
14 | // See http://www.boost.org/libs/multi_array for documentation. |
15 | |
16 | // |
17 | // generative-tests.hpp - Framework for running tests on all the types |
18 | // of multi_array |
19 | // |
20 | // In order to create a set of tests, you must define the following two |
21 | // function signatures: |
22 | // template <typename Array> |
23 | // void access(Array& A, const mutable_array_tag&); |
24 | // |
25 | // template <typename Array> |
26 | // void access(Array& A, const const_array_tag&); |
27 | // |
28 | // The framework will always pass 2x3x4 arrays into these functions. |
29 | // The const_array_tag version of access must NOT attempt to modify |
30 | // the array. Assume that the passed array has constness in this case. |
31 | // |
32 | // The mutable_array_tag version of access should pass the array to the |
33 | // assign() function in order to set its values before running tests. |
34 | // |
35 | // If you wish to write your own code to assign data to the array |
36 | // (ie. test the iterators by assigning data with them), you must |
37 | // #define MULTIARRAY_TEST_ASSIGN before including this file. |
38 | // assign() will call this function. |
39 | // |
40 | // If you wish to know how many tests were run, you must increment |
41 | // the global variable 'tests_run' somewhere in your test code. |
42 | // |
43 | // Since generative-tests uses the Boost.Test framework, you must |
44 | // define at least the following: |
45 | // |
46 | // int test_main(int,char*[]) { return run_generative_tests(); } |
47 | // |
48 | #include <boost/multi_array.hpp> |
49 | |
50 | #include <boost/core/lightweight_test.hpp> |
51 | |
52 | #include <boost/config.hpp> /* BOOST_NO_SFINAE */ |
53 | #include <algorithm> |
54 | #include <iostream> |
55 | #include <vector> |
56 | |
57 | namespace { |
58 | unsigned int tests_run = 0; |
59 | } // empty namespace |
60 | |
61 | struct mutable_array_tag { }; |
62 | struct const_array_tag { }; |
63 | |
64 | template <typename Array> |
65 | void assign_if_not_const(Array&, const const_array_tag&) { |
66 | // do nothing |
67 | } |
68 | |
69 | template <typename Array> |
70 | void assign_if_not_const(Array& A, const mutable_array_tag&); |
71 | |
72 | #ifndef MULTIARRAY_TEST_ASSIGN |
73 | template <typename Array> |
74 | void assign_if_not_const(Array& A, const mutable_array_tag&) { |
75 | |
76 | typedef typename Array::index index; |
77 | |
78 | const index idx0 = A.index_bases()[0]; |
79 | const index idx1 = A.index_bases()[1]; |
80 | const index idx2 = A.index_bases()[2]; |
81 | |
82 | |
83 | int num = 0; |
84 | for (index i = idx0; i != idx0 + 2; ++i) |
85 | for (index j = idx1; j != idx1 + 3; ++j) |
86 | for (index k = idx2; k != idx2 + 4; ++k) |
87 | A[i][j][k] = num++; |
88 | } |
89 | #endif // MULTIARRAY_TEST_ASSIGN |
90 | |
91 | template <typename Array> |
92 | void assign(Array& A) { |
93 | assign_if_not_const(A,mutable_array_tag()); |
94 | } |
95 | |
96 | template <typename Array> |
97 | void access(Array& A, const mutable_array_tag&); |
98 | |
99 | template <typename Array> |
100 | void access(Array& A, const const_array_tag&); |
101 | |
102 | template <typename StorageOrder3,typename StorageOrder4,typename Modifier> |
103 | void run_configuration(const StorageOrder3& so3, |
104 | const StorageOrder4& so4, |
105 | const Modifier& modifier) { |
106 | // multi_array |
107 | { |
108 | typedef boost::multi_array<int,3> array; |
109 | typename array::extent_gen extents; |
110 | { |
111 | array A(extents[2][3][4],so3); |
112 | modifier.modify(A); |
113 | access(A,mutable_array_tag()); |
114 | } |
115 | } |
116 | // multi_array_ref |
117 | { |
118 | typedef boost::multi_array_ref<int,3> array_ref; |
119 | typename array_ref::extent_gen extents; |
120 | { |
121 | int local[24]; |
122 | array_ref A(local,extents[2][3][4],so3); |
123 | modifier.modify(A); |
124 | access(A,mutable_array_tag()); |
125 | } |
126 | } |
127 | // const_multi_array_ref |
128 | { |
129 | typedef boost::multi_array_ref<int,3> array_ref; |
130 | typedef boost::const_multi_array_ref<int,3> const_array_ref; |
131 | typename array_ref::extent_gen extents; |
132 | { |
133 | int local[24]; |
134 | array_ref A(local,extents[2][3][4],so3); |
135 | modifier.modify(A); |
136 | assign(A); |
137 | |
138 | const_array_ref B = A; |
139 | access(A&: B,const_array_tag()); |
140 | } |
141 | } |
142 | // sub_array |
143 | { |
144 | typedef boost::multi_array<int,4> array; |
145 | typename array::extent_gen extents; |
146 | { |
147 | array A(extents[2][2][3][4],so4); |
148 | modifier.modify(A); |
149 | typename array::template subarray<3>::type B = A[1]; |
150 | access(A&: B,mutable_array_tag()); |
151 | } |
152 | } |
153 | // const_sub_array |
154 | { |
155 | typedef boost::multi_array<int,4> array; |
156 | typename array::extent_gen extents; |
157 | { |
158 | array A(extents[2][2][3][4],so4); |
159 | modifier.modify(A); |
160 | typename array::template subarray<3>::type B = A[1]; |
161 | assign(A&: B); |
162 | |
163 | typename array::template const_subarray<3>::type C = B; |
164 | access(A&: C,const_array_tag()); |
165 | } |
166 | } |
167 | // array_view |
168 | { |
169 | typedef boost::multi_array<int,3> array; |
170 | typedef typename array::index_range range; |
171 | typename array::index_gen indices; |
172 | typename array::extent_gen extents; |
173 | { |
174 | typedef typename array::index index; |
175 | |
176 | array A(extents[4][5][6],so3); |
177 | modifier.modify(A); |
178 | const index idx0 = A.index_bases()[0]; |
179 | const index idx1 = A.index_bases()[1]; |
180 | const index idx2 = A.index_bases()[2]; |
181 | |
182 | typename array::template array_view<3>::type B =A[ |
183 | indices[range(idx0+1,idx0+3)] |
184 | [range(idx1+1,idx1+4)] |
185 | [range(idx2+1,idx2+5)] |
186 | ]; |
187 | access(A&: B,mutable_array_tag()); |
188 | } |
189 | } |
190 | // const_array_view |
191 | { |
192 | typedef boost::multi_array<int,3> array; |
193 | typedef typename array::index_range range; |
194 | typename array::index_gen indices; |
195 | typename array::extent_gen extents; |
196 | { |
197 | typedef typename array::index index; |
198 | |
199 | array A(extents[4][5][6],so3); |
200 | modifier.modify(A); |
201 | const index idx0 = A.index_bases()[0]; |
202 | const index idx1 = A.index_bases()[1]; |
203 | const index idx2 = A.index_bases()[2]; |
204 | |
205 | typename array::template array_view<3>::type B =A[ |
206 | indices[range(idx0+1,idx0+3)] |
207 | [range(idx1+1,idx1+4)] |
208 | [range(idx2+1,idx2+5)] |
209 | ]; |
210 | assign(A&: B); |
211 | |
212 | typename array::template const_array_view<3>::type C = B; |
213 | access(A&: C,const_array_tag()); |
214 | } |
215 | } |
216 | } |
217 | |
218 | template <typename ArrayModifier> |
219 | void run_storage_tests(const ArrayModifier& modifier) { |
220 | run_configuration(boost::c_storage_order(), |
221 | boost::c_storage_order(),modifier); |
222 | run_configuration(boost::fortran_storage_order(), |
223 | boost::fortran_storage_order(),modifier); |
224 | |
225 | std::size_t ordering[] = {2,0,1,3}; |
226 | bool ascending[] = {false,true,true,true}; |
227 | run_configuration(boost::general_storage_order<3>(ordering,ascending), |
228 | boost::general_storage_order<4>(ordering,ascending), |
229 | modifier); |
230 | } |
231 | |
232 | struct null_modifier { |
233 | template <typename Array> |
234 | void modify(Array&) const { } |
235 | }; |
236 | |
237 | struct set_index_base_modifier { |
238 | template <typename Array> |
239 | void modify(Array& A) const { |
240 | #ifdef BOOST_NO_SFINAE |
241 | typedef boost::multi_array_types::index index; |
242 | A.reindex(index(1)); |
243 | #else |
244 | A.reindex(1); |
245 | #endif |
246 | } |
247 | }; |
248 | |
249 | struct reindex_modifier { |
250 | template <typename Array> |
251 | void modify(Array& A) const { |
252 | boost::array<int,4> bases = {.elems: {1,2,3,4}}; |
253 | A.reindex(bases); |
254 | } |
255 | }; |
256 | |
257 | struct reshape_modifier { |
258 | template <typename Array> |
259 | void modify(Array& A) const { |
260 | typedef typename Array::size_type size_type; |
261 | std::vector<size_type> old_shape(A.num_dimensions()); |
262 | std::vector<size_type> new_shape(A.num_dimensions()); |
263 | |
264 | std::copy(A.shape(),A.shape()+A.num_dimensions(),old_shape.begin()); |
265 | std::copy(old_shape.rbegin(),old_shape.rend(),new_shape.begin()); |
266 | |
267 | A.reshape(new_shape); |
268 | A.reshape(old_shape); |
269 | } |
270 | }; |
271 | |
272 | int run_generative_tests() { |
273 | |
274 | run_storage_tests(modifier: null_modifier()); |
275 | run_storage_tests(modifier: set_index_base_modifier()); |
276 | run_storage_tests(modifier: reindex_modifier()); |
277 | run_storage_tests(modifier: reshape_modifier()); |
278 | std::cout << "Total Tests Run: " << tests_run << '\n'; |
279 | return boost::report_errors(); |
280 | } |
281 | |
282 | #endif |
283 | |