strided.cpp 10 KB

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