// (C) Copyright David Abrahams 2001. Permission to copy, use, modify, sell and // distribute this software is granted provided this copyright notice appears in // all copies. This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // // See http://www.boost.org for most recent version including documentation. // // Revision History // 29 Jan 2001 Initial revision (David Abrahams) #include #include #include #include #include #include #include #include #ifndef BOOST_NO_LIMITS # include #endif #ifndef BOOST_NO_SLIST # include #endif inline unsigned unsigned_random(unsigned max) { return (max > 0) ? (unsigned)rand() % max : 0; } // Special tests for ranges supporting random access template void category_test_1( const boost::half_open_range& r, std::random_access_iterator_tag) { typedef boost::half_open_range range; typedef typename range::size_type size_type; size_type size = r.size(); // pick a random offset size_type offset = unsigned_random(size); typename range::value_type x = *(r.begin() + offset); // test contains(value_type) assert(r.contains(r.start()) == !r.empty()); assert(!r.contains(r.finish())); assert(r.contains(x) == (offset != size)); range::const_iterator p = r.find(x); assert((p == r.end()) == (x == r.finish())); assert(r.find(r.finish()) == r.end()); if (offset != size) { assert(x == r[offset]); assert(x == r.at(offset)); } bool caught_out_of_range = false; try { bool never_initialized = x == r.at(size); (void)never_initialized; } catch(std::out_of_range&) { caught_out_of_range = true; } catch(...) { } assert(caught_out_of_range); } // Those tests must be skipped for other ranges template void category_test_1( const boost::half_open_range&, std::forward_iterator_tag) { } unsigned indices[][2] = { {0,0},{0,1},{0,2},{0,3}, {1,1},{1,2},{1,3}, {2,2},{2,3}, {3,3}}; template void category_test_2( const std::vector& ranges, unsigned i, unsigned j, std::random_access_iterator_tag) { typedef Range range; const range& ri = ranges[i]; const range& rj = ranges[j]; if (indices[i][0] <= indices[j][0] && indices[i][1] >= indices[j][1]) assert(ri.contains(rj)); if (ri.contains(rj)) assert((ri & rj) == rj); assert(boost::intersects(ri, rj) == !(ri & rj).empty()); range t1(ri); t1 &= rj; assert(t1 == range(indices[i][0] > indices[j][0] ? ri.start() : rj.start(), indices[i][1] < indices[j][1] ? ri.finish() : rj.finish())); assert(t1 == (ri & rj)); range t2(ri); t2 |= rj; if (ri.empty()) assert(t2 == rj); else if (rj.empty()) assert(t2 == ri); else assert(t2 == range(indices[i][0] < indices[j][0] ? ri.start() : rj.start(), indices[i][1] > indices[j][1] ? ri.finish() : rj.finish())); assert(t2 == (ri | rj)); if (i == j) assert(ri == rj); if (ri.empty() || rj.empty()) assert((ri == rj) == (ri.empty() && rj.empty())); else assert((ri == rj) == (ri.start() == rj.start() && ri.finish() == rj.finish())); assert((ri == rj) == !(ri != rj)); bool same = ri == rj; bool one_empty = ri.empty() != rj.empty(); std::less less; std::less_equal less_equal; std::greater greater; std::greater_equal greater_equal; if (same) { assert(greater_equal(ri,rj)); assert(less_equal(ri,rj)); assert(!greater(ri,rj)); assert(!less(ri,rj)); } #if 0 else if (one_empty) { const range& empty = ri.empty() ? ri : rj; const range& non_empty = rj.empty() ? ri : rj; assert(less(empty,non_empty)); assert(less_equal(empty,non_empty)); assert(!greater(empty,non_empty)); assert(!greater_equal(empty,non_empty)); assert(!less(non_empty,empty)); assert(!less_equal(non_empty,empty)); assert(greater(non_empty,empty)); assert(greater_equal(non_empty,empty)); } else { if (indices[i][0] < indices[j][0] || indices[i][0] == indices[j][0] && indices[i][1] < indices[j][1]) { assert(!greater_equal(ri,rj)); assert(less(ri,rj)); } if (indices[i][0] < indices[j][0] || indices[i][0] == indices[j][0] && indices[i][1] <= indices[j][1]) { assert(!greater(ri,rj)); assert(less_equal(ri,rj)); } if (indices[i][0] > indices[j][0] || indices[i][0] == indices[j][0] && indices[i][1] > indices[j][1]) { assert(!less_equal(ri,rj)); assert(greater(ri,rj)); } if (indices[i][0] > indices[j][0] || indices[i][0] == indices[j][0] && indices[i][1] >= indices[j][1]) { assert(!less(ri,rj)); assert(greater_equal(ri,rj)); } } #endif } template void category_test_2( const std::vector&, unsigned, unsigned, std::forward_iterator_tag) { } template void category_test_2( const std::vector >&, unsigned, unsigned, std::bidirectional_iterator_tag) { } template void test_back(Range& x, std::bidirectional_iterator_tag) { assert(x.back() == boost::prior(x.finish())); } template void test_back(Range& x, std::forward_iterator_tag) { } template boost::half_open_range range_identity(const boost::half_open_range& x) { return x; } template void test(T x0, T x1, T x2, T x3) { std::vector > ranges; typedef boost::half_open_range range; T bounds[4] = { x0, x1, x2, x3 }; const std::size_t num_ranges = sizeof(indices)/sizeof(*indices); // test construction for (std::size_t n = 0; n < num_ranges;++n) { T start = bounds[indices[n][0]]; T finish = bounds[indices[n][1]]; boost::half_open_range r(start, finish); ranges.push_back(r); } // test implicit conversion from std::pair range converted = std::pair(x0,x0); (void)converted; // test assignment, equality and inequality range r00 = range(x0, x0); assert(r00 == range(x0,x0)); assert(r00 == range(x1,x1)); // empty ranges are all equal if (x3 != x0) assert(r00 != range(x0, x3)); r00 = range(x0, x3); assert(r00 == range(x0, x3)); if (x3 != x0) assert(r00 != range(x0, x0)); typedef typename range::iterator iterator; typedef typename iterator::iterator_category category; for (unsigned i = 0; i < num_ranges; ++i) { const range& r = ranges[i]; // test begin(), end(), basic iteration. unsigned count = 0; for (range::const_iterator p = r.begin(), finish = r.end(); p != finish; ++p, ++count) { assert(count < 2100); } // test size(), empty(), front(), back() assert((unsigned)r.size() == count); if (indices[i][0] == indices[i][1]) assert(r.empty()); if (r.empty()) assert(r.size() == 0); if (!r.empty()) { assert(r.front() == r.start()); test_back(r, category()); } // test swap range r1(r); range r2(x0,x3); const bool same = r1 == r2; r1.swap(r2); assert(r1 == range(x0,x3)); assert(r2 == r); if (!same) { assert(r1 != r); assert(r2 != range(x0,x3)); } // do individual tests for random-access iterators category_test_1(r, category()); } for (unsigned j = 0; j < num_ranges; ++j) { for (unsigned k = 0; k < num_ranges; ++k) { category_test_2(ranges, j, k, category()); } } } template void test_integer(Integer* = 0) // default arg works around MSVC bug { const Integer a = 0; const Integer b = a + unsigned_random(128 - a); const Integer c = b + unsigned_random(128 - b); const Integer d = c + unsigned_random(128 - c); test(a, b, c, d); } template void test_container(Container* = 0) // default arg works around MSVC bug { Container c(unsigned_random(1673)); const typename Container::size_type offset1 = unsigned_random(c.size()); const typename Container::size_type offset2 = unsigned_random(c.size() - offset1); typename Container::iterator internal1 = c.begin(); std::advance(internal1, offset1); typename Container::iterator internal2 = internal1; std::advance(internal2, offset2); test(c.begin(), internal1, internal2, c.end()); typedef typename Container::const_iterator const_iterator; test(const_iterator(c.begin()), const_iterator(internal1), const_iterator(internal2), const_iterator(c.end())); } 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(ULLONG_MAX) || defined(ULONG_LONG_MAX) test_integer(); test_integer(); #endif // 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]; const std::size_t a = 0; const std::size_t b = a + unsigned_random(2000 - a); const std::size_t c = b + unsigned_random(2000 - b); test(array, array+b, array+c, array+2000); return 0; }