// Boost.TypeErasure library
//
// Copyright 2011 Steven Watanabe
//
// 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)
//
// $Id$

#include <boost/type_erasure/any.hpp>
#include <boost/type_erasure/any_cast.hpp>
#include <boost/type_erasure/builtin.hpp>
#include <boost/type_erasure/operators.hpp>
#include <boost/type_erasure/member.hpp>
#include <boost/type_erasure/free.hpp>
#include <boost/mpl/vector.hpp>
#include <iostream>
#include <vector>

namespace mpl = boost::mpl;
using namespace boost::type_erasure;

void basic1() {
    //[basic1
    /*`
        The main class in the library is __any.  An __any can
        store objects that meet whatever requirements we specify.
        These requirements are passed to __any as an MPL sequence.

        [note The MPL sequence combines multiple concepts.
        In the rare case when we only want a single concept, it doesn't
        need to be wrapped in an MPL sequence.]
    */
    any<mpl::vector<copy_constructible<>, typeid_<>, relaxed> > x(10);
    int i = any_cast<int>(x); // i == 10
    /*`
        __copy_constructible is a builtin concept that allows us to
        copy and destroy the object.  __typeid_ provides run-time
        type information so that we can use __any_cast.  __relaxed
        enables various useful defaults.  Without __relaxed,
        __any supports /exactly/ what you specify and nothing else.
        In particular, it allows default construction and assignment of __any.
     */
    //]
}

void basic2() {
    //[basic2
    /*`
        Now, this example doesn't do very much.  `x` is approximately
        equivalent to a [@boost:/libs/any/index.html boost::any].
        We can make it more interesting by adding some operators,
        such as `operator++` and `operator<<`.
    */
    any<
        mpl::vector<
            copy_constructible<>,
            typeid_<>,
            incrementable<>,
            ostreamable<>
        >
    > x(10);
    ++x;
    std::cout << x << std::endl; // prints 11
    //]
}

//[basic3
/*`
    The library provides concepts for most C++ operators, but this
    obviously won't cover all use cases;  we often need to
    define our own requirements.  Let's take the `push_back`
    member, defined by several STL containers.
*/

BOOST_TYPE_ERASURE_MEMBER(push_back)

void append_many(any<has_push_back<void(int)>, _self&> container) {
    for(int i = 0; i < 10; ++i)
        container.push_back(i);
}

/*`
    We use the macro __BOOST_TYPE_ERASURE_MEMBER 
    to define a concept called `has_push_back`.
    When we use `has_push_back`, we have to
    tell it the signature of the function, `void(int)`.
    This means that the type we store in the any
    has to have a member that looks like:

    ``
    void push_back(int);
    ``

    Thus, we could call `append_many` with `std::vector<int>`,
    `std::list<int>`, or `std::vector<long>` (because `int` is
    convertible to `long`), but not `std::list<std::string>`
    or `std::set<int>`.

    Also, note that `append_many` has to operate directly
    on its argument.  It cannot make a copy.  To handle this
    we use `_self&` as the second argument of __any.  `_self`
    is a __placeholder.  By using `_self&`, we indicate that
    the __any stores a reference to an external object instead of
    allocating its own object.
*/

/*`
    Member functions can be const.
 */
BOOST_TYPE_ERASURE_MEMBER(empty)
bool is_empty(any<has_empty<bool() const>, const _self&> x) {
    return x.empty();
}

/*`
    For free functions, we can use the macro __BOOST_TYPE_ERASURE_FREE.
*/

BOOST_TYPE_ERASURE_FREE(getline)
std::vector<std::string> read_lines(any<has_getline<bool(_self&, std::string&)>, _self&> stream)
{
    std::vector<std::string> result;
    std::string tmp;
    while(getline(stream, tmp))
        result.push_back(tmp);
    return result;
}

/*`
    The use of `has_getline` is very similar to `has_push_back` above.
    The difference is that the placeholder `_self` is passed in
    the function signature instead of as a separate argument.

    The __placeholder doesn't have to be the first argument.
    We could just as easily make it the second argument.
*/


void read_line(any<has_getline<bool(std::istream&, _self&)>, _self&> str)
{
    getline(std::cin, str);
}

//]

//[basic
//` (For the source of the examples in this section see
//` [@boost:/libs/type_erasure/example/basic.cpp basic.cpp])
//` [basic1]
//` [basic2]
//` [basic3]
//]
