1 /* Copyright 2016-2018 Joaquin M Lopez Munoz.
2  * Distributed under the Boost Software License, Version 1.0.
3  * (See accompanying file LICENSE_1_0.txt or copy at
4  * http://www.boost.org/LICENSE_1_0.txt)
5  *
6  * See http://www.boost.org/libs/poly_collection for library home page.
7  */
8 
9 #include "test_iterators.hpp"
10 
11 #include <boost/core/lightweight_test.hpp>
12 #include <iterator>
13 #include <type_traits>
14 #include "any_types.hpp"
15 #include "base_types.hpp"
16 #include "function_types.hpp"
17 #include "test_utilities.hpp"
18 
19 using namespace test_utilities;
20 
21 template<typename Iterator>
22 using is_input=std::is_base_of<
23   std::input_iterator_tag,
24   typename std::iterator_traits<Iterator>::iterator_category
25 >;
26 template<typename Iterator>
27 using is_forward=std::is_base_of<
28   std::forward_iterator_tag,
29   typename std::iterator_traits<Iterator>::iterator_category
30 >;
31 template<typename Iterator>
32 using is_random_access=std::is_base_of<
33   std::random_access_iterator_tag,
34   typename std::iterator_traits<Iterator>::iterator_category
35 >;
36 
37 template<typename Type,typename PolyCollection>
test_iterators(PolyCollection & p)38 void test_iterators(PolyCollection& p)
39 {
40   using local_base_iterator=typename PolyCollection::local_base_iterator;
41   using const_local_base_iterator=
42     typename PolyCollection::const_local_base_iterator;
43   using local_iterator=typename PolyCollection::template local_iterator<Type>;
44   using const_local_iterator=
45     typename PolyCollection::template const_local_iterator<Type>;
46   using base_segment_info=typename PolyCollection::base_segment_info;
47   using const_base_segment_info=
48     typename PolyCollection::const_base_segment_info;
49   using const_segment_info=
50     typename PolyCollection::template const_segment_info<Type>;
51   using segment_info=typename PolyCollection::template segment_info<Type>;
52 
53   static_assert(is_random_access<local_iterator>::value,
54                 "local_iterator must be random access");
55   static_assert(is_random_access<const_local_iterator>::value,
56                 "const_local_iterator must be random access");
57   static_assert(std::is_base_of<const_segment_info,segment_info>::value,
58                 "segment_info must derive from const_segment_info");
59 
60   {
61     local_iterator       lit,lit2;
62     const_local_iterator clit,clit2(lit); /* sorry about the names */
63 
64     lit=lit2;
65     clit=clit2;
66     clit=lit;
67   }
68 
69   const PolyCollection&     cp=p;
70   std::size_t               n=0;
71   local_base_iterator       lbfirst=p.begin(typeid(Type)),
72                             lblast=p.end(typeid(Type));
73   const_local_base_iterator clbfirst=cp.begin(typeid(Type)),
74                             clblast=cp.end(typeid(Type));
75   local_iterator            lfirst=p.template begin<Type>(),
76                             llast=p.template end<Type>();
77   const_local_iterator      clfirst=cp.template begin<Type>(),
78                             cllast=cp.template end<Type>();
79   base_segment_info         bi=p.segment(typeid(Type));
80   const_base_segment_info   cbi=cp.segment(typeid(Type));
81   segment_info              i=p.template segment<Type>();
82   const_segment_info        ci=cp.template segment<Type>();
83 
84   BOOST_TEST(clbfirst==cp.cbegin(typeid(Type)));
85   BOOST_TEST(clblast==cp.cend(typeid(Type)));
86   BOOST_TEST(clfirst==cp.template cbegin<Type>());
87   BOOST_TEST(cllast==cp.template cend<Type>());
88 
89   BOOST_TEST(lbfirst==bi.begin());
90   BOOST_TEST(lblast==bi.end());
91   BOOST_TEST(clbfirst==bi.cbegin());
92   BOOST_TEST(clbfirst==cbi.begin());
93   BOOST_TEST(clblast==bi.cend());
94   BOOST_TEST(clblast==cbi.end());
95 
96   BOOST_TEST(lfirst==i.begin());
97   BOOST_TEST(llast==i.end());
98   BOOST_TEST(clfirst==i.cbegin());
99   BOOST_TEST(clfirst==ci.begin());
100   BOOST_TEST(cllast==i.cend());
101   BOOST_TEST(cllast==ci.end());
102 
103   for(;lbfirst!=lblast;++lbfirst,++clbfirst,++lfirst,++clfirst){
104     BOOST_TEST(lfirst==static_cast<local_iterator>(lbfirst));
105     BOOST_TEST(static_cast<local_base_iterator>(lfirst)==lbfirst);
106     BOOST_TEST(clfirst==static_cast<const_local_iterator>(clbfirst));
107     BOOST_TEST(static_cast<const_local_base_iterator>(clfirst)==clbfirst);
108     BOOST_TEST(clfirst==lfirst);
109     BOOST_TEST(&*lfirst==&*static_cast<local_iterator>(lbfirst));
110     BOOST_TEST(&*clfirst==&*static_cast<const_local_iterator>(clbfirst));
111     BOOST_TEST(&*clfirst==&*lfirst);
112 
113     Type&       r=p.template begin<Type>()[n];
114     const Type& cr=cp.template begin<Type>()[n];
115 
116     BOOST_TEST(&*lfirst==&r);
117     BOOST_TEST(&*clfirst==&cr);
118 
119     ++n;
120   }
121   BOOST_TEST(clbfirst==clblast);
122   BOOST_TEST(lfirst==llast);
123   BOOST_TEST(clfirst==cllast);
124   BOOST_TEST(lfirst==static_cast<local_iterator>(llast));
125   BOOST_TEST(clfirst==static_cast<const_local_iterator>(cllast));
126   BOOST_TEST(clfirst==llast);
127   BOOST_TEST((std::ptrdiff_t)n==p.end(typeid(Type))-p.begin(typeid(Type)));
128   BOOST_TEST(
129     (std::ptrdiff_t)n==p.template end<Type>()-p.template begin<Type>());
130 
131   for(auto s:p.segment_traversal()){
132     if(s.type_info()==typeid(Type)){
133       const auto& cs=s;
134 
135       BOOST_TEST(
136         s.template begin<Type>()==
137         static_cast<local_iterator>(s.begin()));
138       BOOST_TEST(
139         s.template end<Type>()==
140         static_cast<local_iterator>(s.end()));
141       BOOST_TEST(
142         cs.template begin<Type>()==
143         static_cast<const_local_iterator>(cs.begin()));
144       BOOST_TEST(
145         cs.template end<Type>()==
146         static_cast<const_local_iterator>(cs.end()));
147       BOOST_TEST(
148         cs.template cbegin<Type>()==
149         static_cast<const_local_iterator>(cs.cbegin()));
150       BOOST_TEST(
151         cs.template cend<Type>()==
152         static_cast<const_local_iterator>(cs.cend()));
153     }
154   }
155 }
156 
157 template<typename PolyCollection,typename ValueFactory,typename... Types>
test_iterators()158 void test_iterators()
159 {
160   using value_type=typename PolyCollection::value_type;
161   using iterator=typename PolyCollection::iterator;
162   using const_iterator=typename PolyCollection::const_iterator;
163   using local_base_iterator=typename PolyCollection::local_base_iterator;
164   using const_local_base_iterator=
165     typename PolyCollection::const_local_base_iterator;
166   using const_base_segment_info=
167     typename PolyCollection::const_base_segment_info;
168   using base_segment_info=typename PolyCollection::base_segment_info;
169   using base_segment_info_iterator=
170     typename PolyCollection::base_segment_info_iterator;
171   using const_base_segment_info_iterator=
172     typename PolyCollection::const_base_segment_info_iterator;
173   using const_segment_traversal_info=
174     typename PolyCollection::const_segment_traversal_info;
175   using segment_traversal_info=
176     typename PolyCollection::segment_traversal_info;
177 
178   static_assert(is_forward<iterator>::value,
179                 "iterator must be forward");
180   static_assert(is_forward<const_iterator>::value,
181                 "const_iterator must be forward");
182   static_assert(is_random_access<local_base_iterator>::value,
183                 "local_base_iterator must be random access");
184   static_assert(is_random_access<const_local_base_iterator>::value,
185                 "const_local_base_iterator must be random access");
186   static_assert(std::is_base_of<
187                   const_base_segment_info,base_segment_info>::value,
188                 "base_segment_info must derive from const_base_segment_info");
189   static_assert(is_input<base_segment_info_iterator>::value,
190                 "base_segment_info_iterator must be input");
191   static_assert(is_input<const_base_segment_info_iterator>::value,
192                 "const_base_segment_info_iterator must be input");
193   static_assert(std::is_base_of<
194                   const_segment_traversal_info,segment_traversal_info>::value,
195                 "const_segment_traversal_info must derive "\
196                 "from segment_traversal_info");
197 
198   {
199     iterator                         it,it2;
200     const_iterator                   cit,cit2(it);
201     local_base_iterator              lbit,lbit2;
202     const_local_base_iterator        clbit,clbit2(lbit);
203     base_segment_info_iterator       sit,sit2;
204     const_base_segment_info_iterator csit,csit2(csit);
205 
206     it=it2;
207     cit=cit2;
208     cit=it;
209     lbit=lbit2;
210     clbit=clbit2;
211     clbit=lbit;
212     sit=sit2;
213     csit=csit2;
214     csit=sit;
215   }
216 
217   PolyCollection        p;
218   const PolyCollection& cp=p;
219   ValueFactory          v;
220 
221   fill<constraints<>,Types...>(p,v,2);
222 
223   {
224     std::size_t    n=0;
225     iterator       first=p.begin(),last=p.end();
226     const_iterator cfirst=cp.begin(),clast=cp.end();
227 
228     BOOST_TEST(cfirst==cp.cbegin());
229     BOOST_TEST(clast==cp.cend());
230 
231     for(;first!=last;++first,++cfirst){
232       BOOST_TEST(first==cfirst);
233       BOOST_TEST(&*first==&*cfirst);
234 
235       ++n;
236     }
237     BOOST_TEST(cfirst==clast);
238     BOOST_TEST(last==clast);
239     BOOST_TEST(n==p.size());
240   }
241 
242   {
243     std::size_t                      n=0;
244     base_segment_info_iterator       first=p.segment_traversal().begin(),
245                                      last=p.segment_traversal().end();
246     const_base_segment_info_iterator cfirst=cp.segment_traversal().begin(),
247                                      clast=cp.segment_traversal().end();
248 
249     BOOST_TEST(cfirst==cp.segment_traversal().cbegin());
250     BOOST_TEST(clast==cp.segment_traversal().cend());
251 
252     for(;first!=last;++first,++cfirst){
253       BOOST_TEST(first==cfirst);
254 
255       std::size_t               m=0;
256       local_base_iterator       lbfirst=first->begin(),lblast=first->end();
257       const_local_base_iterator clbfirst=cfirst->begin(),clblast=cfirst->end();
258 
259       BOOST_TEST(clbfirst==cfirst->cbegin());
260       BOOST_TEST(clblast==cfirst->cend());
261       BOOST_TEST(lbfirst==p.begin(first->type_info()));
262       BOOST_TEST(lblast==p.end(first->type_info()));
263       BOOST_TEST(clbfirst==cp.begin(first->type_info()));
264       BOOST_TEST(clblast==cp.end(first->type_info()));
265       BOOST_TEST(clbfirst==cp.cbegin(first->type_info()));
266       BOOST_TEST(clblast==cp.cend(first->type_info()));
267 
268       for(;lbfirst!=lblast;++lbfirst,++clbfirst){
269         BOOST_TEST(lbfirst==clbfirst);
270         BOOST_TEST(&*lbfirst==&*clbfirst);
271 
272         value_type&       r=first->begin()[m];
273         const value_type& cr=cfirst->begin()[m];
274 
275         BOOST_TEST(&*lbfirst==&r);
276         BOOST_TEST(&*clbfirst==&cr);
277 
278         ++m;
279       }
280       BOOST_TEST(clbfirst==clblast);
281       BOOST_TEST(lblast==clblast);
282       BOOST_TEST((std::ptrdiff_t)m==first->end()-first->begin());
283       BOOST_TEST((std::ptrdiff_t)m==cfirst->end()-cfirst->begin());
284       BOOST_TEST((std::ptrdiff_t)m==cfirst->cend()-cfirst->cbegin());
285 
286       n+=m;
287     }
288     BOOST_TEST(cfirst==clast);
289     BOOST_TEST(last==clast);
290     BOOST_TEST(n==p.size());
291   }
292 
293   do_((test_iterators<Types>(p),0)...);
294 }
295 
test_iterators()296 void test_iterators()
297 {
298   test_iterators<
299     any_types::collection,auto_increment,
300     any_types::t1,any_types::t2,any_types::t3,
301     any_types::t4,any_types::t5>();
302   test_iterators<
303     base_types::collection,auto_increment,
304     base_types::t1,base_types::t2,base_types::t3,
305     base_types::t4,base_types::t5>();
306   test_iterators<
307     function_types::collection,auto_increment,
308     function_types::t1,function_types::t2,function_types::t3,
309     function_types::t4,function_types::t5>();
310 }
311