counting_iterator_test.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. // (C) Copyright David Abrahams 2001.
  2. // Distributed under the Boost Software License, Version 1.0. (See
  3. // accompanying file LICENSE_1_0.txt or copy at
  4. // http://www.boost.org/LICENSE_1_0.txt)
  5. //
  6. // See http://www.boost.org for most recent version including documentation.
  7. //
  8. // Revision History
  9. // 16 Feb 2001 Added a missing const. Made the tests run (somewhat) with
  10. // plain MSVC again. (David Abrahams)
  11. // 11 Feb 2001 #if 0'd out use of counting_iterator on non-numeric types in
  12. // MSVC without STLport, so that the other tests may proceed
  13. // (David Abrahams)
  14. // 04 Feb 2001 Added use of iterator_tests.hpp (David Abrahams)
  15. // 28 Jan 2001 Removed not_an_iterator detritus (David Abrahams)
  16. // 24 Jan 2001 Initial revision (David Abrahams)
  17. #include <boost/config.hpp>
  18. #ifdef __BORLANDC__ // Borland mis-detects our custom iterators
  19. # pragma warn -8091 // template argument ForwardIterator passed to '...' is a output iterator
  20. # pragma warn -8071 // Conversion may lose significant digits (due to counting_iterator<char> += n).
  21. #endif
  22. #ifdef BOOST_MSVC
  23. # pragma warning(disable:4786) // identifier truncated in debug info
  24. #endif
  25. #include <boost/detail/iterator.hpp>
  26. #include <boost/iterator/counting_iterator.hpp>
  27. #include <boost/iterator/new_iterator_tests.hpp>
  28. #include <boost/next_prior.hpp>
  29. #include <boost/mpl/if.hpp>
  30. #include <boost/detail/iterator.hpp>
  31. #include <boost/detail/workaround.hpp>
  32. #include <boost/limits.hpp>
  33. #include <algorithm>
  34. #include <climits>
  35. #include <iterator>
  36. #include <stdlib.h>
  37. #ifndef __BORLANDC__
  38. # include <boost/tuple/tuple.hpp>
  39. #endif
  40. #include <vector>
  41. #include <list>
  42. #include <boost/detail/lightweight_test.hpp>
  43. #ifndef BOOST_NO_SLIST
  44. # ifdef BOOST_SLIST_HEADER
  45. # include BOOST_SLIST_HEADER
  46. # else
  47. # include <slist>
  48. # endif
  49. #endif
  50. #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
  51. template <class T>
  52. struct signed_assert_nonnegative
  53. {
  54. static void test(T x) { BOOST_TEST(x >= 0); }
  55. };
  56. template <class T>
  57. struct unsigned_assert_nonnegative
  58. {
  59. static void test(T x) {}
  60. };
  61. template <class T>
  62. struct assert_nonnegative
  63. : boost::mpl::if_c<
  64. std::numeric_limits<T>::is_signed
  65. , signed_assert_nonnegative<T>
  66. , unsigned_assert_nonnegative<T>
  67. >::type
  68. {
  69. };
  70. #endif
  71. // Special tests for RandomAccess CountingIterators.
  72. template <class CountingIterator, class Value>
  73. void category_test(
  74. CountingIterator start,
  75. CountingIterator finish,
  76. Value,
  77. std::random_access_iterator_tag)
  78. {
  79. typedef typename
  80. boost::detail::iterator_traits<CountingIterator>::difference_type
  81. difference_type;
  82. difference_type distance = boost::detail::distance(start, finish);
  83. // Pick a random position internal to the range
  84. difference_type offset = (unsigned)rand() % distance;
  85. #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
  86. BOOST_TEST(offset >= 0);
  87. #else
  88. assert_nonnegative<difference_type>::test(offset);
  89. #endif
  90. CountingIterator internal = start;
  91. std::advance(internal, offset);
  92. // Try some binary searches on the range to show that it's ordered
  93. BOOST_TEST(std::binary_search(start, finish, *internal));
  94. // #including tuple crashed borland, so I had to give up on tie().
  95. std::pair<CountingIterator,CountingIterator> xy(
  96. std::equal_range(start, finish, *internal));
  97. CountingIterator x = xy.first, y = xy.second;
  98. BOOST_TEST(boost::detail::distance(x, y) == 1);
  99. // Show that values outside the range can't be found
  100. BOOST_TEST(!std::binary_search(start, boost::prior(finish), *finish));
  101. // Do the generic random_access_iterator_test
  102. typedef typename CountingIterator::value_type value_type;
  103. std::vector<value_type> v;
  104. for (value_type z = *start; !(z == *finish); ++z)
  105. v.push_back(z);
  106. // Note that this test requires a that the first argument is
  107. // dereferenceable /and/ a valid iterator prior to the first argument
  108. boost::random_access_iterator_test(start, v.size(), v.begin());
  109. }
  110. // Special tests for bidirectional CountingIterators
  111. template <class CountingIterator, class Value>
  112. void category_test(CountingIterator start, Value v1, std::bidirectional_iterator_tag)
  113. {
  114. Value v2 = v1;
  115. ++v2;
  116. // Note that this test requires a that the first argument is
  117. // dereferenceable /and/ a valid iterator prior to the first argument
  118. boost::bidirectional_iterator_test(start, v1, v2);
  119. }
  120. template <class CountingIterator, class Value>
  121. void category_test(CountingIterator start, CountingIterator finish, Value v1, std::forward_iterator_tag)
  122. {
  123. Value v2 = v1;
  124. ++v2;
  125. if (finish != start && finish != boost::next(start))
  126. boost::forward_readable_iterator_test(start, finish, v1, v2);
  127. }
  128. template <class CountingIterator, class Value>
  129. void test_aux(CountingIterator start, CountingIterator finish, Value v1)
  130. {
  131. typedef typename CountingIterator::iterator_category category;
  132. // If it's a RandomAccessIterator we can do a few delicate tests
  133. category_test(start, finish, v1, category());
  134. // Okay, brute force...
  135. for (CountingIterator p = start
  136. ; p != finish && boost::next(p) != finish
  137. ; ++p)
  138. {
  139. BOOST_TEST(boost::next(*p) == *boost::next(p));
  140. }
  141. // prove that a reference can be formed to these values
  142. typedef typename CountingIterator::value_type value;
  143. const value* q = &*start;
  144. (void)q; // suppress unused variable warning
  145. }
  146. template <class Incrementable>
  147. void test(Incrementable start, Incrementable finish)
  148. {
  149. test_aux(boost::make_counting_iterator(start), boost::make_counting_iterator(finish), start);
  150. }
  151. template <class Integer>
  152. void test_integer(Integer* = 0) // default arg works around MSVC bug
  153. {
  154. Integer start = 0;
  155. Integer finish = 120;
  156. test(start, finish);
  157. }
  158. template <class Integer, class Category, class Difference>
  159. void test_integer3(Integer* = 0, Category* = 0, Difference* = 0) // default arg works around MSVC bug
  160. {
  161. Integer start = 0;
  162. Integer finish = 120;
  163. typedef boost::counting_iterator<Integer,Category,Difference> iterator;
  164. test_aux(iterator(start), iterator(finish), start);
  165. }
  166. template <class Container>
  167. void test_container(Container* = 0) // default arg works around MSVC bug
  168. {
  169. Container c(1 + (unsigned)rand() % 1673);
  170. const typename Container::iterator start = c.begin();
  171. // back off by 1 to leave room for dereferenceable value at the end
  172. typename Container::iterator finish = start;
  173. std::advance(finish, c.size() - 1);
  174. test(start, finish);
  175. typedef typename Container::const_iterator const_iterator;
  176. test(const_iterator(start), const_iterator(finish));
  177. }
  178. class my_int1 {
  179. public:
  180. my_int1() { }
  181. my_int1(int x) : m_int(x) { }
  182. my_int1& operator++() { ++m_int; return *this; }
  183. bool operator==(const my_int1& x) const { return m_int == x.m_int; }
  184. private:
  185. int m_int;
  186. };
  187. class my_int2 {
  188. public:
  189. typedef void value_type;
  190. typedef void pointer;
  191. typedef void reference;
  192. typedef std::ptrdiff_t difference_type;
  193. typedef std::bidirectional_iterator_tag iterator_category;
  194. my_int2() { }
  195. my_int2(int x) : m_int(x) { }
  196. my_int2& operator++() { ++m_int; return *this; }
  197. my_int2& operator--() { --m_int; return *this; }
  198. bool operator==(const my_int2& x) const { return m_int == x.m_int; }
  199. private:
  200. int m_int;
  201. };
  202. class my_int3 {
  203. public:
  204. typedef void value_type;
  205. typedef void pointer;
  206. typedef void reference;
  207. typedef std::ptrdiff_t difference_type;
  208. typedef std::random_access_iterator_tag iterator_category;
  209. my_int3() { }
  210. my_int3(int x) : m_int(x) { }
  211. my_int3& operator++() { ++m_int; return *this; }
  212. my_int3& operator+=(std::ptrdiff_t n) { m_int += n; return *this; }
  213. std::ptrdiff_t operator-(const my_int3& x) const { return m_int - x.m_int; }
  214. my_int3& operator--() { --m_int; return *this; }
  215. bool operator==(const my_int3& x) const { return m_int == x.m_int; }
  216. bool operator!=(const my_int3& x) const { return m_int != x.m_int; }
  217. bool operator<(const my_int3& x) const { return m_int < x.m_int; }
  218. private:
  219. int m_int;
  220. };
  221. int main()
  222. {
  223. // Test the built-in integer types.
  224. test_integer<char>();
  225. test_integer<unsigned char>();
  226. test_integer<signed char>();
  227. test_integer<wchar_t>();
  228. test_integer<short>();
  229. test_integer<unsigned short>();
  230. test_integer<int>();
  231. test_integer<unsigned int>();
  232. test_integer<long>();
  233. test_integer<unsigned long>();
  234. #if defined(BOOST_HAS_LONG_LONG)
  235. test_integer< ::boost::long_long_type>();
  236. test_integer< ::boost::ulong_long_type>();
  237. #endif
  238. // Test user-defined type.
  239. test_integer3<my_int1, std::forward_iterator_tag, int>();
  240. test_integer3<long, std::random_access_iterator_tag, int>();
  241. test_integer<my_int2>();
  242. test_integer<my_int3>();
  243. // Some tests on container iterators, to prove we handle a few different categories
  244. test_container<std::vector<int> >();
  245. test_container<std::list<int> >();
  246. # ifndef BOOST_NO_SLIST
  247. test_container<BOOST_STD_EXTENSION_NAMESPACE::slist<int> >();
  248. # endif
  249. // Also prove that we can handle raw pointers.
  250. int array[2000];
  251. test(boost::make_counting_iterator(array), boost::make_counting_iterator(array+2000-1));
  252. return boost::report_errors();
  253. }