]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | |
92f5a8d4 | 12 | // contributed by Maxim Yanchenko as part of the trac ticket. |
7c673cae FG |
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(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: | |
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(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> | |
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(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* | |
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 | } |