1 // Boost.Range library
2 //
3 //  Copyright Neil Groves 2009. Use, modification and
4 //  distribution is subject to the Boost Software License, Version
5 //  1.0. (See accompanying file LICENSE_1_0.txt or copy at
6 //  http://www.boost.org/LICENSE_1_0.txt)
7 //
8 //
9 // For more information, see http://www.boost.org/libs/range/
10 //
11 #include <boost/range/adaptor/filtered.hpp>
12 
13 #include <boost/test/test_tools.hpp>
14 #include <boost/test/unit_test.hpp>
15 
16 #include <boost/assign.hpp>
17 #include <boost/range/algorithm_ext.hpp>
18 
19 #include <algorithm>
20 #include <list>
21 #include <set>
22 #include <string>
23 #include <vector>
24 #include <sstream>
25 
26 namespace boost
27 {
28     namespace
29     {
30         struct always_false_pred
31         {
32             template< class T1 >
operator ()boost::__anon5f72b0bf0111::always_false_pred33             bool operator()(T1) const { return false; }
34         };
35 
36         struct always_true_pred
37         {
38             template< class T1 >
operator ()boost::__anon5f72b0bf0111::always_true_pred39             bool operator()(T1) const { return true; }
40         };
41 
42         struct is_even
43         {
44             template< class IntegerT >
operator ()boost::__anon5f72b0bf0111::is_even45             bool operator()( IntegerT x ) const { return x % 2 == 0; }
46         };
47 
48         struct is_odd
49         {
50             template< class IntegerT >
operator ()boost::__anon5f72b0bf0111::is_odd51             bool operator()( IntegerT x ) const { return x % 2 != 0; }
52         };
53 
54         struct lambda_init
55         {
56         };
57 
58         struct lambda
59         {
lambdaboost::__anon5f72b0bf0111::lambda60             lambda(const lambda_init& init) {}
lambdaboost::__anon5f72b0bf0111::lambda61             lambda(const lambda& rhs) {}
62 
63             template< class T1 >
operator ()boost::__anon5f72b0bf0111::lambda64             bool operator()(T1) const { return false; }
65 
66         private:
lambdaboost::__anon5f72b0bf0111::lambda67             lambda() {}
operator =boost::__anon5f72b0bf0111::lambda68             lambda& operator=(const lambda& rhs) { return *this; }
69         };
70 
71         template< class Container, class Pred >
filtered_test_impl(Container & c,Pred pred)72         void filtered_test_impl( Container& c, Pred pred )
73         {
74             using namespace boost::adaptors;
75 
76             typedef BOOST_DEDUCED_TYPENAME Container::value_type value_t;
77 
78             // This is my preferred syntax using the | operator.
79             std::vector< value_t > test_result1;
80             boost::push_back(test_result1, c | filtered(pred));
81 
82             // This is an alternative syntax preferred by some.
83             std::vector< value_t > test_result2;
84             boost::push_back(test_result2, adaptors::filter(c, pred));
85 
86             // Calculate the reference result.
87             std::vector< value_t > reference_result;
88             typedef BOOST_DEDUCED_TYPENAME Container::const_iterator iter_t;
89             for (iter_t it = c.begin(); it != c.end(); ++it)
90             {
91                 if (pred(*it))
92                     reference_result.push_back(*it);
93             }
94 
95             BOOST_CHECK_EQUAL_COLLECTIONS( reference_result.begin(),
96                                            reference_result.end(),
97                                            test_result1.begin(),
98                                            test_result1.end() );
99 
100             BOOST_CHECK_EQUAL_COLLECTIONS( reference_result.begin(),
101                                            reference_result.end(),
102                                            test_result2.begin(),
103                                            test_result2.end() );
104         }
105 
106         template< class Rng >
check_copy_assign(Rng r)107         void check_copy_assign(Rng r)
108         {
109             Rng r2 = r;
110             r2 = r;
111         }
112 
113         template< class Container, class Pred >
filtered_range_copy_assign(Container & c,Pred pred)114         void filtered_range_copy_assign(Container& c, Pred pred)
115         {
116             using namespace boost::adaptors;
117             check_copy_assign(c | filtered(pred));
118             check_copy_assign(adaptors::filter(c, pred));
119         }
120 
121         template< class Container, class Pred, class PredInit >
filtered_test_impl()122         void filtered_test_impl()
123         {
124             using namespace boost::assign;
125 
126             Container c;
127             PredInit init;
128             Pred pred(init);
129 
130             // test empty container
131             filtered_test_impl(c, pred);
132 
133             // test one element
134             c += 1;
135             filtered_test_impl(c, pred);
136 
137             // test many elements
138             c += 1,2,2,2,3,4,4,4,4,5,6,7,8,9,9;
139             filtered_test_impl(c, pred);
140 
141             // test the range and iterator are copy assignable
142             filtered_range_copy_assign(c, pred);
143         }
144 
145         template< class Container >
filtered_test_all_predicates()146         void filtered_test_all_predicates()
147         {
148             filtered_test_impl< Container, always_false_pred, always_false_pred >();
149             filtered_test_impl< Container, always_true_pred, always_true_pred >();
150             filtered_test_impl< Container, is_odd, is_odd >();
151             filtered_test_impl< Container, is_even, is_even >();
152             filtered_test_impl< Container, lambda, lambda_init >();
153         }
154 
ticket_10988_single_pass()155         void ticket_10988_single_pass()
156         {
157             std::vector<int> v;
158             std::string str("0 1 2 3 4 5");
159             std::istringstream in(str);
160 
161             boost::push_back(v,
162                 boost::make_iterator_range(
163                     std::istream_iterator<int>(in),
164                     std::istream_iterator<int>())
165                 | boost::adaptors::filtered(is_even()));
166 
167             std::vector<int> reference;
168             for (int i = 0; i < 6; i += 2)
169             {
170                 reference.push_back(i);
171             }
172             BOOST_CHECK_EQUAL_COLLECTIONS(
173                 reference.begin(), reference.end(),
174                 v.begin(), v.end());
175         }
176 
filtered_test()177         void filtered_test()
178         {
179             filtered_test_all_predicates< std::vector< int > >();
180             filtered_test_all_predicates< std::list< int > >();
181             filtered_test_all_predicates< std::set< int > >();
182             filtered_test_all_predicates< std::multiset< int > >();
183             ticket_10988_single_pass();
184         }
185     }
186 }
187 
188 boost::unit_test::test_suite*
init_unit_test_suite(int argc,char * argv[])189 init_unit_test_suite(int argc, char* argv[])
190 {
191     boost::unit_test::test_suite* test
192         = BOOST_TEST_SUITE( "RangeTestSuite.adaptor.filtered" );
193 
194     test->add( BOOST_TEST_CASE( &boost::filtered_test ) );
195 
196     return test;
197 }
198