diff --git a/half_open_range_test.cpp b/half_open_range_test.cpp new file mode 100644 index 0000000..2d089ee --- /dev/null +++ b/half_open_range_test.cpp @@ -0,0 +1,367 @@ +// (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; +}