[/
          Copyright Oliver Kowalke 2014.
 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
]

[section:asymmetric Asymmetric coroutine]

Two asymmetric coroutine types - __push_coro__ and __pull_coro__ - provide a
unidirectional transfer of data.
[note ['asymmetric_coroutine<>] is a typedef of __coro__.]


[heading __pull_coro__]
__pull_coro__ transfers data from another execution context (== pulled-from).
The template parameter defines the transferred parameter type.
The constructor of __pull_coro__ takes a function (__coro_fn__) accepting a
reference to an __push_coro__ as argument. Instantiating an __pull_coro__ passes
the control of execution to __coro_fn__ and a complementary __push_coro__ is
synthesized by the library and passed as reference to __coro_fn__.

This kind of coroutine provides __pull_coro_op__. This method only switches
context; it transfers no data.

__pull_coro__ provides input iterators (__pull_coro_it__) and __begin__/__end__
are overloaded. The increment-operation switches the context and transfers data.

        typedef boost::coroutines2::coroutine<int>   coro_t;

        coro_t::pull_type source(
            [&](coro_t::push_type& sink){
                int first=1,second=1;
                sink(first);
                sink(second);
                for(int i=0;i<8;++i){
                    int third=first+second;
                    first=second;
                    second=third;
                    sink(third);
                }
            });

        for(auto i:source)
            std::cout << i <<  " ";

        output:
        1 1 2 3 5 8 13 21 34 55

In this example an __pull_coro__ is created in the main execution context taking
a lambda function (== __coro_fn__) which calculates Fibonacci numbers in a
simple ['for]-loop.
The __coro_fn__ is executed in a newly created execution context which is
managed by the instance of __pull_coro__.
An __push_coro__ is automatically generated by the library and passed as
reference to the lambda function. Each time the lambda function calls
__push_coro_op__ with another Fibonacci number, __push_coro__ transfers it back
to the main execution context. The local state of __coro_fn__ is preserved and
will be restored upon transferring execution control back to __coro_fn__
to calculate the next Fibonacci number.
Because __pull_coro__ provides input iterators and __begin__/__end__ are
overloaded, a ['range-based for]-loop can be used to iterate over the generated
Fibonacci numbers.


[heading __push_coro__]
__push_coro__ transfers data to the other execution context (== pushed-to).
The template parameter defines the transferred parameter type.
The constructor of __push_coro__ takes a function (__coro_fn__) accepting a
reference to an __pull_coro__ as argument. In contrast to __pull_coro__,
instantiating an __push_coro__ does not pass the control of execution to
__coro_fn__ - instead the first call of __push_coro_op__ synthesizes a
complementary __pull_coro__ and passes it as reference to __coro_fn__.

The __push_coro__ interface does not contain a ['get()]-function: you can not retrieve
values from another execution context with this kind of coroutine.

__push_coro__ provides output iterators (__push_coro_it__) and
__begin__/__end__ are overloaded. The increment-operation switches the context
and transfers data.

        typedef boost::coroutines2::coroutine<std::string>   coro_t;

        struct FinalEOL{
            ~FinalEOL(){
                std::cout << std::endl;
            }
        };

        const int num=5, width=15;
        coro_t::push_type writer(
            [&](coro_t::pull_type& in){
                // finish the last line when we leave by whatever means
                FinalEOL eol;
                // pull values from upstream, lay them out 'num' to a line
                for (;;){
                    for(int i=0;i<num;++i){
                        // when we exhaust the input, stop
                        if(!in) return;
                        std::cout << std::setw(width) << in.get();
                        // now that we've handled this item, advance to next
                        in();
                    }
                    // after 'num' items, line break
                    std::cout << std::endl;
                }
            });

        std::vector<std::string> words{
            "peas", "porridge", "hot", "peas",
            "porridge", "cold", "peas", "porridge",
            "in", "the", "pot", "nine",
            "days", "old" };

        std::copy(begin(words),end(words),begin(writer));

        output:
                   peas       porridge            hot           peas       porridge
                   cold           peas       porridge             in            the
                    pot           nine           days            old

In this example an __push_coro__ is created in the main execution context
accepting a lambda function (== __coro_fn__) which requests strings and lays out
'num' of them on each line.
This demonstrates the inversion of control permitted by coroutines. Without
coroutines, a utility function to perform the same job would necessarily
accept each new value as a function parameter, returning after processing that
single value. That function would depend on a static state variable. A
__coro_fn__, however, can request each new value as if by calling a function
-- even though its caller also passes values as if by calling a function.
The __coro_fn__ is executed in a newly created execution context which is
managed by the instance of __push_coro__.
The main execution context passes the strings to the __coro_fn__ by calling
__push_coro_op__.
An __pull_coro__ instance is automatically generated by the library and passed as
reference to the lambda function. The __coro_fn__ accesses the strings passed
from the main execution context by calling __pull_coro_get__ and lays those
strings out on ['std::cout] according the parameters 'num' and 'width'.
The local state of __coro_fn__ is preserved and will be restored after
transferring execution control back to __coro_fn__.
Because __push_coro__ provides output iterators and __begin__/__end__ are
overloaded, the ['std::copy] algorithm can be used to iterate over the vector
containing the strings and pass them one by one to the coroutine.


[heading coroutine-function]
The __coro_fn__ returns ['void] and takes its counterpart-coroutine as
argument, so that using the coroutine passed as argument to __coro_fn__ is the
only way to transfer data and execution control back to the caller.
Both coroutine types take the same template argument.
For __pull_coro__ the __coro_fn__ is entered at __pull_coro__ construction.
For __push_coro__ the __coro_fn__ is not entered at __push_coro__ construction
but entered by the first invocation of __push_coro_op__.
After execution control is returned from __coro_fn__ the state of the
coroutine can be checked via __pull_coro_bool__ returning `true` if the
coroutine is still valid (__coro_fn__ has not terminated). Unless the first
template parameter is `void`, `true` also implies that a data value is
available.


[heading passing data from a pull-coroutine to main-context]
In order to transfer data from an __pull_coro__ to the main-context the framework
synthesizes an __push_coro__ associated with the __pull_coro__ instance in the
main-context. The synthesized __push_coro__ is passed as argument to __coro_fn__.
The __coro_fn__ must call this __push_coro_op__ in order to transfer each
data value back to the main-context.
In the main-context, the __pull_coro_bool__ determines whether the coroutine is
still valid and a data value is available or __coro_fn__ has terminated
(__pull_coro__ is invalid; no data value available). Access to the transferred
data value is given by __pull_coro_get__.

        typedef boost::coroutines2::coroutine<int>   coro_t;

        coro_t::pull_type source( // constructor enters coroutine-function
            [&](coro_t::push_type& sink){
                sink(1); // push {1} back to main-context
                sink(1); // push {1} back to main-context
                sink(2); // push {2} back to main-context
                sink(3); // push {3} back to main-context
                sink(5); // push {5} back to main-context
                sink(8); // push {8} back to main-context
            });

        while(source){            // test if pull-coroutine is valid
            int ret=source.get(); // access data value
            source();             // context-switch to coroutine-function
        }


[heading passing data from main-context to a push-coroutine]
In order to transfer data to an __push_coro__ from the main-context the framework
synthesizes an __pull_coro__ associated with the __push_coro__ instance in the
main-context. The synthesized __pull_coro__ is passed as argument to __coro_fn__.
The main-context must call this __push_coro_op__ in order to transfer each data
value into the __coro_fn__.
Access to the transferred data value is given by __pull_coro_get__.

        typedef boost::coroutines2::coroutine<int>   coro_t;

        coro_t::push_type sink( // constructor does NOT enter coroutine-function
            [&](coro_t::pull_type& source){
                for (int i:source) {
                    std::cout << i <<  " ";
                }
            });

        std::vector<int> v{1,1,2,3,5,8,13,21,34,55};
        for( int i:v){
            sink(i); // push {i} to coroutine-function
        }


[heading accessing parameters]
Parameters returned from or transferred to the __coro_fn__ can be accessed with
__pull_coro_get__.

Splitting-up the access of parameters from context switch function enables to
check if __pull_coro__ is valid after return from __pull_coro_op__, e.g.
__pull_coro__ has values and __coro_fn__ has not terminated.

        typedef boost::coroutines2::coroutine<boost::tuple<int,int>> coro_t;

        coro_t::push_type sink(
            [&](coro_t::pull_type& source){
                // access tuple {7,11}; x==7 y==1
                int x,y;
                boost::tie(x,y)=source.get();
            });

        sink(boost::make_tuple(7,11));


[heading exceptions]
An exception thrown inside an __pull_coro__'s __coro_fn__ before its first call
to __push_coro_op__ will be re-thrown by the __pull_coro__ constructor. After an
__pull_coro__'s __coro_fn__'s first call to __push_coro_op__, any subsequent
exception inside that __coro_fn__ will be re-thrown by __pull_coro_op__.
__pull_coro_get__ does not throw.

An exception thrown inside an __push_coro__'s __coro_fn__ will be re-thrown by
__push_coro_op__.

[important Code executed by __coro_fn__ must not prevent the propagation of the
__forced_unwind__ exception.  Absorbing that exception will cause stack
unwinding to fail.  Thus, any code that catches all exceptions must re-throw any
pending __forced_unwind__ exception.]

        try {
            // code that might throw
        } catch(const boost::context::detail::forced_unwind&) {
            throw;
        } catch(...) {
            // possibly not re-throw pending exception
        }

[important Do not jump from inside a catch block and than re-throw the
exception in another execution context.]


[heading Stack unwinding]
Sometimes it is necessary to unwind the stack of an unfinished coroutine to
destroy local stack variables so they can release allocated resources (RAII
pattern). The `attributes` argument of the coroutine constructor
indicates whether the destructor should unwind the stack (stack is unwound by
default).

Stack unwinding assumes the following preconditions:

* The coroutine is not __not_a_coro__
* The coroutine is not complete
* The coroutine is not running
* The coroutine owns a stack

After unwinding, a __coro__ is complete.

        struct X {
            X(){
                std::cout << "X()" << std::endl;
            }

            ~X(){
                std::cout << "~X()" << std::endl;
            }
        };

        {
            typedef boost::coroutines2::coroutine<void> coro_t;

            coro_t::push_type sink(
                [&](coro_t::pull_type& source){
                    X x;
                    for(int i = 0; ; ++i){
                        std::cout << "fn(): " << i << std::endl;
                        // transfer execution control back to main()
                        source();
                    }
                });

            sink();
            sink();
            sink();
            sink();
            sink();

            std::cout<<"sink is complete: "<<std::boolalpha<<!sink<<"\n";
        }

        output:
            X()
            fn(): 0
            fn(): 1
            fn(): 2
            fn(): 3
            fn(): 4
            sink is complete: false
            ~X()


[heading Range iterators]
__boost_coroutine__ provides output- and input-iterators using __boost_range__.
__pull_coro__ can be used via input-iterators using __begin__ and __end__.

        typedef boost::coroutines2::coroutine< int > coro_t;

        int number=2,exponent=8;
        coro_t::pull_type source(
            [&](coro_t::push_type & sink){
                int counter=0,result=1;
                while(counter++<exponent){
                    result=result*number;
                    sink(result);
                }
            });

        for (auto i:source)
            std::cout << i <<  " ";

        output:
            2 4 8 16 32 64 128 256

['coroutine<>::pull_type::iterator::operator++()] corresponds to
__pull_coro_op__; ['coroutine<>::pull_type::iterator::operator*()]
roughly corresponds to __pull_coro_get__. An iterator originally obtained from
__begin__ of an __pull_coro__ compares equal to an iterator obtained from
__end__ of that same __pull_coro__ instance when its __pull_coro_bool__ would
return `false`].

[note If `T` is a move-only type, then
['coroutine<T>::pull_type::iterator] may only be dereferenced once
before it is incremented again.]

Output-iterators can be created from __push_coro__.

        typedef boost::coroutines2::coroutine<int>   coro_t;

        coro_t::push_type sink(
            [&](coro_t::pull_type& source){
                while(source){
                    std::cout << source.get() <<  " ";
                    source();
                }
            });

        std::vector<int> v{1,1,2,3,5,8,13,21,34,55};
        std::copy(begin(v),end(v),begin(sink));

['coroutine<>::push_type::iterator::operator*()] roughly
corresponds to __push_coro_op__. An iterator originally obtained from
__begin__ of an __push_coro__ compares equal to an iterator obtained from
__end__ of that same __push_coro__ instance when its __push_coro_bool__ would
return `false`.


[heading Exit a __coro_fn__]
__coro_fn__ is exited with a simple return statement jumping back to the calling
routine. The __pull_coro__, __push_coro__ becomes complete, e.g. __pull_coro_bool__,
__push_coro_bool__ will return `false`.

[important After returning from __coro_fn__ the __coro__ is complete (can not
resumed with __push_coro_op__, __pull_coro_op__).]



[section:pull_coro Class `coroutine<>::pull_type`]

    #include <boost/coroutine2/coroutine.hpp>

    template< typename R >
    class coroutine<>::pull_type
    {
    public:
        template< typename Fn >
        pull_type( Fn && fn);

        template< typename StackAllocator, typename Fn >
        pull_type( StackAllocator stack_alloc, Fn && fn);

        pull_type( pull_type const& other)=delete;

        pull_type & operator=( pull_type const& other)=delete;

        ~pull_type();

        pull_type( pull_type && other) noexcept;

        pull_type & operator=( pull_type && other) noexcept;

        pull_coroutine & operator()();

        explicit operator bool() const noexcept;

        bool operator!() const noexcept;

        R get() noexcept;
    };

    template< typename R >
    range_iterator< pull_type< R > >::type begin( pull_type< R > &);

    template< typename R >
    range_iterator< pull_type< R > >::type end( pull_type< R > &);

[heading `template< typename Fn >
          pull_type( Fn && fn)`]
[variablelist
[[Effects:] [Creates a coroutine which will execute `fn`, and enters it.]]
[[Throws:] [Exceptions thrown inside __coro_fn__.]]
]

[heading `template< typename StackAllocator, typename Fn >
          pull_type( StackAllocator const& stack_alloc, Fn && fn)`]
[variablelist
[[Effects:] [Creates a coroutine which will execute `fn`.
For allocating/deallocating the stack `stack_alloc` is used.]]
[[Throws:] [Exceptions thrown inside __coro_fn__.]]
]

[heading `~pull_type()`]
[variablelist
[[Effects:] [Destroys the context and deallocates the stack.]]
]

[heading `pull_type( pull_type && other)`]
[variablelist
[[Effects:] [Moves the internal data of `other` to `*this`.
`other` becomes __not_a_coro__.]]
[[Throws:] [Nothing.]]
]

[heading `pull_type & operator=( pull_type && other)`]
[variablelist
[[Effects:] [Destroys the internal data of `*this` and moves the
internal data of `other` to `*this`. `other` becomes __not_a_coro__.]]
[[Throws:] [Nothing.]]
]

[heading `explicit operator bool() const noexcept`]
[variablelist
[[Returns:] [If `*this` refers to __not_a_coro__ or the coroutine-function
has returned (completed), the function returns `false`. Otherwise `true`.]]
[[Throws:] [Nothing.]]
]

[heading `bool operator!() const noexcept`]
[variablelist
[[Returns:] [If `*this` refers to __not_a_coro__ or the coroutine-function
has returned (completed), the function returns `true`. Otherwise `false`.]]
[[Throws:] [Nothing.]]
]

[heading `pull_type<> & operator()()`]
[variablelist
[[Preconditions:] [`*this` is not a __not_a_coro__.]]
[[Effects:] [Execution control is transferred to __coro_fn__ (no parameter is
passed to the coroutine-function).]]
[[Throws:] [Exceptions thrown inside __coro_fn__.]]
]

[heading `R get() noexcept`]

    R    coroutine<R,StackAllocator>::pull_type::get();
    R&   coroutine<R&,StackAllocator>::pull_type::get();
    void coroutine<void,StackAllocator>::pull_type::get()=delete;

[variablelist
[[Preconditions:] [`*this` is not a __not_a_coro__.]]
[[Returns:] [Returns data transferred from coroutine-function via
__push_coro_op__.]]
[[Throws:] [`invalid_result`]]
[[Note:] [If `R` is a move-only type, you may only call `get()` once before
the next __pull_coro_op__ call.]]
]

[heading Non-member function `begin( pull_type< R > &)`]
    template< typename R >
    range_iterator< pull_type< R > >::type begin( pull_type< R > &);

[variablelist
[[Returns:] [Returns a range-iterator (input-iterator).]]
]

[heading Non-member function `end( pull_type< R > &)`]
    template< typename R >
    range_iterator< pull_type< R > >::type end( pull_type< R > &);

[variablelist
[[Returns:] [Returns an end range-iterator (input-iterator).]]
[[Note:] [When first obtained from `begin( pull_type< R > &)`, or after some
number of increment operations, an iterator will compare equal to the iterator
returned by `end( pull_type< R > &)` when the corresponding __pull_coro_bool__
would return `false`.]]
]

[endsect]


[section:push_coro Class `coroutine<>::push_type`]

    #include <boost/coroutine2/coroutine.hpp>

    template< typename Arg >
    class coroutine<>::push_type
    {
    public:
        template< typename Fn >
        push_type( Fn && fn);

        template< typename StackAllocator, typename Fn >
        push_type( StackAllocator stack_alloc, Fn && fn);

        push_type( push_type const& other)=delete;

        push_type & operator=( push_type const& other)=delete;

        ~push_type();

        push_type( push_type && other) noexcept;

        push_type & operator=( push_type && other) noexcept;

        explicit operator bool() const noexcept;

        bool operator!() const noexcept;

        push_type & operator()( Arg arg);
    };

    template< typename Arg >
    range_iterator< push_type< Arg > >::type begin( push_type< Arg > &);

    template< typename Arg >
    range_iterator< push_type< Arg > >::type end( push_type< Arg > &);

[heading `template< typename Fn >
          push_type( Fn && fn)`]
[variablelist
[[Effects:] [Creates a coroutine which will execute `fn`.]]
]

[heading `template< typename StackAllocator, typename Fn >
          push_type( StackAllocator const& stack_alloc, Fn && fn)`]
[variablelist
[[Effects:] [Creates a coroutine which will execute `fn`.
For allocating/deallocating the stack `stack_alloc` is used.]]
]

[heading `~push_type()`]
[variablelist
[[Effects:] [Destroys the context and deallocates the stack.]]
]

[heading `push_type( push_type && other) noexcept`]
[variablelist
[[Effects:] [Moves the internal data of `other` to `*this`.
`other` becomes __not_a_coro__.]]
[[Throws:] [Nothing.]]
]

[heading `push_type & operator=( push_type && other) noexcept`]
[variablelist
[[Effects:] [Destroys the internal data of `*this` and moves the
internal data of `other` to `*this`. `other` becomes __not_a_coro__.]]
[[Throws:] [Nothing.]]
]

[heading `explicit operator bool() const noexcept`]
[variablelist
[[Returns:] [If `*this` refers to __not_a_coro__ or the coroutine-function
has returned (completed), the function returns `false`. Otherwise `true`.]]
[[Throws:] [Nothing.]]
]

[heading `bool operator!() const noexcept`]
[variablelist
[[Returns:] [If `*this` refers to __not_a_coro__ or the coroutine-function
has returned (completed), the function returns `true`. Otherwise `false`.]]
[[Throws:] [Nothing.]]
]

[heading `push_type & operator()(Arg arg)`]

        push_type& coroutine<Arg>::push_type::operator()(Arg);
        push_type& coroutine<Arg&>::push_type::operator()(Arg&);
        push_type& coroutine<void>::push_type::operator()();

[variablelist
[[Preconditions:] [operator unspecified-bool-type() returns `true` for `*this`.]]
[[Effects:] [Execution control is transferred to __coro_fn__ and the argument
`arg` is passed to the coroutine-function.]]
[[Throws:] [Exceptions thrown inside __coro_fn__.]]
]

[heading Non-member function `begin( push_type< Arg > &)`]
    template< typename Arg >
    range_iterator< push_type< Arg > >::type begin( push_type< Arg > &);

[variablelist
[[Returns:] [Returns a range-iterator (output-iterator).]]
]

[heading Non-member function `end( push_type< Arg > &)`]
    template< typename Arg >
    range_iterator< push_type< Arg > >::type end( push_type< Arg > &);

[variablelist
[[Returns:] [Returns a end range-iterator (output-iterator).]]
[[Note:] [When first obtained from `begin( push_type< R > &)`, or after some
number of increment operations, an iterator will compare equal to the iterator
returned by `end( push_type< R > &)` when the corresponding __push_coro_bool__
would return `false`.]]
]

[endsect]



[endsect]
