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 > |
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 > |
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> |
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> |
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 | |
169 | void strided_test() |
170 | { |
171 | strided_test_impl< std::vector<int> >(); |
172 | strided_test_impl< std::list<int> >(); |
173 | } |
174 | |
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(x: 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(on&: output, from: 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: |
211 | explicit strided_mock_iterator(BaseIterator it) |
212 | : super_t(it) |
213 | { |
214 | } |
215 | |
216 | private: |
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> > |
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 | |
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(x: 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(on&: output, from: as_mock_range<boost::forward_traversal_tag>(rng&: 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(on&: output, from: as_mock_range<boost::bidirectional_traversal_tag>(rng&: 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(on&: output, from: as_mock_range<boost::random_access_traversal_tag>(rng&: 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> |
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> |
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 | |
284 | void strided_test_ticket_5236() |
285 | { |
286 | std::vector<int> v; |
287 | v.push_back(x: 1); |
288 | strided_test_ticket_5236_check( rng: 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(x: 1); |
295 | strided_test_ticket_5236_check_bidirectional( rng: l | boost::adaptors::strided(2) ); |
296 | } |
297 | |
298 | } |
299 | } |
300 | |
301 | boost::unit_test::test_suite* |
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 | |