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>
assign_if_not_const(Array &,const const_array_tag &)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>
assign_if_not_const(Array & A,const mutable_array_tag &)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>
assign(Array & A)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>
run_configuration(const StorageOrder3 & so3,const StorageOrder4 & so4,const Modifier & 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(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(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(B);
162
163 typename array::template const_subarray<3>::type C = B;
164 access(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(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(B);
211
212 typename array::template const_array_view<3>::type C = B;
213 access(C,const_array_tag());
214 }
215 }
216 }
217
218 template <typename ArrayModifier>
run_storage_tests(const ArrayModifier & modifier)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>
modifynull_modifier234 void modify(Array&) const { }
235 };
236
237 struct set_index_base_modifier {
238 template <typename Array>
modifyset_index_base_modifier239 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>
modifyreindex_modifier251 void modify(Array& A) const {
252 boost::array<int,4> bases = {{1,2,3,4}};
253 A.reindex(bases);
254 }
255 };
256
257 struct reshape_modifier {
258 template <typename Array>
modifyreshape_modifier259 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
run_generative_tests()272 int run_generative_tests() {
273
274 run_storage_tests(null_modifier());
275 run_storage_tests(set_index_base_modifier());
276 run_storage_tests(reindex_modifier());
277 run_storage_tests(reshape_modifier());
278 std::cout << "Total Tests Run: " << tests_run << '\n';
279 return boost::report_errors();
280 }
281
282 #endif
283