// (C) Copyright David Abrahams 2001. // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // See http://www.boost.org for most recent version including documentation. // // Revision History // 16 Feb 2001 Added a missing const. Made the tests run (somewhat) with // plain MSVC again. (David Abrahams) // 11 Feb 2001 #if 0'd out use of counting_iterator on non-numeric types in // MSVC without STLport, so that the other tests may proceed // (David Abrahams) // 04 Feb 2001 Added use of iterator_tests.hpp (David Abrahams) // 28 Jan 2001 Removed not_an_iterator detritus (David Abrahams) // 24 Jan 2001 Initial revision (David Abrahams) #include #ifdef BOOST_BORLANDC // Borland mis-detects our custom iterators # pragma warn -8091 // template argument ForwardIterator passed to '...' is a output iterator # pragma warn -8071 // Conversion may lose significant digits (due to counting_iterator += n). #endif #ifdef BOOST_MSVC # pragma warning(disable:4786) // identifier truncated in debug info #endif #include #include #include #include #include #include #include #include #include #include #ifndef BOOST_BORLANDC # include #endif #include #include #include #ifndef BOOST_NO_SLIST # ifdef BOOST_SLIST_HEADER # include BOOST_SLIST_HEADER # else # include # endif #endif #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS template struct signed_assert_nonnegative { static void test(T x) { BOOST_TEST(x >= 0); } }; template struct unsigned_assert_nonnegative { static void test(T x) {} }; template struct assert_nonnegative : boost::mpl::if_c< std::numeric_limits::is_signed , signed_assert_nonnegative , unsigned_assert_nonnegative >::type { }; #endif // Special tests for RandomAccess CountingIterators. template void category_test( CountingIterator start, CountingIterator finish, Value, std::random_access_iterator_tag) { typedef typename std::iterator_traits::difference_type difference_type; difference_type distance = std::distance(start, finish); // Pick a random position internal to the range difference_type offset = (unsigned)rand() % distance; #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS BOOST_TEST(offset >= 0); #else assert_nonnegative::test(offset); #endif CountingIterator internal = start; std::advance(internal, offset); // Try some binary searches on the range to show that it's ordered BOOST_TEST(std::binary_search(start, finish, *internal)); // #including tuple crashed borland, so I had to give up on tie(). std::pair xy( std::equal_range(start, finish, *internal)); CountingIterator x = xy.first, y = xy.second; BOOST_TEST(std::distance(x, y) == 1); // Show that values outside the range can't be found BOOST_TEST(!std::binary_search(start, boost::prior(finish), *finish)); // Do the generic random_access_iterator_test typedef typename CountingIterator::value_type value_type; std::vector v; for (value_type z = *start; !(z == *finish); ++z) v.push_back(z); // Note that this test requires a that the first argument is // dereferenceable /and/ a valid iterator prior to the first argument boost::random_access_iterator_test(start, v.size(), v.begin()); } // Special tests for bidirectional CountingIterators template void category_test(CountingIterator start, Value v1, std::bidirectional_iterator_tag) { Value v2 = v1; ++v2; // Note that this test requires a that the first argument is // dereferenceable /and/ a valid iterator prior to the first argument boost::bidirectional_iterator_test(start, v1, v2); } template void category_test(CountingIterator start, CountingIterator finish, Value v1, std::forward_iterator_tag) { Value v2 = v1; ++v2; if (finish != start && finish != boost::next(start)) boost::forward_readable_iterator_test(start, finish, v1, v2); } template void test_aux(CountingIterator start, CountingIterator finish, Value v1) { typedef typename CountingIterator::iterator_category category; // If it's a RandomAccessIterator we can do a few delicate tests category_test(start, finish, v1, category()); // Okay, brute force... for (CountingIterator p = start ; p != finish && boost::next(p) != finish ; ++p) { BOOST_TEST(boost::next(*p) == *boost::next(p)); } // prove that a reference can be formed to these values typedef typename CountingIterator::value_type value; const value* q = &*start; (void)q; // suppress unused variable warning } template void test(Incrementable start, Incrementable finish) { test_aux(boost::make_counting_iterator(start), boost::make_counting_iterator(finish), start); } template void test_integer(Integer* = 0) // default arg works around MSVC bug { Integer start = 0; Integer finish = 120; test(start, finish); } template void test_integer3(Integer* = 0, Category* = 0, Difference* = 0) // default arg works around MSVC bug { Integer start = 0; Integer finish = 120; typedef boost::counting_iterator iterator; test_aux(iterator(start), iterator(finish), start); } template void test_container(Container* = 0) // default arg works around MSVC bug { Container c(1 + (unsigned)rand() % 1673); const typename Container::iterator start = c.begin(); // back off by 1 to leave room for dereferenceable value at the end typename Container::iterator finish = start; std::advance(finish, c.size() - 1); test(start, finish); typedef typename Container::const_iterator const_iterator; test(const_iterator(start), const_iterator(finish)); } class my_int1 { public: my_int1() { } my_int1(int x) : m_int(x) { } my_int1& operator++() { ++m_int; return *this; } bool operator==(const my_int1& x) const { return m_int == x.m_int; } private: int m_int; }; class my_int2 { public: typedef void value_type; typedef void pointer; typedef void reference; typedef std::ptrdiff_t difference_type; typedef std::bidirectional_iterator_tag iterator_category; my_int2() { } my_int2(int x) : m_int(x) { } my_int2& operator++() { ++m_int; return *this; } my_int2& operator--() { --m_int; return *this; } bool operator==(const my_int2& x) const { return m_int == x.m_int; } private: int m_int; }; class my_int3 { public: typedef void value_type; typedef void pointer; typedef void reference; typedef std::ptrdiff_t difference_type; typedef std::random_access_iterator_tag iterator_category; my_int3() { } my_int3(int x) : m_int(x) { } my_int3& operator++() { ++m_int; return *this; } my_int3& operator+=(std::ptrdiff_t n) { m_int += n; return *this; } std::ptrdiff_t operator-(const my_int3& x) const { return m_int - x.m_int; } my_int3& operator--() { --m_int; return *this; } bool operator==(const my_int3& x) const { return m_int == x.m_int; } bool operator!=(const my_int3& x) const { return m_int != x.m_int; } bool operator<(const my_int3& x) const { return m_int < x.m_int; } private: int m_int; }; int main() { // Test the built-in integer types. test_integer(); test_integer(); test_integer(); test_integer(); test_integer(); test_integer(); test_integer(); test_integer(); test_integer(); test_integer(); #if defined(BOOST_HAS_LONG_LONG) test_integer< ::boost::long_long_type>(); test_integer< ::boost::ulong_long_type>(); #endif // Test user-defined type. test_integer3(); test_integer3(); test_integer(); test_integer(); // Some tests on container iterators, to prove we handle a few different categories test_container >(); test_container >(); # ifndef BOOST_NO_SLIST test_container >(); # endif // Also prove that we can handle raw pointers. int array[2000]; test(boost::make_counting_iterator(array), boost::make_counting_iterator(array+2000-1)); return boost::report_errors(); }