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 #ifndef BOOST_POLY_COLLECTION_TEST_TEST_ALGORITHM_IMPL_HPP
10 #define BOOST_POLY_COLLECTION_TEST_TEST_ALGORITHM_IMPL_HPP
11 
12 #if defined(_MSC_VER)
13 #pragma once
14 #endif
15 
16 #include <algorithm>
17 #include <boost/config.hpp>
18 #include <boost/core/lightweight_test.hpp>
19 #include <boost/detail/workaround.hpp>
20 #include <boost/function_output_iterator.hpp>
21 #include <boost/poly_collection/algorithm.hpp>
22 #include <functional>
23 #include <iterator>
24 #include <random>
25 #include <type_traits>
26 #include <utility>
27 #include <vector>
28 #include "test_utilities.hpp"
29 
30 using namespace test_utilities;
31 
32 #if BOOST_WORKAROUND(BOOST_MSVC,>=1910)
33 /* https://lists.boost.org/Archives/boost/2017/06/235687.php */
34 
35 #define DEFINE_ALGORITHM(name,f)                    \
36 template<typename... Ts>                            \
37 struct name                                         \
38 {                                                   \
39   template<typename... Args>                        \
40   auto operator()(Args&&... args)const              \
41   {                                                 \
42     return f<Ts...>(std::forward<Args>(args)...);   \
43   }                                                 \
44 };
45 #elif BOOST_WORKAROUND(BOOST_GCC_VERSION,<50200)
46 /* problem here is with return type containing <Ts...> */
47 
48 #define DEFINE_ALGORITHM(name,f)                    \
49 template<typename... Ts>                            \
50 struct name                                         \
51 {                                                   \
52   template<typename... Args>                        \
53   auto operator()(Args&&... args)const->            \
54     decltype(f(std::forward<Args>(args)...))        \
55   {                                                 \
56     return f<Ts...>(std::forward<Args>(args)...);   \
57   }                                                 \
58 };
59 #else
60 #define DEFINE_ALGORITHM(name,f)                    \
61 template<typename... Ts>                            \
62 struct name                                         \
63 {                                                   \
64   template<typename... Args>                        \
65   auto operator()(Args&&... args)const->            \
66     decltype(f<Ts...>(std::forward<Args>(args)...)) \
67   {                                                 \
68     return f<Ts...>(std::forward<Args>(args)...);   \
69   }                                                 \
70 };
71 #endif
72 
73 DEFINE_ALGORITHM(std_all_of,std::all_of)
74 DEFINE_ALGORITHM(poly_all_of,boost::poly_collection::all_of)
75 DEFINE_ALGORITHM(std_any_of,std::any_of)
76 DEFINE_ALGORITHM(poly_any_of,boost::poly_collection::any_of)
77 DEFINE_ALGORITHM(std_none_of,std::none_of)
78 DEFINE_ALGORITHM(poly_none_of,boost::poly_collection::none_of)
79 DEFINE_ALGORITHM(std_for_each,std::for_each)
80 DEFINE_ALGORITHM(poly_for_each,boost::poly_collection::for_each)
81 DEFINE_ALGORITHM(poly_for_each_n,boost::poly_collection::for_each_n)
82 DEFINE_ALGORITHM(std_find,std::find)
83 DEFINE_ALGORITHM(poly_find,boost::poly_collection::find)
84 DEFINE_ALGORITHM(std_find_if,std::find_if)
85 DEFINE_ALGORITHM(poly_find_if,boost::poly_collection::find_if)
86 DEFINE_ALGORITHM(std_find_if_not,std::find_if_not)
87 DEFINE_ALGORITHM(poly_find_if_not,boost::poly_collection::find_if_not)
88 DEFINE_ALGORITHM(std_find_end,std::find_end)
89 DEFINE_ALGORITHM(poly_find_end,boost::poly_collection::find_end)
90 DEFINE_ALGORITHM(std_find_first_of,std::find_first_of)
91 DEFINE_ALGORITHM(poly_find_first_of,boost::poly_collection::find_first_of)
92 DEFINE_ALGORITHM(std_adjacent_find,std::adjacent_find)
93 DEFINE_ALGORITHM(poly_adjacent_find,boost::poly_collection::adjacent_find)
94 DEFINE_ALGORITHM(std_count,std::count)
95 DEFINE_ALGORITHM(poly_count,boost::poly_collection::count)
96 DEFINE_ALGORITHM(std_count_if,std::count_if)
97 DEFINE_ALGORITHM(poly_count_if,boost::poly_collection::count_if)
98 DEFINE_ALGORITHM(std_cpp11_mismatch,std::mismatch) /* note std_cpp11 prefix */
99 DEFINE_ALGORITHM(poly_mismatch,boost::poly_collection::mismatch)
100 DEFINE_ALGORITHM(std_cpp11_equal,std::equal)       /* note std_cpp11 prefix */
101 DEFINE_ALGORITHM(poly_equal,boost::poly_collection::equal)
102 DEFINE_ALGORITHM(std_cpp11_is_permutation,std::is_permutation) /* std_cpp11 */
103 DEFINE_ALGORITHM(poly_is_permutation,boost::poly_collection::is_permutation)
104 DEFINE_ALGORITHM(std_search,std::search)
105 DEFINE_ALGORITHM(poly_search,boost::poly_collection::search)
106 DEFINE_ALGORITHM(std_search_n,std::search_n)
107 DEFINE_ALGORITHM(poly_search_n,boost::poly_collection::search_n)
108 DEFINE_ALGORITHM(std_copy,std::copy)
109 DEFINE_ALGORITHM(poly_copy,boost::poly_collection::copy)
110 DEFINE_ALGORITHM(std_copy_n,std::copy_n)
111 DEFINE_ALGORITHM(poly_copy_n,boost::poly_collection::copy_n)
112 DEFINE_ALGORITHM(std_copy_if,std::copy_if)
113 DEFINE_ALGORITHM(poly_copy_if,boost::poly_collection::copy_if)
114 DEFINE_ALGORITHM(std_move,std::move)
115 DEFINE_ALGORITHM(poly_move,boost::poly_collection::move)
116 DEFINE_ALGORITHM(std_transform,std::transform)
117 DEFINE_ALGORITHM(poly_transform,boost::poly_collection::transform)
118 DEFINE_ALGORITHM(std_replace_copy,std::replace_copy)
119 DEFINE_ALGORITHM(poly_replace_copy,boost::poly_collection::replace_copy)
120 DEFINE_ALGORITHM(std_replace_copy_if,std::replace_copy_if)
121 DEFINE_ALGORITHM(poly_replace_copy_if,boost::poly_collection::replace_copy_if)
122 DEFINE_ALGORITHM(std_remove_copy,std::remove_copy)
123 DEFINE_ALGORITHM(poly_remove_copy,boost::poly_collection::remove_copy)
124 DEFINE_ALGORITHM(std_remove_copy_if,std::remove_copy_if)
125 DEFINE_ALGORITHM(poly_remove_copy_if,boost::poly_collection::remove_copy_if)
126 DEFINE_ALGORITHM(std_unique_copy,std::unique_copy)
127 DEFINE_ALGORITHM(poly_unique_copy,boost::poly_collection::unique_copy)
128 DEFINE_ALGORITHM(poly_sample,boost::poly_collection::sample)
129 DEFINE_ALGORITHM(std_rotate_copy,std::rotate_copy)
130 DEFINE_ALGORITHM(poly_rotate_copy,boost::poly_collection::rotate_copy)
131 DEFINE_ALGORITHM(std_is_partitioned,std::is_partitioned)
132 DEFINE_ALGORITHM(poly_is_partitioned,boost::poly_collection::is_partitioned)
133 DEFINE_ALGORITHM(std_partition_copy,std::partition_copy)
134 DEFINE_ALGORITHM(poly_partition_copy,boost::poly_collection::partition_copy)
135 DEFINE_ALGORITHM(std_partition_point,std::partition_point)
136 DEFINE_ALGORITHM(poly_partition_point,boost::poly_collection::partition_point)
137 
138 template<typename...>
139 struct std_for_each_n
140 {
141   /* implemented here as the algorithm is C++17 */
142 
143   template<typename InputIterator,typename Size,typename Function>
144   InputIterator operator()(InputIterator first,Size n,Function f)const
145   {
146     for(;n>0;++first,(void)--n)f(*first);
147     return first;
148   }
149 };
150 
151 template<typename... Ts>
152 struct std_mismatch:std_cpp11_mismatch<Ts...>
153 {
154   using std_cpp11_mismatch<Ts...>::operator();
155 
156   /* C++14 variants */
157 
158   template<typename InputIterator1,typename InputIterator2>
operator ()std_mismatch159   std::pair<InputIterator1,InputIterator2> operator()(
160     InputIterator1 first1,InputIterator1 last1,
161     InputIterator2 first2,InputIterator2 last2)const
162   {
163     while(first1!=last1&&first2!=last2&&*first1==*first2){
164       ++first1;
165       ++first2;
166     }
167     return {first1,first2};
168   }
169 
170   template<typename InputIterator1,typename InputIterator2,typename Predicate>
operator ()std_mismatch171   std::pair<InputIterator1,InputIterator2> operator()(
172     InputIterator1 first1,InputIterator1 last1,
173     InputIterator2 first2,InputIterator2 last2,Predicate pred)const
174   {
175     while(first1!=last1&&first2!=last2&&pred(*first1,*first2)){
176       ++first1;
177       ++first2;
178     }
179     return {first1,first2};
180   }
181 };
182 
183 template<typename... Ts>
184 struct std_equal:std_cpp11_equal<Ts...>
185 {
186   using std_cpp11_equal<Ts...>::operator();
187 
188   /* C++14 variants */
189 
190   template<typename InputIterator1,typename InputIterator2>
operator ()std_equal191   bool operator()(
192     InputIterator1 first1,InputIterator1 last1,
193     InputIterator2 first2,InputIterator2 last2)const
194   {
195     for(;first1!=last1&&first2!=last2;++first1,++first2){
196       if(!(*first1==*first2))return false;
197     }
198     return first1==last1&&first2==last2;
199   }
200 
201   template<typename InputIterator1,typename InputIterator2,typename Predicate>
operator ()std_equal202   bool operator()(
203     InputIterator1 first1,InputIterator1 last1,
204     InputIterator2 first2,InputIterator2 last2,Predicate pred)const
205   {
206     for(;first1!=last1&&first2!=last2;++first1,++first2){
207       if(!pred(*first1,*first2))return false;
208     }
209     return first1==last1&&first2==last2;
210   }
211 };
212 
213 template<typename... Ts>
214 struct std_is_permutation:std_cpp11_is_permutation<Ts...>
215 {
216   using std_cpp11_is_permutation<Ts...>::operator();
217 
218   /* The implementation of predicate-based std::is_permutation in GCC<=4.8
219    * version of libstdc++-v3 incorrectly triggers the instantiation of
220    * ForwardIterator2::value_type, which fails when this is an abstract class.
221    * The implementation below ripped from libc++ source code.
222    */
223 
224   template<
225     typename ForwardIterator1,typename ForwardIterator2,typename Predicate
226   >
operator ()std_is_permutation227   bool operator()(
228     ForwardIterator1 first1,ForwardIterator1 last1,
229     ForwardIterator2 first2,Predicate pred)const
230   {
231     using difference_type=
232       typename std::iterator_traits<ForwardIterator1>::difference_type;
233 
234     for(;first1!=last1;++first1,(void)++first2){
235       if(!pred(*first1,*first2))goto not_done;
236     }
237     return true;
238 
239   not_done:
240     difference_type l1=std::distance(first1,last1);
241     if(l1==difference_type(1))return false;
242 
243     ForwardIterator2 last2=std::next(first2,l1);
244     for(ForwardIterator1 i=first1;i!= last1;++i){
245       for(ForwardIterator1 j=first1;j!=i;++j)if(pred(*j,*i))goto next_iter;
246       {
247         difference_type c2=0;
248         for(ForwardIterator2 j=first2;j!=last2;++j)if(pred(*i,*j))++c2;
249         if(c2==0)return false;
250         difference_type c1=1;
251         for(ForwardIterator1 j=std::next(i);j!=last1;++j)if(pred(*i,*j))++c1;
252         if(c1!=c2)return false;
253       }
254   next_iter:;
255     }
256     return true;
257   }
258 
259   /* C++14 variants */
260 
261   template<typename ForwardIterator1,typename ForwardIterator2>
operator ()std_is_permutation262   bool operator()(
263     ForwardIterator1 first1,ForwardIterator1 last1,
264     ForwardIterator2 first2,ForwardIterator2 last2)const
265   {
266     if(std::distance(first1,last1)!=std::distance(first2,last2))return false;
267     return (*this)(first1,last1,first2);
268   }
269 
270   template<
271     typename ForwardIterator1,typename ForwardIterator2,typename Predicate
272   >
operator ()std_is_permutation273   bool operator()(
274     ForwardIterator1 first1,ForwardIterator1 last1,
275     ForwardIterator2 first2,ForwardIterator2 last2,Predicate pred)const
276   {
277     if(std::distance(first1,last1)!=std::distance(first2,last2))return false;
278     return (*this)(first1,last1,first2,pred);
279   }
280 };
281 
282 template<typename...>
283 struct std_sample
284 {
285   /* Implemented here as the algorithm is C++17 and because we need to control
286    * the implementation to do white-box testing. Only the ForwardIterator
287    * version required.
288    */
289 
290   template<
291     typename ForwardIterator,typename OutputIterator,
292     typename Distance, typename UniformRandomBitGenerator
293   >
294   OutputIterator operator()(
295     ForwardIterator first,ForwardIterator last,
296     OutputIterator res, Distance n,UniformRandomBitGenerator&& g)const
297   {
298     Distance m=std::distance(first,last);
299     for(n=(std::min)(n,m);n!=0;++first){
300       auto r=std::uniform_int_distribution<Distance>(0,--m)(g);
301       if (r<n){
302         *res++=*first;
303         --n;
304       }
305     }
306     return res;
307   }
308 };
309 
310 template<
311   typename ControlAlgorithm,typename Algorithm,
312   typename PolyCollection,typename... Args
313 >
test_algorithm(PolyCollection & p,Args &&...args)314 void test_algorithm(PolyCollection& p,Args&&... args)
315 {
316   Algorithm        alg;
317   ControlAlgorithm control;
318   for(auto first=p.begin(),end=p.end();;++first){
319     for(auto last=first;;++last){
320       BOOST_TEST(
321         alg(first,last,std::forward<Args>(args)...)==
322         control(first,last,std::forward<Args>(args)...));
323       if(last==end)break;
324     }
325     if(first==end)break;
326   }
327 }
328 
329 template<
330   typename ControlAlgorithm,typename... Algorithms,
331   typename PolyCollection,typename... Args
332 >
test_algorithms(PolyCollection & p,Args &&...args)333 void test_algorithms(PolyCollection& p,Args&&... args)
334 {
335   do_((test_algorithm<ControlAlgorithm,Algorithms>(
336     p,std::forward<Args>(args)...),0)...);
337   do_((test_algorithm<ControlAlgorithm,Algorithms>(
338     const_cast<const PolyCollection&>(p),std::forward<Args>(args)...),0)...);
339 }
340 
341 template<
342   typename ControlAlgorithm,typename... Algorithms,
343   typename PolyCollection,typename... Args
344 >
test_algorithms_with_equality_impl(std::true_type,PolyCollection & p,Args &&...args)345 void test_algorithms_with_equality_impl(
346   std::true_type,PolyCollection& p,Args&&... args)
347 {
348   test_algorithms<ControlAlgorithm,Algorithms...>(
349     p,std::forward<Args>(args)...);
350 }
351 
352 template<
353   typename ControlAlgorithm,typename... Algorithm,
354   typename PolyCollection,typename... Args
355 >
test_algorithms_with_equality_impl(std::false_type,PolyCollection &,Args &&...)356 void test_algorithms_with_equality_impl(
357   std::false_type,PolyCollection&,Args&&...)
358 {
359 }
360 
361 template<
362   typename ControlAlgorithm,typename... Algorithms,
363   typename PolyCollection,typename... Args
364 >
test_algorithms_with_equality(PolyCollection & p,Args &&...args)365 void test_algorithms_with_equality(PolyCollection& p,Args&&... args)
366 {
367   test_algorithms_with_equality_impl<ControlAlgorithm,Algorithms...>(
368     is_equality_comparable<typename PolyCollection::value_type>{},
369     p,std::forward<Args>(args)...);
370 }
371 
372 template<
373   typename ControlAlgorithm,typename Algorithm,
374   typename ToInt,typename PolyCollection
375 >
test_for_each_n_algorithm(ToInt to_int,PolyCollection & p)376 void test_for_each_n_algorithm(ToInt to_int,PolyCollection& p)
377 {
378   Algorithm        alg;
379   ControlAlgorithm control;
380   for(auto first=p.begin(),end=p.end();;++first){
381     for(auto n=std::distance(first,end);n>=0;--n){
382       int  res1=0,res2=0;
383       auto acc1=compose(to_int,[&](int x){res1+=x;});
384       auto acc2=compose(to_int,[&](int x){res2+=x;});
385       auto it1=alg(first,n,acc1),
386            it2=control(first,n,acc2);
387       BOOST_TEST(it1==it2);
388       BOOST_TEST(res1==res2);
389     }
390     if(first==end)break;
391   }
392 }
393 
394 template<
395   typename ControlAlgorithm,typename... Algorithms,
396   typename ToInt,typename PolyCollection
397 >
test_for_each_n_algorithms(ToInt to_int,PolyCollection & p)398 void test_for_each_n_algorithms(ToInt to_int,PolyCollection& p)
399 {
400   do_((test_for_each_n_algorithm<ControlAlgorithm,Algorithms>(
401     to_int,p),0)...);
402   do_((test_for_each_n_algorithm<ControlAlgorithm,Algorithms>(
403     to_int,const_cast<const PolyCollection&>(p)),0)...);
404 }
405 
406 template<
407   typename ControlAlgorithm,typename Algorithm,
408   typename ToInt,typename PolyCollection,typename... Args
409 >
test_copy_algorithm(ToInt to_int,PolyCollection & p,Args &&...args)410 void test_copy_algorithm(ToInt to_int,PolyCollection& p,Args&&... args)
411 {
412   Algorithm        alg;
413   ControlAlgorithm control;
414   for(auto first=p.begin(),end=p.end();;++first){
415     for(auto last=first;;++last){
416       using vector=std::vector<int>;
417 
418       vector v1,v2;
419       auto   insert1=compose(to_int,[&](int x){v1.push_back(x);});
420       auto   insert2=compose(to_int,[&](int x){v2.push_back(x);});
421       auto   out1=boost::make_function_output_iterator(std::ref(insert1));
422       auto   out2=boost::make_function_output_iterator(std::ref(insert2));
423 
424       out1=alg(first,last,out1,std::forward<Args>(args)...);
425       out2=control(first,last,out2,std::forward<Args>(args)...);
426       BOOST_TEST(v1==v2);
427       if(last==end)break;
428     }
429     if(first==end)break;
430   }
431 }
432 
433 template<
434   typename ControlAlgorithm,typename... Algorithms,
435   typename ToInt,typename PolyCollection,typename... Args
436 >
test_copy_algorithms(ToInt to_int,PolyCollection & p,Args &&...args)437 void test_copy_algorithms(ToInt to_int,PolyCollection& p,Args&&... args)
438 {
439   do_((test_copy_algorithm<ControlAlgorithm,Algorithms>(
440     to_int,p,std::forward<Args>(args)...),0)...);
441   do_((test_copy_algorithm<ControlAlgorithm,Algorithms>(
442     to_int,const_cast<const PolyCollection&>(p),
443     std::forward<Args>(args)...),0)...);
444 }
445 
446 template<
447   typename ControlAlgorithm,typename... Algorithms,
448   typename ToInt,typename PolyCollection,typename... Args
449 >
test_copy_algorithms_with_equality_impl(std::true_type,ToInt to_int,PolyCollection & p,Args &&...args)450 void test_copy_algorithms_with_equality_impl(
451   std::true_type,ToInt to_int,PolyCollection& p,Args&&... args)
452 {
453   test_copy_algorithms<ControlAlgorithm,Algorithms...>(
454     to_int,p,std::forward<Args>(args)...);
455 }
456 
457 template<
458   typename ControlAlgorithm,typename... Algorithm,
459   typename ToInt,typename PolyCollection,typename... Args
460 >
test_copy_algorithms_with_equality_impl(std::false_type,ToInt,PolyCollection &,Args &&...)461 void test_copy_algorithms_with_equality_impl(
462   std::false_type,ToInt,PolyCollection&,Args&&...)
463 {
464 }
465 
466 template<
467   typename ControlAlgorithm,typename... Algorithms,
468   typename ToInt,typename PolyCollection,typename... Args
469 >
test_copy_algorithms_with_equality(ToInt to_int,PolyCollection & p,Args &&...args)470 void test_copy_algorithms_with_equality(
471   ToInt to_int,PolyCollection& p,Args&&... args)
472 {
473   test_copy_algorithms_with_equality_impl<ControlAlgorithm,Algorithms...>(
474     is_equality_comparable<typename PolyCollection::value_type>{},
475     to_int,p,std::forward<Args>(args)...);
476 }
477 
478 template<
479   typename ControlAlgorithm,typename Algorithm,
480   typename ToInt,typename PolyCollection,typename... Args
481 >
test_copy_n_algorithm(ToInt to_int,PolyCollection & p,Args &&...args)482 void test_copy_n_algorithm(ToInt to_int,PolyCollection& p,Args&&... args)
483 {
484   Algorithm        alg;
485   ControlAlgorithm control;
486   for(auto first=p.begin(),end=p.end();;++first){
487     for(std::ptrdiff_t n=0,m=std::distance(first,end);n<=m;++n){
488       using vector=std::vector<int>;
489 
490       vector v1,v2;
491       auto   insert1=compose(to_int,[&](int x){v1.push_back(x);});
492       auto   insert2=compose(to_int,[&](int x){v2.push_back(x);});
493       auto   out1=boost::make_function_output_iterator(std::ref(insert1));
494       auto   out2=boost::make_function_output_iterator(std::ref(insert2));
495 
496       alg(first,n,out1,std::forward<Args>(args)...);
497       control(first,n,out2,std::forward<Args>(args)...);
498       BOOST_TEST(v1==v2);
499     }
500     if(first==end)break;
501   }
502 }
503 
504 template<
505   typename ControlAlgorithm,typename... Algorithms,
506   typename ToInt,typename PolyCollection,typename... Args
507 >
test_copy_n_algorithms(ToInt to_int,PolyCollection & p,Args &&...args)508 void test_copy_n_algorithms(ToInt to_int,PolyCollection& p,Args&&... args)
509 {
510   do_((test_copy_n_algorithm<ControlAlgorithm,Algorithms>(
511     to_int,p,std::forward<Args>(args)...),0)...);
512   do_((test_copy_n_algorithm<ControlAlgorithm,Algorithms>(
513     to_int,const_cast<const PolyCollection&>(p),
514     std::forward<Args>(args)...),0)...);
515 }
516 
517 template<
518   typename ControlAlgorithm,typename Algorithm,
519   typename ToInt,typename PolyCollection
520 >
test_transform2_algorithm(ToInt to_int,PolyCollection & p)521 void test_transform2_algorithm(ToInt to_int,PolyCollection& p)
522 {
523   Algorithm        alg;
524   ControlAlgorithm control;
525   for(auto first=p.begin(),end=p.end();;++first){
526     for(auto last=first;;++last){
527       using vector=std::vector<int>;
528 
529       auto   op=compose_all(to_int,[](int x,int y){return x+y;});
530       vector v1,v2;
531       auto   insert1=[&](int x){v1.push_back(x);};
532       auto   insert2=[&](int x){v2.push_back(x);};
533       auto   out1=boost::make_function_output_iterator(std::ref(insert1));
534       auto   out2=boost::make_function_output_iterator(std::ref(insert2));
535 
536       out1=alg(first,last,p.begin(),out1,op);
537       out2=control(first,last,p.begin(),out2,op);
538       BOOST_TEST(v1==v2);
539       if(last==end)break;
540     }
541     if(first==end)break;
542   }
543 }
544 
545 template<
546   typename ControlAlgorithm,typename... Algorithms,
547   typename ToInt,typename PolyCollection
548 >
test_transform2_algorithms(ToInt to_int,PolyCollection & p)549 void test_transform2_algorithms(ToInt to_int,PolyCollection& p)
550 {
551   do_((test_transform2_algorithm<ControlAlgorithm,Algorithms>(
552     to_int,p),0)...);
553   do_((test_transform2_algorithm<ControlAlgorithm,Algorithms>(
554     to_int,const_cast<const PolyCollection&>(p)),0)...);
555 }
556 
557 template<
558   typename ControlAlgorithm,typename Algorithm,
559   typename ToInt,typename PolyCollection
560 >
test_rotate_copy_algorithm(ToInt to_int,PolyCollection & p)561 void test_rotate_copy_algorithm(ToInt to_int,PolyCollection& p)
562 {
563   Algorithm        alg;
564   ControlAlgorithm control;
565   for(auto first=p.begin(),end=p.end();;++first){
566     for(auto last=first;;++last){
567       for(auto middle=first;;++middle){
568         using vector=std::vector<int>;
569 
570         vector v1,v2;
571         auto   insert1=compose(to_int,[&](int x){v1.push_back(x);});
572         auto   insert2=compose(to_int,[&](int x){v2.push_back(x);});
573         auto   out1=boost::make_function_output_iterator(std::ref(insert1));
574         auto   out2=boost::make_function_output_iterator(std::ref(insert2));
575 
576         out1=alg(first,middle,last,out1);
577         out2=control(first,middle,last,out2);
578         BOOST_TEST(v1==v2);
579 
580         if(middle==last)break;
581       }
582       if(last==end)break;
583     }
584     if(first==end)break;
585   }
586 }
587 
588 template<
589   typename ControlAlgorithm,typename... Algorithms,
590   typename ToInt,typename PolyCollection
591 >
test_rotate_copy_algorithms(ToInt to_int,PolyCollection & p)592 void test_rotate_copy_algorithms(ToInt to_int,PolyCollection& p)
593 {
594   do_((test_rotate_copy_algorithm<ControlAlgorithm,Algorithms>(
595     to_int,p),0)...);
596   do_((test_rotate_copy_algorithm<ControlAlgorithm,Algorithms>(
597     to_int,const_cast<const PolyCollection&>(p)),0)...);
598 }
599 
600 template<
601   typename ControlAlgorithm,typename Algorithm,
602   typename ToInt,typename PolyCollection,typename Predicate
603 >
test_partition_copy_algorithm(ToInt to_int,PolyCollection & p,Predicate pred)604 void test_partition_copy_algorithm(
605   ToInt to_int,PolyCollection& p,Predicate pred)
606 {
607   Algorithm        alg;
608   ControlAlgorithm control;
609   for(auto first=p.begin(),end=p.end();;++first){
610     for(auto last=first;;++last){
611       using vector=std::vector<int>;
612 
613       vector v11,v12,v21,v22;
614       auto   insert11=compose(to_int,[&](int x){v11.push_back(x);});
615       auto   insert12=compose(to_int,[&](int x){v12.push_back(x);});
616       auto   insert21=compose(to_int,[&](int x){v21.push_back(x);});
617       auto   insert22=compose(to_int,[&](int x){v22.push_back(x);});
618       auto   out11=boost::make_function_output_iterator(std::ref(insert11));
619       auto   out12=boost::make_function_output_iterator(std::ref(insert12));
620       auto   out21=boost::make_function_output_iterator(std::ref(insert21));
621       auto   out22=boost::make_function_output_iterator(std::ref(insert22));
622 
623       std::tie(out11,out12)=alg(first,last,out11,out12,pred);
624       std::tie(out21,out22)=control(first,last,out21,out22,pred);
625       BOOST_TEST(v11==v21);
626       BOOST_TEST(v12==v22);
627       if(last==end)break;
628     }
629     if(first==end)break;
630   }
631 }
632 
633 template<
634   typename ControlAlgorithm,typename... Algorithms,
635   typename ToInt,typename PolyCollection,typename Predicate
636 >
test_partition_copy_algorithms(ToInt to_int,PolyCollection & p,Predicate pred)637 void test_partition_copy_algorithms(
638   ToInt to_int,PolyCollection& p,Predicate pred)
639 {
640   do_((test_partition_copy_algorithm<ControlAlgorithm,Algorithms>(
641     to_int,p,pred),0)...);
642   do_((test_partition_copy_algorithm<ControlAlgorithm,Algorithms>(
643     to_int,const_cast<const PolyCollection&>(p),pred),0)...);
644 }
645 
646 template<typename ToInt>
647 struct poly_accumulator_class
648 {
poly_accumulator_classpoly_accumulator_class649   poly_accumulator_class(const ToInt& to_int):res{0},to_int(to_int){}
operator ==poly_accumulator_class650   bool operator==(const poly_accumulator_class& x)const{return res==x.res;}
651 
operator ()poly_accumulator_class652   template<typename T> void operator()(const T& x){res+=to_int(x);}
653 
654   int   res;
655   ToInt to_int;
656 };
657 
658 template<typename ToInt>
poly_accumulator(const ToInt & to_int)659 poly_accumulator_class<ToInt> poly_accumulator(const ToInt& to_int)
660 {
661   return to_int;
662 }
663 
664 template<typename Algorithm>
665 struct force_arg_copying
666 {
667   Algorithm alg;
668 
669   template<typename T>
copyforce_arg_copying670   static T copy(const T& x){return x;}
671 
672   template<typename... Args>
operator ()force_arg_copying673   auto operator()(Args&&... args)const
674     ->decltype(std::declval<Algorithm>()(copy(args)...))
675   {
676     return alg(copy(args)...);
677   }
678 };
679 
680 template<
681   typename PolyCollection,typename ValueFactory,typename ToInt,
682   typename... Types
683 >
test_algorithm()684 void test_algorithm()
685 {
686   PolyCollection p;
687   ValueFactory   v;
688   ToInt          to_int;
689 
690   fill<constraints<>,Types...>(p,v,2);
691 
692   {
693     auto always_true=compose(to_int,[](int){return true;});
694     auto always_false=compose(to_int,[](int){return false;});
695     auto pred=compose(to_int,[](int x){return x%2==0;});
696 
697     test_algorithms<std_all_of<>,poly_all_of<>,poly_all_of<Types...>>(
698       p,always_true);
699     test_algorithms<std_all_of<>,poly_all_of<>,poly_all_of<Types...>>(
700       p,always_false);
701     test_algorithms<std_all_of<>,poly_all_of<>,poly_all_of<Types...>>(
702       p,pred);
703 
704     test_algorithms<std_any_of<>,poly_any_of<>,poly_any_of<Types...>>(
705       p,always_true);
706     test_algorithms<std_any_of<>,poly_any_of<>,poly_any_of<Types...>>(
707       p,always_false);
708     test_algorithms<std_any_of<>,poly_any_of<>,poly_any_of<Types...>>(
709       p,pred);
710 
711     test_algorithms<std_none_of<>,poly_none_of<>,poly_none_of<Types...>>(
712       p,always_true);
713     test_algorithms<std_none_of<>,poly_none_of<>,poly_none_of<Types...>>(
714       p,always_false);
715     test_algorithms<std_none_of<>,poly_none_of<>,poly_none_of<Types...>>(
716       p,pred);
717   }
718   {
719     test_algorithms<std_for_each<>,poly_for_each<>,poly_for_each<Types...>>(
720       p,poly_accumulator(to_int));
721 
722     test_for_each_n_algorithms<
723       std_for_each_n<>,poly_for_each_n<>,poly_for_each_n<Types...>
724     >(to_int,p);
725   }
726   {
727     for(const auto& x:p){
728       test_algorithms_with_equality<
729         std_find<>,poly_find<>,only_eq_comparable<poly_find,Types...>
730       >(p,x);
731     }
732   }
733   {
734     auto it=p.begin();
735     std::advance(it,p.size()/2);
736     int n=to_int(*it);
737     auto pred=compose(to_int,[=](int x){return x==n;});
738 
739     test_algorithms<std_find_if<>,poly_find_if<>,poly_find_if<Types...>>(
740       p,pred);
741 
742     test_algorithms<
743       std_find_if_not<>,poly_find_if_not<>,poly_find_if_not<Types...>
744     >(p,pred);
745   }
746   {
747     auto first=p.begin(),end=first;
748     std::advance(end,+p.size()/2);
749     for(;first!=end;++first){
750       test_algorithms_with_equality<
751         std_find_end<>,poly_find_end<>,
752         only_eq_comparable<poly_find_end,Types...>
753       >(p,first,end);
754 
755       test_algorithms_with_equality<
756         std_search<>,poly_search<>,
757         only_eq_comparable<poly_search,Types...>
758       >(p,first,end);
759     }
760   }
761   {
762     std::vector<int> v;
763     for(const auto& x:p)v.push_back(to_int(x));
764     v.erase(v.begin()+v.size()/2,v.end());
765 
766     for(auto first=v.begin(),end=v.begin()+v.size()/2;first!=end;++first){
767       for(int i=1;i<4;++i){
768         auto pred=compose(to_int,[&](int x,int y){return x%i==y%i;});
769 
770         test_algorithms<
771           std_find_end<>,poly_find_end<>,poly_find_end<Types...>
772         >(p,first,end,pred);
773 
774         test_algorithms<std_search<>,poly_search<>,poly_search<Types...>>(
775           p,first,end,pred);
776       }
777     }
778   }
779   {
780     using value_type=typename PolyCollection::value_type;
781     using vector=std::vector<std::reference_wrapper<const value_type>>;
782 
783     vector v;
784     for(const auto& x:p){
785       switch(v.size()%3){
786         case 0:v.push_back(x);break;
787         case 1:v.push_back(*p.begin());break;
788         default:{}
789       }
790     }
791 
792     for(auto first=v.begin(),end=v.end();;++first){
793       for(auto last=first;;++last){
794         test_algorithms_with_equality<
795           std_find_first_of<>,poly_find_first_of<>,
796           only_eq_comparable<poly_find_first_of,Types...>
797         >(p,first,last);
798         if(last==end)break;
799       }
800       if(first==end)break;
801     }
802   }
803   {
804     std::vector<int> v;
805     for(const auto& x:p){
806       switch(v.size()%3){
807         case 0:v.push_back(to_int(x));break;
808         case 1:v.push_back(-1);break;
809         default:{}
810       }
811     }
812 
813     for(auto first=v.begin(),end=v.end();;++first){
814       for(auto last=first;;++last){
815         test_algorithms<
816           std_find_first_of<>,poly_find_first_of<>,poly_find_first_of<Types...>
817         >(p,first,last,compose(to_int,std::equal_to<int>{}));
818         if(last==end)break;
819       }
820       if(first==end)break;
821     }
822   }
823   {
824     test_algorithms_with_equality<
825       std_adjacent_find<>,poly_adjacent_find<>,
826       only_eq_comparable<poly_adjacent_find,Types...>
827     >(p);
828   }
829   {
830     std::vector<int> v;
831     for(const auto& x:p)v.push_back(to_int(x));
832     v.push_back(-1);
833 
834     for(auto first=v.begin(),end=v.end()-1;first!=end;++first){
835       int n1=*first,n2=*(first+1);
836       test_algorithms<
837         std_adjacent_find<>,poly_adjacent_find<>,poly_adjacent_find<Types...>
838       >(p,compose_all(to_int,[=](int x,int y){return x==n1&&y==n2;}));
839     }
840   }
841   {
842     for(const auto& x:p){
843       test_algorithms_with_equality<
844         std_count<>,poly_count<>,only_eq_comparable<poly_count,Types...>
845       >(p,x);
846     }
847   }
848   {
849     for(int i=1;i<4;++i){
850       test_algorithms<std_count_if<>,poly_count_if<>,poly_count_if<Types...>>(
851         p,compose(to_int,[&](int x){return x%i==0;}));
852     }
853   }
854   {
855     using value_type=typename PolyCollection::value_type;
856     using vector=std::vector<std::reference_wrapper<const value_type>>;
857 
858     vector v;
859     for(const auto& x:p)v.push_back(x);
860     v.back()=v.front();
861     auto w=v;
862     v.insert(v.end(),w.begin(),w.end());
863 
864     for(auto first=v.begin(),end=v.begin()+v.size()/2;first!=end;++first){
865       test_algorithms_with_equality<
866         std_mismatch<>,poly_mismatch<>,
867         only_eq_comparable<poly_mismatch,Types...>
868       >(p,first);
869 
870       test_algorithms_with_equality<
871         std_mismatch<>,poly_mismatch<>,
872         only_eq_comparable<poly_mismatch,Types...>
873       >(p,first,end);
874 
875       test_algorithms_with_equality<
876         std_equal<>,poly_equal<>,only_eq_comparable<poly_equal,Types...>
877       >(p,first);
878 
879       test_algorithms_with_equality<
880         std_equal<>,poly_equal<>,only_eq_comparable<poly_equal,Types...>
881       >(p,first,end);
882     }
883 
884     test_algorithms_with_equality<
885       std_mismatch<>,poly_mismatch<>,only_eq_comparable<poly_mismatch,Types...>
886     >(p,v.end(),v.end());
887 
888     test_algorithms_with_equality<
889       std_equal<>,poly_equal<>,only_eq_comparable<poly_equal,Types...>
890     >(p,v.end(),v.end());
891   }
892   {
893     std::vector<int> v;
894     for(const auto& x:p)v.push_back(to_int(x));
895     v.back()=-1;
896     auto w=v;
897     v.insert(v.end(),w.begin(),w.end());
898     auto pred=compose(to_int,std::equal_to<int>{});
899 
900     for(auto first=v.begin(),end=v.begin()+v.size()/2;first!=end;++first){
901       test_algorithms<std_mismatch<>,poly_mismatch<>,poly_mismatch<Types...>>(
902         p,first,pred);
903 
904       test_algorithms<std_mismatch<>,poly_mismatch<>,poly_mismatch<Types...>>(
905         p,first,end,pred);
906 
907       test_algorithms<std_equal<>,poly_equal<>,poly_equal<Types...>>(
908         p,first,pred);
909 
910       test_algorithms<std_equal<>,poly_equal<>,poly_equal<Types...>>(
911         p,first,end,pred);
912     }
913 
914     test_algorithms<std_mismatch<>,poly_mismatch<>,poly_mismatch<Types...>>(
915       p,v.end(),v.end(),pred);
916 
917     test_algorithms<std_equal<>,poly_equal<>,poly_equal<Types...>>(
918       p,v.end(),v.end(),pred);
919   }
920   {
921     using value_type=typename PolyCollection::value_type;
922     using vector=std::vector<std::reference_wrapper<const value_type>>;
923 
924     vector v;
925     for(const auto& x:p)v.push_back(x);
926     auto w=v;
927     std::mt19937 gen{73642};
928     std::shuffle(w.begin(),w.end(),gen);
929     v.insert(v.end(),w.begin(),w.end());
930     auto pred=compose_all(to_int,std::equal_to<int>{});
931 
932     for(auto first=unwrap_iterator(v.begin()),
933              end=unwrap_iterator(v.begin()+v.size()/2);first!=end;++first){
934       test_algorithms_with_equality<
935         std_is_permutation<>,
936         poly_is_permutation<>,
937         only_eq_comparable<poly_is_permutation,Types...>
938       >(p,first);
939 
940       test_algorithms<
941         std_is_permutation<>,
942         poly_is_permutation<>,poly_is_permutation<Types...>
943       >(p,first,pred);
944 
945       test_algorithms_with_equality<
946         std_is_permutation<>,
947         poly_is_permutation<>,
948         only_eq_comparable<poly_is_permutation,Types...>
949       >(p,first,end);
950 
951       test_algorithms<
952         std_is_permutation<>,
953         poly_is_permutation<>,poly_is_permutation<Types...>
954       >(p,first,end,pred);
955     }
956 
957     test_algorithms_with_equality<
958       std_is_permutation<>,
959       poly_is_permutation<>,
960       only_eq_comparable<poly_is_permutation,Types...>
961     >(p,unwrap_iterator(v.end()),unwrap_iterator(v.end()));
962 
963     test_algorithms<
964       std_is_permutation<>,
965       poly_is_permutation<>,poly_is_permutation<Types...>
966     >(p,unwrap_iterator(v.end()),unwrap_iterator(v.end()),pred);
967   }
968   {
969     /* search tested above */
970   }
971   {
972     for(const auto&x: p){
973       for(int n=0;n<3;++n){
974         test_algorithms_with_equality<
975           std_search_n<>,poly_search_n<>,
976           only_eq_comparable<poly_search_n,Types...>
977         >(p,n,x);
978       }
979     }
980   }
981   {
982     for(int n=0;n<6;++n){
983       test_algorithms<std_search_n<>,poly_search_n<>,poly_search_n<Types...>>(
984         p,n,0,compose(to_int,[&](int x,int y){return x%(6-n)==y%(6-n);}));
985     }
986   }
987   {
988     test_copy_algorithms<std_copy<>,poly_copy<>,poly_copy<Types...>>(
989       to_int,p);
990   }
991   {
992     test_copy_n_algorithms<std_copy_n<>,poly_copy_n<>,poly_copy_n<Types...>>(
993       to_int,p);
994   }
995   {
996     auto always_true=compose(to_int,[](int){return true;});
997     auto always_false=compose(to_int,[](int){return false;});
998     auto pred=compose(to_int,[](int x){return x%2==0;});
999 
1000     test_copy_algorithms<std_copy_if<>,poly_copy_if<>,poly_copy_if<Types...>>(
1001       to_int,p,always_true);
1002     test_copy_algorithms<std_copy_if<>,poly_copy_if<>,poly_copy_if<Types...>>(
1003       to_int,p,always_false);
1004     test_copy_algorithms<std_copy_if<>,poly_copy_if<>,poly_copy_if<Types...>>(
1005       to_int,p,pred);
1006   }
1007   {
1008     test_copy_algorithms<std_move<>,poly_move<>,poly_move<Types...>>(
1009       to_int,p); /* we're not checking std::move is properly used internally */
1010   }
1011   {
1012     auto f=compose(to_int,[](int x){return -x;});
1013     auto int_id=[](int x){return x;};
1014 
1015     test_copy_algorithms<
1016       std_transform<>,poly_transform<>,poly_transform<Types...>
1017     >(int_id,p,f);
1018   }
1019   {
1020     test_transform2_algorithms<
1021       std_transform<>,poly_transform<>,poly_transform<Types...>
1022     >(to_int,p);
1023   }
1024   {
1025     const auto& y=*p.begin();
1026     for(const auto& x:p){
1027       test_copy_algorithms_with_equality<
1028         std_replace_copy<>,poly_replace_copy<>,
1029         only_eq_comparable<poly_replace_copy,Types...>
1030       >(to_int,p,x,y);
1031 
1032       test_copy_algorithms_with_equality<
1033         std_remove_copy<>,poly_remove_copy<>,
1034         only_eq_comparable<poly_remove_copy,Types...>
1035       >(to_int,p,x);
1036     }
1037   }
1038   {
1039     auto  always_true=compose(to_int,[](int){return true;});
1040     auto  always_false=compose(to_int,[](int){return false;});
1041     auto  pred=compose(to_int,[](int x){return x%2==0;});
1042     auto& x=*p.begin();
1043 
1044     test_copy_algorithms<
1045       std_replace_copy_if<>,
1046       poly_replace_copy_if<>,poly_replace_copy_if<Types...>
1047     >(to_int,p,always_true,x);
1048     test_copy_algorithms<
1049       std_replace_copy_if<>,
1050       poly_replace_copy_if<>,poly_replace_copy_if<Types...>
1051     >(to_int,p,always_false,x);
1052     test_copy_algorithms<
1053       std_replace_copy_if<>,
1054       poly_replace_copy_if<>,poly_replace_copy_if<Types...>
1055     >(to_int,p,pred,x);
1056 
1057     test_copy_algorithms<
1058       std_remove_copy_if<>,
1059       poly_remove_copy_if<>,poly_remove_copy_if<Types...>
1060     >(to_int,p,always_true);
1061     test_copy_algorithms<
1062       std_remove_copy_if<>,
1063       poly_remove_copy_if<>,poly_remove_copy_if<Types...>
1064     >(to_int,p,always_false);
1065     test_copy_algorithms<
1066       std_remove_copy_if<>,
1067       poly_remove_copy_if<>,poly_remove_copy_if<Types...>
1068     >(to_int,p,pred);
1069   }
1070   {
1071     test_copy_algorithms_with_equality<
1072       std_unique_copy<>,poly_unique_copy<>,
1073       only_eq_comparable<poly_unique_copy,Types...>
1074     >(to_int,p);
1075   }
1076   {
1077     for(int n=0;n<6;++n){
1078       test_copy_algorithms<
1079         std_unique_copy<>,poly_unique_copy<>,poly_unique_copy<Types...>
1080       >(to_int,p,
1081         compose_all(to_int,[&](int x,int y){return x%(6-n)==y%(6-n);}));
1082     }
1083   }
1084   {
1085     test_rotate_copy_algorithms<
1086       std_rotate_copy<>,poly_rotate_copy<>,poly_rotate_copy<Types...>
1087     >(to_int,p);
1088   }
1089   {
1090     /* force_arg_copying used to avoid sharing mt19937's state */
1091 
1092     for(auto n=p.size()+1;n-->0;){
1093       test_copy_algorithms<
1094         force_arg_copying<std_sample<>>,
1095         force_arg_copying<poly_sample<>>,
1096         force_arg_copying<poly_sample<Types...>>
1097       >(to_int,p,n,std::mt19937{});
1098     }
1099   }
1100   {
1101     for(int n=0;n<6;++n){
1102       auto pred=compose(to_int,[&](int x){return x%(6-n)<=(6-n)/2;});
1103 
1104       test_algorithms<
1105         std_is_partitioned<>,
1106         poly_is_partitioned<>,poly_is_partitioned<Types...>
1107       >(p,pred);
1108 
1109       test_partition_copy_algorithms<
1110         std_partition_copy<>,
1111         poly_partition_copy<>,poly_partition_copy<Types...>
1112       >(to_int,p,pred);
1113 
1114       test_algorithms<
1115         std_partition_point<>,
1116         poly_partition_point<>,poly_partition_point<Types...>
1117       >(p,pred);
1118     }
1119   }
1120 }
1121 
1122 #endif
1123