• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // The strided_defect_Trac5014 test case is a modified version of a test case
12 // contributed by Maxim Yanchenko as part of the trac ticket.
13 //
14 // The deque test case has been removed due to erroneous standard library
15 // implementations causing test failures.
16 //
17 #include <boost/range/adaptor/strided.hpp>
18 
19 #include <boost/config.hpp>
20 #include <boost/test/test_tools.hpp>
21 #include <boost/test/unit_test.hpp>
22 
23 #include <boost/assign.hpp>
24 #include <boost/range/algorithm_ext.hpp>
25 
26 #include <algorithm>
27 #include <vector>
28 
29 namespace boost
30 {
31     namespace
32     {
33         template< class Container >
strided_test_impl(Container & c,int stride_size)34         void strided_test_impl( Container& c, int stride_size )
35         {
36             using namespace boost::adaptors;
37 
38             // Rationale:
39             // This requirement was too restrictive. It makes the use of the
40             // strided adaptor too dangerous, and a simple solution existed
41             // to make it safe, hence the strided adaptor has been modified
42             // and this restriction no longer applies.
43             //BOOST_ASSERT( c.size() % STRIDE_SIZE == 0 );
44 
45             Container reference;
46 
47             {
48                 typedef BOOST_DEDUCED_TYPENAME Container::const_iterator
49                             iterator_t BOOST_RANGE_UNUSED;
50                 typedef BOOST_DEDUCED_TYPENAME Container::difference_type
51                             diff_t BOOST_RANGE_UNUSED;
52                 typedef BOOST_DEDUCED_TYPENAME Container::size_type
53                             size_type BOOST_RANGE_UNUSED;
54                 iterator_t it = c.begin();
55 
56                 iterator_t last = c.end();
57                 for (; it != last; )
58                 {
59                     reference.push_back(*it);
60 
61                     for (int i = 0; (it != last) && (i < stride_size); ++i)
62                         ++it;
63                 }
64             }
65 
66             Container test;
67             boost::push_back( test, c | strided(stride_size) );
68 
69             BOOST_CHECK_EQUAL_COLLECTIONS( test.begin(), test.end(),
70                 reference.begin(), reference.end() );
71 
72             Container test2;
73             boost::push_back( test2, adaptors::stride(c, stride_size) );
74 
75             BOOST_CHECK_EQUAL_COLLECTIONS( test2.begin(), test2.end(),
76                 reference.begin(), reference.end() );
77 
78             // Test the const versions:
79             const Container& cc = c;
80             Container test3;
81             boost::push_back( test3, cc | strided(stride_size) );
82 
83             BOOST_CHECK_EQUAL_COLLECTIONS( test3.begin(), test3.end(),
84                 reference.begin(), reference.end() );
85 
86             Container test4;
87             boost::push_back( test4, adaptors::stride(cc, stride_size) );
88 
89             BOOST_CHECK_EQUAL_COLLECTIONS( test4.begin(), test4.end(),
90                 reference.begin(), reference.end() );
91         }
92 
93         template< class Container >
strided_test_impl(int stride_size)94         void strided_test_impl(int stride_size)
95         {
96             using namespace boost::assign;
97 
98             Container c;
99 
100             // Test empty
101             strided_test_impl(c, stride_size);
102 
103             // Test two elements
104             c += 1,2;
105             strided_test_impl(c, stride_size);
106 
107             // Test many elements
108             c += 1,1,1,2,2,3,4,5,6,6,6,7,8,9;
109             strided_test_impl(c, stride_size);
110 
111             // Test an odd number of elements to determine that the relaxation
112             // of the requirements has been successful
113             // Test a sequence of length 1 with a stride of 2
114             c.clear();
115             c += 1;
116             strided_test_impl(c, stride_size);
117 
118             // Test a sequence of length 2 with a stride of 2
119             c.clear();
120             c += 1,2;
121             strided_test_impl(c, stride_size);
122 
123             // Test a sequence of length 3 with a stride of 2
124             c.clear();
125             c += 1,2,3;
126             strided_test_impl(c, stride_size);
127         }
128 
129         template<typename Container>
strided_test_zero_stride()130         void strided_test_zero_stride()
131         {
132             Container c;
133             c.push_back(1);
134 
135             typedef boost::strided_range<Container> strided_range_t;
136             strided_range_t rng( boost::adaptors::stride(c, 0) );
137             boost::ignore_unused_variable_warning(rng);
138             typedef BOOST_DEDUCED_TYPENAME boost::range_iterator<strided_range_t>::type iter_t;
139 
140             typedef BOOST_DEDUCED_TYPENAME boost::iterator_traversal<
141                         BOOST_DEDUCED_TYPENAME Container::const_iterator
142             >::type container_traversal_tag;
143 
144             iter_t first = boost::range_detail::make_begin_strided_iterator(
145                 c, 0, container_traversal_tag());
146 
147             iter_t last = boost::range_detail::make_end_strided_iterator(
148                 c, 0, container_traversal_tag());
149 
150             iter_t it = first;
151             for (int i = 0; i < 10; ++i, ++it)
152             {
153                 BOOST_CHECK(it == first);
154             }
155         }
156 
157         template<typename Container>
strided_test_impl()158         void strided_test_impl()
159         {
160             strided_test_zero_stride< Container >();
161 
162             const int MAX_STRIDE_SIZE = 10;
163             for (int stride_size = 1; stride_size <= MAX_STRIDE_SIZE; ++stride_size)
164             {
165                 strided_test_impl< Container >(stride_size);
166             }
167         }
168 
strided_test()169         void strided_test()
170         {
171             strided_test_impl< std::vector<int> >();
172             strided_test_impl< std::list<int> >();
173         }
174 
strided_defect_Trac5014()175         void strided_defect_Trac5014()
176         {
177             using namespace boost::assign;
178 
179             std::vector<int> v;
180             for (int i = 0; i < 30; ++i)
181                 v.push_back(i);
182 
183             std::vector<int> reference;
184             reference += 0,4,8,12,16,20,24,28;
185 
186             std::vector<int> output;
187             boost::push_back(output, v | boost::adaptors::strided(4));
188 
189             BOOST_CHECK_EQUAL_COLLECTIONS( reference.begin(), reference.end(),
190                                            output.begin(), output.end() );
191 
192             BOOST_CHECK_EQUAL( output.back(), 28 );
193         }
194 
195         template<typename BaseIterator, typename Category>
196         class strided_mock_iterator
197             : public boost::iterator_adaptor<
198                 strided_mock_iterator<BaseIterator,Category>
199               , BaseIterator
200               , boost::use_default
201               , Category
202             >
203         {
204             typedef boost::iterator_adaptor<
205                         strided_mock_iterator
206                       , BaseIterator
207                       , boost::use_default
208                       , Category
209                     > super_t;
210         public:
strided_mock_iterator(BaseIterator it)211             explicit strided_mock_iterator(BaseIterator it)
212                 : super_t(it)
213             {
214             }
215 
216         private:
increment()217             void increment()
218             {
219                 ++(this->base_reference());
220             }
221 
222             friend class boost::iterator_core_access;
223         };
224 
225         template<typename Category, typename Range>
226         boost::iterator_range<strided_mock_iterator<BOOST_DEDUCED_TYPENAME boost::range_iterator<Range>::type, Category> >
as_mock_range(Range & rng)227         as_mock_range(Range& rng)
228         {
229             typedef BOOST_DEDUCED_TYPENAME boost::range_iterator<Range>::type range_iter_t;
230             typedef strided_mock_iterator<range_iter_t, Category> mock_iter_t;
231 
232             return boost::iterator_range<mock_iter_t>(
233                       mock_iter_t(boost::begin(rng)),
234                       mock_iter_t(boost::end(rng)));
235         }
236 
strided_test_traversal()237         void strided_test_traversal()
238         {
239             using namespace boost::assign;
240 
241             std::vector<int> v;
242             for (int i = 0; i < 30; ++i)
243                 v.push_back(i);
244 
245             std::vector<int> reference;
246             reference += 0,4,8,12,16,20,24,28;
247 
248             std::vector<int> output;
249             boost::push_back(output, as_mock_range<boost::forward_traversal_tag>(v) | boost::adaptors::strided(4));
250 
251             BOOST_CHECK_EQUAL_COLLECTIONS( reference.begin(), reference.end(),
252                                            output.begin(), output.end() );
253 
254             output.clear();
255             boost::push_back(output, as_mock_range<boost::bidirectional_traversal_tag>(v) | boost::adaptors::strided(4));
256 
257             BOOST_CHECK_EQUAL_COLLECTIONS( reference.begin(), reference.end(),
258                                            output.begin(), output.end() );
259 
260             output.clear();
261             boost::push_back(output, as_mock_range<boost::random_access_traversal_tag>(v) | boost::adaptors::strided(4));
262 
263             BOOST_CHECK_EQUAL_COLLECTIONS( reference.begin(), reference.end(),
264                                            output.begin(), output.end() );
265         }
266 
267         template<typename Range>
strided_test_ticket_5236_check_bidirectional(const Range & rng)268         void strided_test_ticket_5236_check_bidirectional(const Range& rng)
269         {
270             BOOST_CHECK_EQUAL( boost::distance(rng), 1 );
271             BOOST_CHECK_EQUAL( std::distance(boost::begin(rng), boost::prior(boost::end(rng))), 0 );
272         }
273 
274         template<typename Range>
strided_test_ticket_5236_check(const Range & rng)275         void strided_test_ticket_5236_check(const Range& rng)
276         {
277             strided_test_ticket_5236_check_bidirectional(rng);
278 
279             typename boost::range_iterator<const Range>::type it = boost::end(rng);
280             it = it - 1;
281             BOOST_CHECK_EQUAL( std::distance(boost::begin(rng), it), 0 );
282         }
283 
strided_test_ticket_5236()284         void strided_test_ticket_5236()
285         {
286             std::vector<int> v;
287             v.push_back(1);
288             strided_test_ticket_5236_check( v | boost::adaptors::strided(2) );
289 
290             // Ensure that there is consistency between the random-access implementation
291             // and the bidirectional.
292 
293             std::list<int> l;
294             l.push_back(1);
295             strided_test_ticket_5236_check_bidirectional( l | boost::adaptors::strided(2) );
296         }
297 
298     }
299 }
300 
301 boost::unit_test::test_suite*
init_unit_test_suite(int argc,char * argv[])302 init_unit_test_suite(int argc, char* argv[])
303 {
304     boost::unit_test::test_suite* test
305         = BOOST_TEST_SUITE( "RangeTestSuite.adaptor.strided" );
306 
307     test->add( BOOST_TEST_CASE( &boost::strided_test ) );
308     test->add( BOOST_TEST_CASE( &boost::strided_defect_Trac5014 ) );
309     test->add( BOOST_TEST_CASE( &boost::strided_test_traversal ) );
310     test->add( BOOST_TEST_CASE( &boost::strided_test_ticket_5236 ) );
311 
312     return test;
313 }
314