// 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/
//
#include <boost/range/adaptor/type_erased.hpp>
#include <boost/range/algorithm/copy.hpp>
#include <boost/assign.hpp>
#include <boost/foreach.hpp>
#include <algorithm>
#include <iostream>
#include <list>
#include <vector>

#include <boost/test/test_tools.hpp>
#include <boost/test/unit_test.hpp>

namespace
{
    namespace boost_range_test
    {
        namespace type_erased_example
        {

// The client interface from an OO perspective merely requires a sequence
// of integers that can be forward traversed
typedef boost::any_range<
    int
  , boost::forward_traversal_tag
  , int
  , std::ptrdiff_t
> integer_range;

namespace server
{
    void display_integers(const integer_range& rng)
    {
        boost::copy(rng,
                    std::ostream_iterator<int>(std::cout, ","));

        std::cout << std::endl;
    }
}

namespace client
{
    void run()
    {
        using namespace boost::assign;
        using namespace boost::adaptors;

        // Under most conditions one would simply use an appropriate
        // any_range as a function parameter. The type_erased adaptor
        // is often superfluous. However because the type_erased
        // adaptor is applied to a range, we can use default template
        // arguments that are generated in conjunction with the
        // range type to which we are applying the adaptor.

        std::vector<int> input;
        input += 1,2,3,4,5;

        // Note that this call is to a non-template function
        server::display_integers(input);

        std::list<int> input2;
        input2 += 6,7,8,9,10;

        // Note that this call is to the same non-tempate function
        server::display_integers(input2);

        input2.clear();
        input2 += 11,12,13,14,15;

        // Calling using the adaptor looks like this:
        // Notice that here I have a type_erased that would be a
        // bidirectional_traversal_tag, but this is convertible
        // to the forward_traversal_tag equivalent hence this
        // works.
        server::display_integers(input2 | type_erased<>());

        // However we may simply wish to define an adaptor that
        // takes a range and makes it into an appropriate
        // forward_traversal any_range...
        typedef boost::adaptors::type_erased<
            boost::use_default
          , boost::forward_traversal_tag
        > type_erased_forward;

        // This adaptor can turn other containers with different
        // value_types and reference_types into the appropriate
        // any_range.

        server::display_integers(input2 | type_erased_forward());
    }
}

        } // namespace type_erased_example
    } // namespace boost_range_test
} // anonymous namespace

boost::unit_test::test_suite*
init_unit_test_suite(int argc, char* argv[])
{
    boost::unit_test::test_suite* test
        = BOOST_TEST_SUITE( "RangeTestSuite.adaptor.type_erased_example" );

    test->add( BOOST_TEST_CASE( &boost_range_test::type_erased_example::client::run) );

    return test;
}
