123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397 |
- // Boost.Range library
- //
- // Copyright Neil Groves 2010. Use, modification and
- // distribution is subject to 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)
- //
- //
- // For more information, see http://www.boost.org/libs/range/
- //
- // Credits:
- // Trac 7376 - was raised by Leonid Gershanovich and his sample was used to
- // make the test case to cover this condition.
- //
- #include <boost/range/join.hpp>
- #include <boost/range/adaptor/transformed.hpp>
- #include <boost/foreach.hpp>
- #include <boost/test/test_tools.hpp>
- #include <boost/test/unit_test.hpp>
- #include <boost/assign.hpp>
- #include <boost/range/algorithm_ext.hpp>
- #include <boost/range/irange.hpp>
- #include <boost/iterator/iterator_facade.hpp>
- #include <algorithm>
- #include <deque>
- #include <list>
- #include <vector>
- namespace boost
- {
- namespace
- {
- // This function is a helper function that writes integers
- // of increasing value into a range. It is used to test
- // that joined ranged may be written to.
- //
- // Requires:
- // - Range uses shallow copy semantics.
- template< typename Range >
- void fill_with_ints(Range rng)
- {
- typedef typename range_iterator<Range>::type iterator;
- iterator target = boost::begin(rng);
- const int count = boost::distance(rng);
- for (int i = 0; i < count; ++i)
- {
- *target = i;
- ++target;
- }
- }
- // The test_join_traversal function is used to provide additional
- // tests based upon the underlying join iterator traversal.
- // The join iterator takes care of the appropriate demotion, and
- // this demotion.
- // test_join_traversal - additional tests for input and forward
- // traversal iterators. This is of course a no-op.
- template< typename Range1, typename Range2, typename TraversalTag >
- void test_join_traversal(Range1& rng1, Range2& rng2, TraversalTag)
- {
- }
- // test_join_traversal - additional tests for bidirectional
- // traversal iterators.
- template< typename Range1, typename Range2 >
- void test_join_traversal(Range1& rng1, Range2& rng2, boost::bidirectional_traversal_tag)
- {
- typedef typename range_value<Range1>::type value_type;
- std::vector<value_type> reference(boost::begin(rng1), boost::end(rng1));
- boost::push_back(reference, rng2);
- std::reverse(reference.begin(), reference.end());
- std::vector<value_type> test_result;
- BOOST_REVERSE_FOREACH( value_type x, join(rng1, rng2) )
- {
- test_result.push_back(x);
- }
- BOOST_CHECK_EQUAL_COLLECTIONS( reference.begin(), reference.end(),
- test_result.begin(), test_result.end() );
- }
- // Test helper function to implement the additional tests for random
- // access traversal iterators. This is used by the test_join_traversal
- // function for random access iterators. The reason that the test
- // implementation is put into this function is to utilise
- // template parameter type deduction for the joined range type.
- template< typename Range1, typename Range2, typename JoinedRange >
- void test_random_access_join(Range1& rng1, Range2& rng2, JoinedRange joined)
- {
- BOOST_CHECK_EQUAL( boost::end(joined) - boost::begin(joined), boost::distance(joined) );
- BOOST_CHECK( boost::end(joined) <= boost::begin(joined) );
- BOOST_CHECK( boost::begin(joined) >= boost::end(joined) );
- if (boost::empty(joined))
- {
- BOOST_CHECK(!(boost::begin(joined) < boost::end(joined)));
- BOOST_CHECK(!(boost::end(joined) > boost::begin(joined)));
- }
- else
- {
- BOOST_CHECK(boost::begin(joined) < boost::end(joined));
- BOOST_CHECK(boost::end(joined) < boost::begin(joined));
- }
- typedef typename boost::range_difference<JoinedRange>::type difference_t;
- const difference_t count = boost::distance(joined);
- BOOST_CHECK( boost::begin(joined) + count == boost::end(joined) );
- BOOST_CHECK( boost::end(joined) - count == boost::begin(joined) );
- typedef typename boost::range_iterator<JoinedRange>::type iterator_t;
- iterator_t it = boost::begin(joined);
- it += count;
- BOOST_CHECK( it == boost::end(joined) );
- it = boost::end(joined);
- it -= count;
- BOOST_CHECK( it == boost::begin(joined) );
- }
- // test_join_traversal function for random access traversal joined
- // ranges.
- template< typename Range1, typename Range2 >
- void test_join_traversal(Range1& rng1, Range2& rng2, boost::random_access_traversal_tag)
- {
- test_join_traversal(rng1, rng2, boost::bidirectional_traversal_tag());
- test_random_access_join(rng1, rng2, join(rng1, rng2));
- }
- // Test the ability to write values into a joined range. This is
- // achieved by copying the constant collections, altering them
- // and then checking the result. Hence this relies upon both
- // rng1 and rng2 having value copy semantics.
- template< typename Collection1, typename Collection2 >
- void test_write_to_joined_range(const Collection1& rng1, const Collection2& rng2)
- {
- Collection1 c1(rng1);
- Collection2 c2(rng2);
-
- typedef BOOST_DEDUCED_TYPENAME boost::range_value<
- Collection1
- >::type value_t BOOST_RANGE_UNUSED;
-
- fill_with_ints(boost::join(c1,c2));
- // Ensure that the size of the written range has not been
- // altered.
- BOOST_CHECK_EQUAL( boost::distance(c1), boost::distance(rng1) );
- BOOST_CHECK_EQUAL( boost::distance(c2), boost::distance(rng2) );
- // For each element x, in c1 ensure that it has been written to
- // with incrementing integers
- int x = 0;
- typedef typename range_iterator<Collection1>::type iterator1;
- iterator1 it1 = boost::begin(c1);
- for (; it1 != boost::end(c1); ++it1)
- {
- BOOST_CHECK_EQUAL( x, *it1 );
- ++x;
- }
- // For each element y, in c2 ensure that it has been written to
- // with incrementing integers
- typedef typename range_iterator<Collection2>::type iterator2;
- iterator2 it2 = boost::begin(c2);
- for (; it2 != boost::end(c2); ++it2)
- {
- BOOST_CHECK_EQUAL( x, *it2 );
- ++x;
- }
- }
- // Perform a unit test of a Boost.Range join() comparing
- // it to a reference that is populated by appending
- // elements from both source ranges into a vector.
- template< typename Collection1, typename Collection2 >
- void test_join_impl(Collection1& rng1, Collection2& rng2)
- {
- typedef typename range_value<Collection1>::type value_type;
- std::vector<value_type> reference(boost::begin(rng1), boost::end(rng1));
- boost::push_back(reference, rng2);
- std::vector<value_type> test_result;
- boost::push_back(test_result, join(rng1, rng2));
- BOOST_CHECK_EQUAL_COLLECTIONS( reference.begin(), reference.end(),
- test_result.begin(), test_result.end() );
- typedef boost::range_detail::join_iterator<
- typename boost::range_iterator<Collection1>::type,
- typename boost::range_iterator<Collection2>::type
- > join_iterator_t;
- typedef boost::iterator_traversal< join_iterator_t > tag_t;
- test_join_traversal(rng1, rng2, tag_t());
- test_write_to_joined_range(rng1, rng2);
- }
- // Make a collection filling it with items from the source
- // range. This is used to build collections of various
- // sizes populated with various values designed to optimize
- // the code coverage exercised by the core test function
- // test_join_impl.
- template<typename Collection, typename Range>
- boost::shared_ptr<Collection> makeCollection(const Range& source)
- {
- boost::shared_ptr<Collection> c(new Collection);
- c->insert(c->end(), boost::begin(source), boost::end(source));
- return c;
- }
- // This templatised version of the test_join_impl function
- // generates and populates collections which are later
- // used as input to the core test function.
- // The caller of this function explicitly provides the
- // template parameters. This supports the generation
- // of testing a large combination of range types to be
- // joined. It is of particular importance to remember
- // to combine a random_access range with a bidirectional
- // range to determine that the correct demotion of
- // types occurs in the join_iterator.
- template< typename Collection1, typename Collection2 >
- void test_join_impl()
- {
- typedef boost::shared_ptr<Collection1> collection1_ptr;
- typedef boost::shared_ptr<Collection2> collection2_ptr;
- typedef boost::shared_ptr<const Collection1> collection1_cptr;
- typedef boost::shared_ptr<const Collection2> collection2_cptr;
- std::vector< collection1_cptr > left_containers;
- std::vector< collection2_cptr > right_containers;
- left_containers.push_back(collection1_ptr(new Collection1));
- left_containers.push_back(makeCollection<Collection1>(irange(0,1)));
- left_containers.push_back(makeCollection<Collection1>(irange(0,100)));
- right_containers.push_back(collection2_ptr(new Collection2));
- right_containers.push_back(makeCollection<Collection2>(irange(0,1)));
- right_containers.push_back(makeCollection<Collection2>(irange(0,100)));
- BOOST_FOREACH( collection1_cptr left_container, left_containers )
- {
- BOOST_FOREACH( collection2_cptr right_container, right_containers )
- {
- test_join_impl(*left_container, *right_container);
- }
- }
- }
- // entry-point into the unit test for the join() function
- // this tests a representative sample of combinations of
- // source range type.
- void join_test()
- {
- test_join_impl< std::vector<int>, std::vector<int> >();
- test_join_impl< std::list<int>, std::list<int> >();
- test_join_impl< std::deque<int>, std::deque<int> >();
- test_join_impl< std::vector<int>, std::list<int> >();
- test_join_impl< std::list<int>, std::vector<int> >();
- test_join_impl< std::vector<int>, std::deque<int> >();
- test_join_impl< std::deque<int>, std::vector<int> >();
- }
-
- void test_join_iterator_reference_type_constness_ticket8483()
- {
- // Just test that this compiles.
- // Before the fix for bug 8483, the reference type of the joined
- // range's iterator was incorrect ('int&' instead of 'const int&'),
- // causing compiler errors.
- const std::vector<int> v1;
- std::vector<int> v2;
- std::vector<int> joined;
- boost::push_back(joined, join(v1, v2));
- boost::push_back(joined, join(v2, v1));
- }
- namespace trac7376
- {
- struct base_type
- {
- explicit base_type(boost::int32_t value)
- : value(value)
- {
- }
- virtual boost::int32_t get() const = 0;
- boost::int32_t value;
- };
- struct derived_type1
- : base_type
- {
- derived_type1(boost::int32_t value)
- : base_type(value)
- {
- }
- virtual boost::int32_t get() const
- {
- return value * 2;
- }
- };
- struct derived_type2
- : base_type
- {
- derived_type2(boost::int32_t value)
- : base_type(value)
- {
- }
- virtual boost::int32_t get() const
- {
- return value * 4;
- }
- };
- struct apply_get
- {
- typedef boost::int32_t result_type;
- result_type operator()(const base_type& arg) const
- {
- return arg.get();
- }
- };
- void test_reference_types()
- {
- using namespace boost::adaptors;
- typedef boost::range_detail::join_iterator<
- std::vector<derived_type1>::iterator,
- std::vector<derived_type2>::iterator,
- const base_type&,
- const base_type&
- > join_iterator_t;
- std::vector<boost::int32_t> reference_output;
- std::vector<derived_type1> x;
- for (boost::int32_t i = 0; i < 10; ++i)
- {
- x.push_back(derived_type1(i));
- reference_output.push_back(i * 2);
- }
- std::vector<derived_type2> y;
- for (boost::int32_t i = 0; i < 10; ++i)
- {
- y.push_back(derived_type2(i));
- reference_output.push_back(i * 4);
- }
- join_iterator_t it(
- x,
- y,
- boost::range_detail::join_iterator_begin_tag());
- std::vector<boost::int32_t> output;
- boost::push_back(
- output,
- boost::make_iterator_range(
- join_iterator_t(
- x, y,
- boost::range_detail::join_iterator_begin_tag()),
- join_iterator_t(
- x, y,
- boost::range_detail::join_iterator_end_tag()))
- | transformed(apply_get()));
- BOOST_CHECK_EQUAL_COLLECTIONS(
- output.begin(), output.end(),
- reference_output.begin(), reference_output.end());
- }
- } // namespace trac7376
- }
- }
- boost::unit_test::test_suite*
- init_unit_test_suite(int argc, char* argv[])
- {
- boost::unit_test::test_suite* test
- = BOOST_TEST_SUITE( "RangeTestSuite.adaptor.joined" );
- test->add( BOOST_TEST_CASE( &boost::join_test ) );
- test->add( BOOST_TEST_CASE( &boost::test_join_iterator_reference_type_constness_ticket8483 ) );
- test->add( BOOST_TEST_CASE( &boost::trac7376::test_reference_types ) );
- return test;
- }
|