1 /***************************************************************************
2 * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht          *
3 * Copyright (c) QuantStack                                                 *
4 *                                                                          *
5 * Distributed under the terms of the BSD 3-Clause License.                 *
6 *                                                                          *
7 * The full license is in the file LICENSE, distributed with this software. *
8 ****************************************************************************/
9 
10 #ifndef TEST_COMMON_HPP
11 #define TEST_COMMON_HPP
12 
13 #include <sstream>
14 
15 #include "xtensor/xlayout.hpp"
16 #include "xtensor/xmanipulation.hpp"
17 #include "xtensor/xreducer.hpp" // tuple_idx_of
18 
19 #include "test_common_macros.hpp"
20 
21 // the tests used to be implemented with gtest
22 // testing::Types<...> and testing::Test
23 // where introduced to keep compatible
24 // with the gtest test where we can
25 namespace testing
26 {
27     template<class ... ARGS>
28     using Types = std::tuple<ARGS ...>;
29 
30     struct Test{};
31 }
32 
33 namespace xt
34 {
35     template<class C>
stringify(const C & container)36     std::string stringify(const C & container)
37     {
38         std::size_t i = 0;
39         std::stringstream ss;
40         ss << "[";
41         for(auto && c : container)
42         {
43             if(i + 1 == container.size())
44             {
45                 ss<<c;
46             }
47             else
48             {
49                 ss<<c<<",";
50             }
51             ++i;
52         }
53         ss << "]";
54         return ss.str();
55     }
56 
57     template <class T, class A, class AV>
operator ==(const uvector<T,A> & lhs,const std::vector<T,AV> & rhs)58     bool operator==(const uvector<T, A>& lhs, const std::vector<T, AV>& rhs)
59     {
60         return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin());
61     }
62 
63     template <class T, class A, class AV>
operator ==(const std::vector<T,AV> & lhs,const uvector<T,A> & rhs)64     bool operator==(const std::vector<T, AV>& lhs, const uvector<T, A>& rhs)
65     {
66         return rhs == lhs;
67     }
68 
69     template <class C = dynamic_shape<std::size_t>>
70     struct layout_result
71     {
72         using vector_type = uvector<int, XTENSOR_DEFAULT_ALLOCATOR(int)>;
73         using size_type = typename C::value_type;
74         using difference_type = typename C::difference_type;
75         using shape_type = C;
76         using strides_type = get_strides_t<C>;
77 
78         using assigner_type = std::vector<std::vector<vector_type>>;
79 
layout_resultxt::layout_result80         inline layout_result()
81         {
82             m_shape = {3, 2, 4};
83             m_assigner.resize(m_shape[0]);
84             for (size_type i = 0; i < m_shape[0]; ++i)
85             {
86                 m_assigner[i].resize(m_shape[1]);
87             }
88             m_assigner[0][0] = {-1, 1, 2, 3};
89             m_assigner[0][1] = {4, 5, 6, 7};
90             m_assigner[1][0] = {8, 9, 10, 11};
91             m_assigner[1][1] = {12, 13, 14, 15};
92             m_assigner[2][0] = {16, 17, 18, 19};
93             m_assigner[2][1] = {20, 21, 22, 23};
94         }
95 
96         shape_type m_shape;
97         strides_type m_strides;
98         strides_type m_backstrides;
99         vector_type m_data;
100         layout_type m_layout;
101         assigner_type m_assigner;
102 
sizext::layout_result103         inline size_type size() const { return m_data.size(); }
shapext::layout_result104         inline const shape_type& shape() const { return m_shape; }
stridesxt::layout_result105         inline const strides_type& strides() const { return m_strides; }
backstridesxt::layout_result106         inline const strides_type& backstrides() const { return m_backstrides; }
layoutxt::layout_result107         inline layout_type layout() const { return m_layout; }
storagext::layout_result108         inline const vector_type& storage() const { return m_data; }
109     };
110 
111     template <class C = dynamic_shape<std::size_t>>
112     struct row_major_result : layout_result<C>
113     {
row_major_resultxt::row_major_result114         inline row_major_result()
115         {
116             this->m_strides = {8, 4, 1};
117             this->m_backstrides = {16, 4, 3};
118             this->m_data = {-1, 1, 2, 3, 4, 5, 6, 7, 8, 9,
119                             10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
120                             20, 21, 22, 23};
121             this->m_layout = layout_type::row_major;
122         }
123     };
124 
125     template <class C = dynamic_shape<std::size_t>>
126     struct column_major_result : layout_result<C>
127     {
column_major_resultxt::column_major_result128         inline column_major_result()
129         {
130             this->m_strides = {1, 3, 6};
131             this->m_backstrides = {2, 3, 18};
132             this->m_data = {-1, 8, 16, 4, 12, 20,
133                              1, 9, 17, 5, 13, 21,
134                              2, 10, 18, 6, 14, 22,
135                              3, 11, 19, 7, 15, 23};
136             this->m_layout = layout_type::column_major;
137         }
138     };
139 
140     template <class C = dynamic_shape<std::size_t>>
141     struct central_major_result : layout_result<C>
142     {
central_major_resultxt::central_major_result143         inline central_major_result()
144         {
145             this->m_strides = {8, 1, 2};
146             this->m_backstrides = {16, 1, 6};
147             this->m_data = {-1, 4, 1, 5, 2, 6, 3, 7,
148                             8, 12, 9, 13, 10, 14, 11, 15,
149                             16, 20, 17, 21, 18, 22, 19, 23};
150             this->m_layout = layout_type::dynamic;
151         }
152     };
153 
154     template <class C = dynamic_shape<std::size_t>>
155     struct unit_shape_result
156     {
157         using vector_type = std::vector<int>;
158         using size_type = typename C::value_type;
159         using difference_type = typename C::difference_type;
160         using shape_type = C;
161         using strides_type = get_strides_t<C>;
162 
163         using assigner_type = std::vector<std::vector<vector_type>>;
164 
unit_shape_resultxt::unit_shape_result165         inline unit_shape_result()
166         {
167             m_shape = {3, 1, 4};
168             m_strides = {4, 0, 1};
169             m_backstrides = {8, 0, 3};
170             m_data = {-1, 1, 2, 3, 8, 9, 10, 11, 16, 17, 18, 19};
171             m_layout = layout_type::dynamic;
172             m_assigner.resize(m_shape[0]);
173             for (std::size_t i = 0; i < m_shape[0]; ++i)
174             {
175                 m_assigner[i].resize(m_shape[1]);
176             }
177             m_assigner[0][0] = {-1, 1, 2, 3};
178             m_assigner[1][0] = {8, 9, 10, 11};
179             m_assigner[2][0] = {16, 17, 18, 19};
180         }
181 
182         shape_type m_shape;
183         strides_type m_strides;
184         strides_type m_backstrides;
185         vector_type m_data;
186         layout_type m_layout;
187         assigner_type m_assigner;
188 
sizext::unit_shape_result189         inline size_type size() const { return m_data.size(); }
shapext::unit_shape_result190         inline const shape_type& shape() const { return m_shape; }
stridesxt::unit_shape_result191         inline const strides_type& strides() const { return m_strides; }
backstridesxt::unit_shape_result192         inline const strides_type& backstrides() const { return m_backstrides; }
layoutxt::unit_shape_result193         inline layout_type layout() const { return m_layout; }
storagext::unit_shape_result194         inline const vector_type& storage() const { return m_data; }
195     };
196 
197     template <class V, class R>
compare_shape(V & vec,const R & result,bool compare_layout=true)198     void compare_shape(V& vec, const R& result, bool compare_layout = true)
199     {
200         EXPECT_TRUE(std::equal(vec.shape().cbegin(), vec.shape().cend(), result.shape().cbegin()));
201         EXPECT_TRUE(std::equal(vec.strides().cbegin(), vec.strides().cend(), result.strides().cbegin()));
202         EXPECT_TRUE(std::equal(vec.backstrides().cbegin(), vec.backstrides().cend(), result.backstrides().cbegin()));
203         EXPECT_EQ(vec.size(), result.size());
204         if (compare_layout)
205         {
206             EXPECT_EQ(vec.layout(), result.layout());
207         }
208     }
209 
210     template <class V, class C = dynamic_shape<std::size_t>>
test_resize(V & vec)211     void test_resize(V& vec)
212     {
213         {
214             INFO("row_major resize");
215             row_major_result<C> rm;
216             vec.resize(rm.m_shape, layout_type::row_major);
217             compare_shape(vec, rm);
218         }
219 
220         {
221             INFO("different types resize");
222             row_major_result<C> rm;
223             auto v_copy_a = vec;
224             auto v_copy_b = vec;
225             std::array<std::size_t, 3> ar = {3, 2, 4};
226             std::vector<std::size_t> vr = {3, 2, 4};
227             v_copy_a.resize(ar, true);
228             compare_shape(v_copy_a, rm);
229             v_copy_b.resize(vr, true);
230             compare_shape(v_copy_b, rm);
231         }
232 
233         {
234             INFO("column_major resize");
235             column_major_result<C> cm;
236             vec.resize(cm.m_shape, layout_type::column_major);
237             compare_shape(vec, cm);
238         }
239 
240         {
241             INFO("central_major resize");
242             central_major_result<C> cem;
243             vec.resize(cem.m_shape, cem.m_strides);
244             compare_shape(vec, cem);
245         }
246 
247         {
248             INFO("unit_shape resize");
249             unit_shape_result<C> usr;
250             vec.resize(usr.m_shape, layout_type::row_major);
251             compare_shape(vec, usr, false);
252             EXPECT_EQ(vec.layout(), layout_type::row_major);
253         }
254     }
255 
256     template <class V, class C = std::vector<std::size_t>>
test_reshape(V & vec)257     void test_reshape(V& vec)
258     {
259         {
260             INFO("row_major reshape");
261             row_major_result<C> rm;
262             auto shape = rm.m_shape;
263             std::size_t sz = compute_size(shape);
264             std::fill(shape.begin(), shape.end(), 1);
265             shape[0] = sz;
266             vec.resize(shape);
267             vec.reshape(rm.m_shape, layout_type::row_major);
268             compare_shape(vec, rm);
269             dynamic_shape<signed long long> signed_shape;
270             std::copy(rm.m_shape.begin(), rm.m_shape.end(), std::back_inserter(signed_shape));
271             signed_shape[1] = -1;
272             vec.resize(shape);
273             vec.reshape(signed_shape, layout_type::row_major);
274             compare_shape(vec, rm);
275 
276             vec.resize(shape);
277             vec.reshape({ 3, -1, 4 }, layout_type::row_major);
278             compare_shape(vec, rm);
279 
280             auto & vec_ref = vec.reshape({ 3, -1, 4 }, layout_type::row_major);
281             compare_shape(vec_ref, rm);
282 
283             shape = rm.m_shape;
284             shape.front() += 123;
285             XT_EXPECT_THROW(vec_ref.reshape(shape), std::runtime_error);
286         }
287     }
288 
289     template <class V>
test_throwing_reshape(V & vec)290     void test_throwing_reshape(V& vec)
291     {
292         {
293             INFO("throwing reshape");
294             vec = xt::arange(6);
295             XT_EXPECT_THROW(vec.reshape({2}), std::runtime_error);
296         }
297     }
298 
299     template <class V, class C = std::vector<std::size_t>>
test_transpose(V & vec)300     void test_transpose(V& vec)
301     {
302         using shape_type = typename V::shape_type;
303         using strides_type = typename V::strides_type;
304 
305         {
306             INFO("transpose");
307             shape_type shape_new = vec.shape();
308             auto vt = transpose(vec);
309             std::reverse(shape_new.begin(), shape_new.end());
310             EXPECT_EQ(vt.shape(), shape_new);
311         }
312 
313         {
314             INFO("transpose with data");
315             row_major_result<C> rm;
316             vec.resize(rm.shape(), layout_type::row_major);
317 
318             assign_array(vec, rm.m_assigner);
319             EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), rm.m_data.cbegin()));
320 
321             auto vec_copy = vec;
322 
323             shape_type shape_new(rm.shape());
324             auto vt = transpose(vec);
325             std::reverse(shape_new.begin(), shape_new.end());
326             EXPECT_EQ(vt.shape(), shape_new);
327             EXPECT_TRUE(std::equal(vt.storage().cbegin(), vt.storage().cend(), rm.m_data.cbegin()));
328 
329             strides_type new_strides = {rm.m_strides[2],
330                                         rm.m_strides[1],
331                                         rm.m_strides[0]};
332             EXPECT_EQ(vt.strides(), new_strides);
333 
334             strides_type new_backstrides = {rm.m_backstrides[2],
335                                             rm.m_backstrides[1],
336                                             rm.m_backstrides[0]};
337             EXPECT_EQ(vt.backstrides(), new_backstrides);
338 
339             EXPECT_EQ(vec_copy(0, 0, 0), vt(0, 0, 0));
340             EXPECT_EQ(vec_copy(0, 1, 0), vt(0, 1, 0));
341             EXPECT_EQ(vec_copy(1, 1, 0), vt(0, 1, 1));
342             EXPECT_EQ(vec_copy(1, 1, 2), vt(2, 1, 1));
343         }
344 
345         {
346             INFO("transpose with permutation");
347             row_major_result<C> rm;
348             vec.resize(rm.shape(), layout_type::row_major);
349 
350             assign_array(vec, rm.m_assigner);
351             EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), rm.m_data.cbegin()));
352 
353             auto vec_copy = vec;
354 
355             shape_type a = vec.shape();
356             auto vt = transpose(vec, {1, 0, 2});
357             shape_type shape_new = {a[1], a[0], a[2]};
358             EXPECT_TRUE(std::equal(vt.shape().cbegin(), vt.shape().cend(), shape_new.begin()));
359             EXPECT_TRUE(std::equal(vt.storage().cbegin(), vt.storage().cend(), rm.m_data.cbegin()));
360 
361             strides_type new_strides = {rm.m_strides[1],
362                                         rm.m_strides[0],
363                                         rm.m_strides[2]};
364             EXPECT_EQ(vt.strides(), new_strides);
365 
366             strides_type new_backstrides = {rm.m_backstrides[1],
367                                             rm.m_backstrides[0],
368                                             rm.m_backstrides[2]};
369             EXPECT_EQ(vt.backstrides(), new_backstrides);
370 
371             EXPECT_EQ(vec_copy(0, 0, 0), vt(0, 0, 0));
372             EXPECT_EQ(vec_copy(0, 1, 0), vt(1, 0, 0));
373             EXPECT_EQ(vec_copy(1, 1, 0), vt(1, 1, 0));
374             EXPECT_EQ(vec_copy(1, 1, 2), vt(1, 1, 2));
375 
376             // Compilation check only
377             std::vector<std::size_t> perm = {1, 0, 2};
378             transpose(vec, perm);
379         }
380 
381         {
382             INFO("transpose permutation throws");
383             row_major_result<C> rm;
384             vec.reshape(rm.shape(), layout_type::row_major);
385 
386             XT_EXPECT_THROW(transpose(vec, {1, 1, 0}, check_policy::full()), transpose_error);
387             XT_EXPECT_THROW(transpose(vec, {1, 0, 2, 3}, check_policy::full()), transpose_error);
388             XT_EXPECT_THROW(transpose(vec, {1, 2}, check_policy::full()), transpose_error);
389             XT_EXPECT_THROW(transpose(vec, {3, 0, 1}, check_policy::full()), transpose_error);
390         }
391     }
392 
393     template <class V1, class V2>
assign_array(V1 & dst,const V2 & src)394     void assign_array(V1& dst, const V2& src)
395     {
396         for (std::size_t i = 0; i < dst.shape()[0]; ++i)
397         {
398             for (std::size_t j = 0; j < dst.shape()[1]; ++j)
399             {
400                 for (std::size_t k = 0; k < dst.shape()[2]; ++k)
401                 {
402                     dst(i, j, k) = src[i][j][k];
403                 }
404             }
405         }
406     }
407 
408     template <class V1, class V2>
safe_assign_array(V1 & dst,const V2 & src)409     void safe_assign_array(V1& dst, const V2& src)
410     {
411         for (std::size_t i = 0; i < dst.shape()[0]; ++i)
412         {
413             for (std::size_t j = 0; j < dst.shape()[1]; ++j)
414             {
415                 for (std::size_t k = 0; k < dst.shape()[2]; ++k)
416                 {
417                     dst.at(i, j, k) = src[i][j][k];
418                 }
419             }
420         }
421     }
422     template <class V>
test_bound_check(V & vec)423     void test_bound_check(V& vec)
424     {
425 #if XTENSOR_ENABLE_ASSERT
426         XT_EXPECT_ANY_THROW(vec(10, 10, 10));
427 #else
428         (void)vec;
429 #endif
430     }
431 
432     template <class V>
test_access_check(V & vec)433     void test_access_check(V& vec)
434     {
435         XT_EXPECT_ANY_THROW(vec.at(10, 10, 10));
436         XT_EXPECT_ANY_THROW(vec.at(0, 0, 0, 0, 0, 0));
437     }
438 
439     template <class V, class C = dynamic_shape<std::size_t>>
test_access(V & vec)440     void test_access(V& vec)
441     {
442         {
443             INFO("row_major access");
444             row_major_result<C> rm;
445             vec.resize(rm.m_shape, layout_type::row_major);
446             assign_array(vec, rm.m_assigner);
447             EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), rm.m_data.cbegin()));
448             EXPECT_EQ(vec(0, 1, 1), vec(1, 1));
449             EXPECT_EQ(vec(2, 1, 3), vec(2, 2, 2, 1, 3));
450             test_bound_check(vec);
451         }
452 
453         {
454             INFO("column_major access");
455             column_major_result<C> cm;
456             vec.resize(cm.m_shape, layout_type::column_major);
457             assign_array(vec, cm.m_assigner);
458             EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), cm.m_data.cbegin()));
459             EXPECT_EQ(vec(0, 1, 1), vec(1, 1));
460             EXPECT_EQ(vec(2, 1, 3), vec(2, 2, 2, 1, 3));
461             test_bound_check(vec);
462         }
463 
464         {
465             INFO("central_major access");
466             central_major_result<C> cem;
467             vec.resize(cem.m_shape, cem.m_strides);
468             assign_array(vec, cem.m_assigner);
469             EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), cem.m_data.cbegin()));
470             EXPECT_EQ(vec(0, 1, 1), vec(1, 1));
471             EXPECT_EQ(vec(2, 1, 3), vec(2, 2, 2, 1, 3));
472             test_bound_check(vec);
473         }
474 
475         {
476             INFO("unit_shape access");
477             unit_shape_result<C> usr;
478             vec.resize(usr.m_shape, layout_type::row_major);
479             assign_array(vec, usr.m_assigner);
480             EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), usr.m_data.cbegin()));
481             EXPECT_EQ(vec(0, 1, 0), vec(1, 0));
482             EXPECT_EQ(vec(2, 0, 3), vec(2, 2, 2, 0, 3));
483             test_bound_check(vec);
484         }
485     }
486 
487     template <class V, class C = dynamic_shape<std::size_t>>
test_unchecked(V & vec)488     void test_unchecked(V& vec)
489     {
490         {
491             INFO("row_major access");
492             row_major_result<C> rm;
493             vec.resize(rm.m_shape, layout_type::row_major);
494             assign_array(vec, rm.m_assigner);
495             EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), rm.m_data.cbegin()));
496             EXPECT_EQ(vec.unchecked(0, 1, 1), vec(0, 1, 1));
497         }
498 
499         {
500             INFO("column_major access");
501             column_major_result<C> cm;
502             vec.resize(cm.m_shape, layout_type::column_major);
503             assign_array(vec, cm.m_assigner);
504             EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), cm.m_data.cbegin()));
505             EXPECT_EQ(vec.unchecked(0, 1, 1), vec(0, 1, 1));
506         }
507 
508         {
509             INFO("central_major access");
510             central_major_result<C> cem;
511             vec.resize(cem.m_shape, cem.m_strides);
512             assign_array(vec, cem.m_assigner);
513             EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), cem.m_data.cbegin()));
514             EXPECT_EQ(vec.unchecked(0, 1, 1), vec(0, 1, 1));
515         }
516 
517         {
518             INFO("unit_shape access");
519             unit_shape_result<C> usr;
520             vec.resize(usr.m_shape, layout_type::row_major);
521             assign_array(vec, usr.m_assigner);
522             EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), usr.m_data.cbegin()));
523             EXPECT_EQ(vec.unchecked(0, 1, 0), vec(0, 1, 0));
524         }
525     }
526 
527     template <class V, class C = dynamic_shape<std::size_t>>
test_at(V & vec)528     void test_at(V& vec)
529     {
530         {
531             INFO("row_major access");
532             row_major_result<C> rm;
533             vec.resize(rm.m_shape, layout_type::row_major);
534             safe_assign_array(vec, rm.m_assigner);
535             EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), rm.m_data.cbegin()));
536             test_access_check(vec);
537         }
538 
539         {
540             INFO("column_major access");
541             column_major_result<C> cm;
542             vec.resize(cm.m_shape, layout_type::column_major);
543             safe_assign_array(vec, cm.m_assigner);
544             EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), cm.m_data.cbegin()));
545             test_access_check(vec);
546         }
547 
548         {
549             INFO("central_major access");
550             central_major_result<C> cem;
551             vec.resize(cem.m_shape, cem.m_strides);
552             safe_assign_array(vec, cem.m_assigner);
553             EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), cem.m_data.cbegin()));
554             test_access_check(vec);
555         }
556 
557         {
558             INFO("unit_shape access");
559             unit_shape_result<C> usr;
560             vec.resize(usr.m_shape, layout_type::row_major);
561             safe_assign_array(vec, usr.m_assigner);
562             EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), usr.m_data.cbegin()));
563             test_access_check(vec);
564         }
565     }
566 
567     template <class V, class C = dynamic_shape<std::size_t>>
test_element(V & vec)568     void test_element(V& vec)
569     {
570         {
571             INFO("row_major access");
572             row_major_result<C> rm;
573             vec.resize(rm.m_shape, layout_type::row_major);
574             assign_array(vec, rm.m_assigner);
575             EXPECT_EQ(vec.storage(), rm.m_data);
576             std::vector<std::size_t> index1 = {0, 1, 1};
577             std::vector<std::size_t> index2 = {1, 1};
578             std::vector<std::size_t> index3 = {2, 1, 3};
579             std::vector<std::size_t> index4 = {2, 2, 2, 1, 3};
580             EXPECT_EQ(vec.element(index1.begin(), index1.end()), vec.element(index2.begin(), index2.end()));
581             EXPECT_EQ(vec.element(index3.begin(), index3.end()), vec.element(index4.begin(), index4.end()));
582             test_bound_check(vec);
583         }
584 
585         {
586             INFO("column_major access");
587             column_major_result<C> cm;
588             vec.resize(cm.m_shape, layout_type::column_major);
589             assign_array(vec, cm.m_assigner);
590             EXPECT_EQ(vec.storage(), cm.m_data);
591             std::vector<std::size_t> index1 = {0, 1, 1};
592             std::vector<std::size_t> index2 = {1, 1};
593             std::vector<std::size_t> index3 = {2, 1, 3};
594             std::vector<std::size_t> index4 = {2, 2, 2, 1, 3};
595             EXPECT_EQ(vec.element(index1.begin(), index1.end()), vec.element(index2.begin(), index2.end()));
596             EXPECT_EQ(vec.element(index3.begin(), index3.end()), vec.element(index4.begin(), index4.end()));
597             test_bound_check(vec);
598         }
599 
600         {
601             INFO("central_major access");
602             central_major_result<C> cem;
603             vec.resize(cem.m_shape, cem.m_strides);
604             assign_array(vec, cem.m_assigner);
605             EXPECT_EQ(vec.storage(), cem.m_data);
606             std::vector<std::size_t> index1 = {0, 1, 1};
607             std::vector<std::size_t> index2 = {1, 1};
608             std::vector<std::size_t> index3 = {2, 1, 3};
609             std::vector<std::size_t> index4 = {2, 2, 2, 1, 3};
610             EXPECT_EQ(vec.element(index1.begin(), index1.end()), vec.element(index2.begin(), index2.end()));
611             EXPECT_EQ(vec.element(index3.begin(), index3.end()), vec.element(index4.begin(), index4.end()));
612             test_bound_check(vec);
613         }
614 
615         {
616             INFO("unit_shape access");
617             unit_shape_result<C> usr;
618             vec.resize(usr.m_shape, layout_type::row_major);
619             assign_array(vec, usr.m_assigner);
620             EXPECT_EQ(vec.storage(), usr.m_data);
621             std::vector<std::size_t> index1 = {0, 1, 0};
622             std::vector<std::size_t> index2 = {1, 0};
623             std::vector<std::size_t> index3 = {2, 0, 3};
624             std::vector<std::size_t> index4 = {2, 2, 2, 0, 3};
625             EXPECT_EQ(vec.element(index1.begin(), index1.end()), vec.element(index2.begin(), index2.end()));
626             EXPECT_EQ(vec.element(index3.begin(), index3.end()), vec.element(index4.begin(), index4.end()));
627             test_bound_check(vec);
628         }
629     }
630 
631     template <class V1, class V2>
indexed_assign_array(V1 & dst,const V2 & src)632     void indexed_assign_array(V1& dst, const V2& src)
633     {
634         xindex index(dst.dimension());
635         for (std::size_t i = 0; i < dst.shape()[0]; ++i)
636         {
637             index[0] = i;
638             for (std::size_t j = 0; j < dst.shape()[1]; ++j)
639             {
640                 index[1] = j;
641                 for (std::size_t k = 0; k < dst.shape()[2]; ++k)
642                 {
643                     index[2] = k;
644                     dst[index] = src[i][j][k];
645                 }
646             }
647         }
648     }
649 
650     template <class V, class C = dynamic_shape<std::size_t>>
test_indexed_access(V & vec)651     void test_indexed_access(V& vec)
652     {
653         xindex index1 = {1, 1};
654         xindex index2 = {2, 2, 2, 1, 3};
655         {
656             INFO("row_major access");
657             row_major_result<C> rm;
658             vec.resize(rm.m_shape, layout_type::row_major);
659             indexed_assign_array(vec, rm.m_assigner);
660             EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), rm.m_data.cbegin()));
661             EXPECT_EQ(vec(0, 1, 1), vec[index1]);
662             EXPECT_EQ(vec(0, 1, 1), (vec[{1, 1}]));
663             EXPECT_EQ(vec(2, 1, 3), vec[index2]);
664             EXPECT_EQ(vec(2, 1, 3), (vec[{2, 2, 2, 1, 3}]));
665         }
666 
667         {
668             INFO("column_major access");
669             column_major_result<C> cm;
670             vec.resize(cm.m_shape, layout_type::column_major);
671             indexed_assign_array(vec, cm.m_assigner);
672             EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), cm.m_data.cbegin()));
673             EXPECT_EQ(vec(0, 1, 1), vec[index1]);
674             EXPECT_EQ(vec(0, 1, 1), (vec[{1, 1}]));
675             EXPECT_EQ(vec(2, 1, 3), vec[index2]);
676             EXPECT_EQ(vec(2, 1, 3), (vec[{2, 2, 2, 1, 3}]));
677         }
678 
679         {
680             INFO("central_major access");
681             central_major_result<C> cem;
682             vec.resize(cem.m_shape, cem.m_strides);
683             indexed_assign_array(vec, cem.m_assigner);
684             EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), cem.m_data.cbegin()));
685             EXPECT_EQ(vec(0, 1, 1), vec[index1]);
686             EXPECT_EQ(vec(0, 1, 1), (vec[{1, 1}]));
687             EXPECT_EQ(vec(2, 1, 3), vec[index2]);
688             EXPECT_EQ(vec(2, 1, 3), (vec[{2, 2, 2, 1, 3}]));
689         }
690 
691         {
692             INFO("unit_shape access");
693             unit_shape_result<C> usr;
694             vec.resize(usr.m_shape, layout_type::row_major);
695             indexed_assign_array(vec, usr.m_assigner);
696             EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), usr.m_data.cbegin()));
697             xindex id1 = {1, 0};
698             xindex id2 = {2, 2, 2, 0, 3};
699             EXPECT_EQ(vec(0, 1, 0), vec[id1]);
700             EXPECT_EQ(vec(0, 1, 0), (vec[{1, 0}]));
701             EXPECT_EQ(vec(2, 0, 3), vec[id2]);
702             EXPECT_EQ(vec(2, 0, 3), (vec[{2, 2, 2, 0, 3}]));
703         }
704     }
705 
706     template <class V>
test_broadcast(V & vec)707     void test_broadcast(V& vec)
708     {
709         using shape_type = typename V::shape_type;
710 
711         shape_type s = {3, 1, 4, 2};
712         vec.resize(s);
713 
714         {
715             INFO("same shape");
716             shape_type s1 = s;
717             bool res = vec.broadcast_shape(s1);
718             EXPECT_EQ(s1, s);
719             EXPECT_TRUE(res);
720         }
721 
722         {
723             INFO("different shape");
724             shape_type s2 = {3, 5, 1, 2};
725             shape_type s2r = {3, 5, 4, 2};
726             bool res = vec.broadcast_shape(s2);
727             EXPECT_EQ(s2, s2r);
728             EXPECT_FALSE(res);
729         }
730 
731         {
732             INFO("incompatible shapes");
733             shape_type s4 = {2, 1, 3, 2};
734             XT_EXPECT_THROW(vec.broadcast_shape(s4), broadcast_error);
735         }
736     }
737 
738     template <class V>
test_broadcast2(V & vec)739     void test_broadcast2(V& vec)
740     {
741         using shape_type = typename V::shape_type;
742 
743         shape_type s = {3, 1, 4, 2};
744         vec.resize(s);
745 
746         {
747             INFO("different dimensions");
748             shape_type s3 = {5, 3, 1, 4, 2};
749             shape_type s3r = s3;
750             bool res = vec.broadcast_shape(s3);
751             EXPECT_EQ(s3, s3r);
752             EXPECT_FALSE(res);
753         }
754     }
755 
756     template <class VRM, class VCM, class C = dynamic_shape<std::size_t>>
test_iterator(VRM & vecrm,VCM & veccm)757     void test_iterator(VRM& vecrm, VCM& veccm)
758     {
759         {
760             INFO("row_major storage iterator");
761             row_major_result<C> rm;
762             vecrm.resize(rm.m_shape, layout_type::row_major);
763             std::copy(rm.storage().cbegin(), rm.storage().cend(), vecrm.template begin<layout_type::row_major>());
764             EXPECT_TRUE(std::equal(rm.storage().cbegin(), rm.storage().cend(), vecrm.storage().cbegin()));
765             EXPECT_EQ(vecrm.template end<layout_type::row_major>(), vecrm.storage().end());
766         }
767 
768         {
769             INFO("column_major storage iterator");
770             column_major_result<C> cm;
771             veccm.resize(cm.m_shape, layout_type::column_major);
772             std::copy(cm.storage().cbegin(), cm.storage().cend(), veccm.template begin<layout_type::column_major>());
773             EXPECT_TRUE(std::equal(cm.storage().cbegin(), cm.storage().cend(), veccm.storage().cbegin()));
774             EXPECT_EQ(veccm.template end<layout_type::column_major>(), veccm.storage().end());
775         }
776     }
777 
778     template <class V>
test_fill(V & vec)779     void test_fill(V& vec)
780     {
781         using value_type = typename V::value_type;
782         vec.resize({ 3, 4 });
783         value_type v(4);
784         vec.fill(v);
785         for (auto it = vec.cbegin(); it != vec.cend(); ++it)
786         {
787             EXPECT_EQ(*it, v);
788         }
789     }
790 
791     template <class V, class C = dynamic_shape<std::size_t>>
test_xiterator(V & vec)792     void test_xiterator(V& vec)
793     {
794         row_major_result<C> rm;
795         vec.resize(rm.m_shape, layout_type::row_major);
796         indexed_assign_array(vec, rm.m_assigner);
797         size_t nb_iter = vec.size() / 2;
798         using shape_type = std::vector<size_t>;
799 
800         {
801             INFO("broadcast_iterator");
802             auto iter = vec.template begin<layout_type::row_major>();
803             auto iter_end = vec.template end<layout_type::row_major>();
804             for (size_t i = 0; i < nb_iter; ++i)
805             {
806                 ++iter;
807             }
808             EXPECT_EQ(vec.storage()[nb_iter], *iter);
809             for (size_t i = 0; i < nb_iter; ++i)
810             {
811                 ++iter;
812             }
813             EXPECT_EQ(iter, iter_end);
814         }
815 
816         {
817             INFO("shaped_xiterator");
818             shape_type shape(rm.m_shape.size() + 1);
819             std::copy(rm.m_shape.begin(), rm.m_shape.end(), shape.begin() + 1);
820             shape[0] = 2;
821             auto iter = vec.template begin<layout_type::row_major>(shape);
822             auto iter_end = vec.template end<layout_type::row_major>(shape);
823             for (size_t i = 0; i < 2 * nb_iter; ++i)
824             {
825                 ++iter;
826             }
827             EXPECT_EQ(vec.storage()[0], *iter);
828             for (size_t i = 0; i < 2 * nb_iter; ++i)
829             {
830                 ++iter;
831             }
832             EXPECT_EQ(iter, iter_end);
833         }
834 
835         {
836             INFO("column broadcast_iterator");
837             auto iter = vec.template begin<layout_type::column_major>();
838             auto iter_end = vec.template end<layout_type::column_major>();
839             for (size_t i = 0; i < nb_iter; ++i)
840             {
841                 ++iter;
842             }
843             EXPECT_EQ(vec(0, 0, 2), *iter);
844             for (size_t i = 0; i < nb_iter; ++i)
845             {
846                 ++iter;
847             }
848             EXPECT_EQ(iter, iter_end);
849         }
850 
851         {
852             INFO("column shaped_xiterator");
853             shape_type shape(rm.m_shape.size() + 1);
854             std::copy(rm.m_shape.begin(), rm.m_shape.end(), shape.begin() + 1);
855             shape[0] = 2;
856             auto iter = vec.template begin<layout_type::column_major>(shape);
857             auto iter_end = vec.template end<layout_type::column_major>(shape);
858             for (size_t i = 0; i < 2 * nb_iter; ++i)
859             {
860                 ++iter;
861             }
862             EXPECT_EQ(vec(0, 0, 2), *iter);
863             for (size_t i = 0; i < 2 * nb_iter; ++i)
864             {
865                 ++iter;
866             }
867             EXPECT_EQ(iter, iter_end);
868         }
869     }
870 
871     template <class V, class C = dynamic_shape<std::size_t>>
test_reverse_xiterator(V & vec)872     void test_reverse_xiterator(V& vec)
873     {
874         row_major_result<C> rm;
875         vec.resize(rm.m_shape, layout_type::row_major);
876         indexed_assign_array(vec, rm.m_assigner);
877         size_t nb_iter = vec.size() / 2;
878 
879         {
880             INFO("broadcast_iterator");
881             auto iter = vec.template rbegin<layout_type::row_major>();
882             auto iter_end = vec.template rend<layout_type::row_major>();
883             for (size_t i = 0; i < nb_iter; ++i)
884             {
885                 ++iter;
886             }
887             EXPECT_EQ(vec.storage()[nb_iter - 1], *iter);
888             for (size_t i = 0; i < nb_iter; ++i)
889             {
890                 ++iter;
891             }
892             EXPECT_EQ(iter, iter_end);
893         }
894 
895         {
896             INFO("shaped_xiterator");
897             using shape_type = std::vector<size_t>;
898             shape_type shape(rm.m_shape.size() + 1);
899             std::copy(rm.m_shape.begin(), rm.m_shape.end(), shape.begin() + 1);
900             shape[0] = 2;
901             auto iter = vec.template rbegin<layout_type::row_major>(shape);
902             auto iter_end = vec.template rend<layout_type::row_major>(shape);
903             for (size_t i = 0; i < 2 * nb_iter; ++i)
904             {
905                 ++iter;
906             }
907             EXPECT_EQ(vec.storage()[2 * nb_iter - 1], *iter);
908             for (size_t i = 0; i < 2 * nb_iter; ++i)
909             {
910                 ++iter;
911             }
912             EXPECT_EQ(iter, iter_end);
913         }
914     }
915 
916     // C: container type (xarray<int>, xtensor<int>)
917     // SIT: storage iterator (int*, std::vector<int>::iterator)
918     // SCIT: storage const iterator (const int*, std::vector<int>::const_iterator)
919     template <class C, class SIT, class SCIT>
test_iterator_types()920     void test_iterator_types()
921     {
922         using stepper = xstepper<C>;
923         using const_stepper = xstepper<const C>;
924         using shape_type = typename C::shape_type;
925 
926         using rm_layout_iterator = typename C::template layout_iterator<layout_type::row_major>;
927         using rm_const_layout_iterator = typename C::template const_layout_iterator<layout_type::row_major>;
928         using rm_reverse_layout_iterator = typename C::template reverse_layout_iterator<layout_type::row_major>;
929         using rm_const_reverse_layout_iterator = typename C::template const_reverse_layout_iterator<layout_type::row_major>;
930 
931         using exp_rm_layout_iterator = xiterator<stepper, shape_type*, layout_type::row_major>;
932         using exp_rm_const_layout_iterator = xiterator<const_stepper, shape_type*, layout_type::row_major>;
933         using exp_rm_reverse_layout_iterator = std::reverse_iterator<rm_layout_iterator>;
934         using exp_rm_const_reverse_layout_iterator = std::reverse_iterator<rm_const_layout_iterator>;
935 
936         EXPECT_TRUE((std::is_same<rm_layout_iterator, exp_rm_layout_iterator>::value));
937         EXPECT_TRUE((std::is_same<rm_const_layout_iterator, exp_rm_const_layout_iterator>::value));
938         EXPECT_TRUE((std::is_same<rm_reverse_layout_iterator, exp_rm_reverse_layout_iterator>::value));
939         EXPECT_TRUE((std::is_same<rm_const_reverse_layout_iterator, exp_rm_const_reverse_layout_iterator>::value));
940 
941         using cm_layout_iterator = typename C::template layout_iterator<layout_type::column_major>;
942         using cm_const_layout_iterator = typename C::template const_layout_iterator<layout_type::column_major>;
943         using cm_reverse_layout_iterator = typename C::template reverse_layout_iterator<layout_type::column_major>;
944         using cm_const_reverse_layout_iterator = typename C::template const_reverse_layout_iterator<layout_type::column_major>;
945 
946         using exp_cm_layout_iterator = xiterator<stepper, shape_type*, layout_type::column_major>;
947         using exp_cm_const_layout_iterator = xiterator<const_stepper, shape_type*, layout_type::column_major>;
948         using exp_cm_reverse_layout_iterator = std::reverse_iterator<cm_layout_iterator>;
949         using exp_cm_const_reverse_layout_iterator = std::reverse_iterator<cm_const_layout_iterator>;
950 
951         EXPECT_TRUE((std::is_same<cm_layout_iterator, exp_cm_layout_iterator>::value));
952         EXPECT_TRUE((std::is_same<cm_const_layout_iterator, exp_cm_const_layout_iterator>::value));
953         EXPECT_TRUE((std::is_same<cm_reverse_layout_iterator, exp_cm_reverse_layout_iterator>::value));
954         EXPECT_TRUE((std::is_same<cm_const_reverse_layout_iterator, exp_cm_const_reverse_layout_iterator>::value));
955 
956         using storage_iterator = typename C::storage_iterator;
957         using const_storage_iterator = typename C::const_storage_iterator;
958         using reverse_storage_iterator = typename C::reverse_storage_iterator;
959         using const_reverse_storage_iterator = typename C::const_reverse_storage_iterator;
960 
961         using exp_storage_iterator = SIT;
962         using exp_const_storage_iterator = SCIT;
963         using exp_reverse_storage_iterator = std::reverse_iterator<SIT>;
964         using exp_const_reverse_storage_iterator = std::reverse_iterator<SCIT>;
965 
966         EXPECT_TRUE((std::is_same<storage_iterator, exp_storage_iterator>::value));
967         EXPECT_TRUE((std::is_same<const_storage_iterator, exp_const_storage_iterator>::value));
968         EXPECT_TRUE((std::is_same<reverse_storage_iterator, exp_reverse_storage_iterator>::value));
969         EXPECT_TRUE((std::is_same<const_reverse_storage_iterator, exp_const_reverse_storage_iterator>::value));
970     }
971 }
972 
973 #endif
974