diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index f17f570..68f6ef4 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -45,6 +45,7 @@ explicit allocator_sources ; lib boost_coroutine : allocator_sources detail/coroutine_context.cpp + exceptions.cpp : shared:../../context/build//boost_context ; diff --git a/example/cpp03/echo.cpp b/example/cpp03/echo.cpp index e2b19f6..1219707 100644 --- a/example/cpp03/echo.cpp +++ b/example/cpp03/echo.cpp @@ -14,31 +14,31 @@ typedef boost::coroutines::coroutine< void >::pull_type pull_coro_t; typedef boost::coroutines::coroutine< void >::push_type push_coro_t; -void echo( pull_coro_t & c, int i) +void echo( pull_coro_t & source, int i) { std::cout << i; - c(); + source(); } -void runit( push_coro_t & ca) +void runit( push_coro_t & sink1) { std::cout << "started! "; for ( int i = 0; i < 10; ++i) { - push_coro_t c( boost::bind( echo, _1, i) ); - while ( c) - c(); - ca(); + push_coro_t sink2( boost::bind( echo, _1, i) ); + while ( sink2) + sink2(); + sink1(); } } int main( int argc, char * argv[]) { { - pull_coro_t c( runit); - while ( c) { + pull_coro_t source( runit); + while ( source) { std::cout << "-"; - c(); + source(); } } diff --git a/example/cpp03/fibonacci.cpp b/example/cpp03/fibonacci.cpp index 9154a6c..5f6dd4f 100644 --- a/example/cpp03/fibonacci.cpp +++ b/example/cpp03/fibonacci.cpp @@ -11,26 +11,26 @@ #include #ifdef BOOST_COROUTINES_UNIDIRECT -void fibonacci( boost::coroutines::coroutine< int >::push_type & c) +void fibonacci( boost::coroutines::coroutine< int >::push_type & sink) { int first = 1, second = 1; - c( first); - c( second); + sink( first); + sink( second); while ( true) { int third = first + second; first = second; second = third; - c( third); + sink( third); } } int main() { - boost::coroutines::coroutine< int >::pull_type c( fibonacci); + boost::coroutines::coroutine< int >::pull_type source( fibonacci); boost::range_iterator< boost::coroutines::coroutine< int >::pull_type - >::type it( boost::begin( c) ); + >::type it( boost::begin( source) ); for ( int i = 0; i < 10; ++i) { std::cout << * it << " "; diff --git a/example/cpp03/parallel.cpp b/example/cpp03/parallel.cpp index 7c952f7..29098e2 100644 --- a/example/cpp03/parallel.cpp +++ b/example/cpp03/parallel.cpp @@ -11,22 +11,22 @@ #include #ifdef BOOST_COROUTINES_UNIDIRECT -void first( boost::coroutines::coroutine< void >::push_type & c) +void first( boost::coroutines::coroutine< void >::push_type & sink) { std::cout << "started first! "; for ( int i = 0; i < 10; ++i) { - c(); + sink(); std::cout << "a" << i; } } -void second( boost::coroutines::coroutine< void >::push_type & c) +void second( boost::coroutines::coroutine< void >::push_type & sink) { std::cout << "started second! "; for ( int i = 0; i < 10; ++i) { - c(); + sink(); std::cout << "b" << i; } } @@ -34,12 +34,12 @@ void second( boost::coroutines::coroutine< void >::push_type & c) int main( int argc, char * argv[]) { { - boost::coroutines::coroutine< void >::pull_type c1( boost::bind( first, _1) ); - boost::coroutines::coroutine< void >::pull_type c2( boost::bind( second, _1) ); - while ( c1 && c2) { - c1(); + boost::coroutines::coroutine< void >::pull_type source1( boost::bind( first, _1) ); + boost::coroutines::coroutine< void >::pull_type source2( boost::bind( second, _1) ); + while ( source1 && source2) { + source1(); std::cout << " "; - c2(); + source2(); std::cout << " "; } } diff --git a/example/cpp03/power.cpp b/example/cpp03/power.cpp index 370da0f..3a43b6a 100644 --- a/example/cpp03/power.cpp +++ b/example/cpp03/power.cpp @@ -13,14 +13,14 @@ #include #ifdef BOOST_COROUTINES_UNIDIRECT -void power( boost::coroutines::coroutine< int >::push_type & c, int number, int exponent) +void power( boost::coroutines::coroutine< int >::push_type & sink, int number, int exponent) { int counter = 0; int result = 1; while ( counter++ < exponent) { result = result * number; - c( result); + sink( result); } } @@ -28,17 +28,17 @@ int main() { { std::cout << "using range functions" << std::endl; - boost::coroutines::coroutine< int >::pull_type c( boost::bind( power, _1, 2, 8) ); - boost::coroutines::coroutine< int >::pull_type::iterator e( boost::end( c) ); - for ( boost::coroutines::coroutine< int >::pull_type::iterator i( boost::begin( c) ); + boost::coroutines::coroutine< int >::pull_type source( boost::bind( power, _1, 2, 8) ); + boost::coroutines::coroutine< int >::pull_type::iterator e( boost::end( source) ); + for ( boost::coroutines::coroutine< int >::pull_type::iterator i( boost::begin( source) ); i != e; ++i) std::cout << * i << " "; } { std::cout << "\nusing BOOST_FOREACH" << std::endl; - boost::coroutines::coroutine< int >::pull_type c( boost::bind( power, _1, 2, 8) ); - BOOST_FOREACH( int i, c) + boost::coroutines::coroutine< int >::pull_type source( boost::bind( power, _1, 2, 8) ); + BOOST_FOREACH( int i, source) { std::cout << i << " "; } } diff --git a/example/cpp03/segmented_stack.cpp b/example/cpp03/segmented_stack.cpp index 814a5a0..6ca4b9f 100644 --- a/example/cpp03/segmented_stack.cpp +++ b/example/cpp03/segmented_stack.cpp @@ -32,17 +32,17 @@ void bar( int i) } #ifdef BOOST_COROUTINES_UNIDIRECT -void foo( boost::coroutines::coroutine< void >::pull_type & c) +void foo( boost::coroutines::coroutine< void >::pull_type & source) { bar( count); - c(); + source(); } void thread_fn() { { - boost::coroutines::coroutine< void >::push_type c( foo); - c(); + boost::coroutines::coroutine< void >::push_type sink( foo); + sink(); } } #else diff --git a/example/cpp03/unwind.cpp b/example/cpp03/unwind.cpp index 91b7e6c..bda050d 100644 --- a/example/cpp03/unwind.cpp +++ b/example/cpp03/unwind.cpp @@ -17,24 +17,24 @@ struct X : private boost::noncopyable ~X() { std::cout << "~X()" << std::endl; } }; -void fn( boost::coroutines::coroutine< void >::push_type & c) +void fn( boost::coroutines::coroutine< void >::push_type & sink) { X x; int i = 0; while ( true) { std::cout << "fn() : " << ++i << std::endl; - c(); + sink(); } } int main( int argc, char * argv[]) { { - boost::coroutines::coroutine< void >::pull_type c( fn); + boost::coroutines::coroutine< void >::pull_type source( fn); for ( int k = 0; k < 3; ++k) { - c(); + source(); } std::cout << "destroying coroutine and unwinding stack" << std::endl; } diff --git a/example/cpp11/fibonacci.cpp b/example/cpp11/fibonacci.cpp index c6545d7..fc1f1b9 100644 --- a/example/cpp11/fibonacci.cpp +++ b/example/cpp11/fibonacci.cpp @@ -12,21 +12,21 @@ #ifdef BOOST_COROUTINES_UNIDIRECT int main() { - boost::coroutines::coroutine< int >::pull_type c( - [&]( boost::coroutines::coroutine< int >::push_type & c) { + boost::coroutines::coroutine< int >::pull_type source( + [&]( boost::coroutines::coroutine< int >::push_type & sink) { int first = 1, second = 1; - c( first); - c( second); + sink( first); + sink( second); for ( int i = 0; i < 8; ++i) { int third = first + second; first = second; second = third; - c( third); + sink( third); } }); - for ( auto i : c) + for ( auto i : source) std::cout << i << " "; std::cout << "\nDone" << std::endl; diff --git a/include/boost/coroutine/all.hpp b/include/boost/coroutine/all.hpp index d80ca20..e32a420 100644 --- a/include/boost/coroutine/all.hpp +++ b/include/boost/coroutine/all.hpp @@ -9,6 +9,7 @@ #include #include +#include #include #include diff --git a/include/boost/coroutine/exceptions.hpp b/include/boost/coroutine/exceptions.hpp new file mode 100644 index 0000000..f263429 --- /dev/null +++ b/include/boost/coroutine/exceptions.hpp @@ -0,0 +1,105 @@ + +// Copyright Oliver Kowalke 2009. +// 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) + +#ifndef BOOST_COROUTINES_EXCEPTIONS_H +#define BOOST_COROUTINES_EXCEPTIONS_H + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace coroutines { +namespace detail { + +struct forced_unwind {}; + +} + +BOOST_SCOPED_ENUM_DECLARE_BEGIN(coroutine_errc) +{ + no_data = 1 +} +BOOST_SCOPED_ENUM_DECLARE_END(coroutine_errc) + +BOOST_COROUTINES_DECL system::error_category const& coroutine_category() BOOST_NOEXCEPT; + +} + +namespace system { + +template<> +struct is_error_code_enum< coroutines::coroutine_errc > : public true_type +{}; + +#ifdef BOOST_NO_CXX11_SCOPED_ENUMS +template<> +struct is_error_code_enum< coroutines::coroutine_errc::enum_type > : public true_type +{}; +#endif + +inline +error_code make_error_code( coroutines::coroutine_errc e) //BOOST_NOEXCEPT +{ + return error_code( underlying_cast< int >( e), coroutines::coroutine_category() ); +} + +inline +error_condition make_error_condition( coroutines::coroutine_errc e) //BOOST_NOEXCEPT +{ + return error_condition( underlying_cast< int >( e), coroutines::coroutine_category() ); +} + +} + +namespace coroutines { + +class coroutine_error : public std::logic_error +{ +private: + system::error_code ec_; + +public: + coroutine_error( system::error_code ec) : + logic_error( ec.message() ), + ec_( ec) + {} + + system::error_code const& code() const BOOST_NOEXCEPT + { return ec_; } + + const char* what() const throw() + { return code().message().c_str(); } +}; + +class invalid_result : public coroutine_error +{ +public: + invalid_result() : + coroutine_error( + system::make_error_code( + coroutine_errc::no_data) ) + {} +}; + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_COROUTINES_EXCEPTIONS_H diff --git a/include/boost/coroutine/v1/detail/coroutine_base_resume.hpp b/include/boost/coroutine/v1/detail/coroutine_base_resume.hpp index 020f97c..a932edd 100644 --- a/include/boost/coroutine/v1/detail/coroutine_base_resume.hpp +++ b/include/boost/coroutine/v1/detail/coroutine_base_resume.hpp @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include diff --git a/include/boost/coroutine/v1/detail/coroutine_object.hpp b/include/boost/coroutine/v1/detail/coroutine_object.hpp index f6348c2..2f260a3 100644 --- a/include/boost/coroutine/v1/detail/coroutine_object.hpp +++ b/include/boost/coroutine/v1/detail/coroutine_object.hpp @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include #include diff --git a/include/boost/coroutine/v2/coroutine.hpp b/include/boost/coroutine/v2/coroutine.hpp index ed26c2e..f166a19 100644 --- a/include/boost/coroutine/v2/coroutine.hpp +++ b/include/boost/coroutine/v2/coroutine.hpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -26,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -1079,7 +1081,7 @@ public: R get() const { - BOOST_ASSERT( has_result() ); + BOOST_ASSERT( ! empty() ); return impl_->get(); } @@ -1156,17 +1158,27 @@ public: } reference_t operator*() const - { return const_cast< optional< R > & >( val_).get(); } + { + if ( ! val_) + boost::throw_exception( + invalid_result() ); + return const_cast< optional< R > & >( val_).get(); + } pointer_t operator->() const - { return const_cast< optional< R > & >( val_).get_ptr(); } + { + if ( ! val_) + boost::throw_exception( + invalid_result() ); + return const_cast< optional< R > & >( val_).get_ptr(); + } }; class const_iterator : public std::iterator< std::input_iterator_tag, const typename remove_reference< R >::type > { private: pull_coroutine< R > * c_; - optional< R > val_; + optional< R > val_; void fetch_() { @@ -1234,10 +1246,20 @@ public: } reference_t operator*() const - { return val_.get(); } + { + if ( ! val_) + boost::throw_exception( + invalid_result() ); + return val_.get(); + } pointer_t operator->() const - { return val_.get_ptr(); } + { + if ( ! val_) + boost::throw_exception( + invalid_result() ); + return val_.get_ptr(); + } }; }; @@ -1579,11 +1601,7 @@ public: } R & get() const - { - BOOST_ASSERT( has_result() ); - - return impl_->get(); - } + { return impl_->get(); } class iterator : public std::iterator< std::input_iterator_tag, R > { @@ -1657,10 +1675,20 @@ public: } reference_t operator*() const - { return const_cast< optional< R & > & >( val_).get(); } + { + if ( ! val_) + boost::throw_exception( + invalid_result() ); + return const_cast< optional< R & > & >( val_).get(); + } pointer_t operator->() const - { return const_cast< optional< R & > & >( val_).get_ptr(); } + { + if ( ! val_) + boost::throw_exception( + invalid_result() ); + return const_cast< optional< R & > & >( val_).get_ptr(); + } }; class const_iterator : public std::iterator< std::input_iterator_tag, R > @@ -1735,10 +1763,20 @@ public: } reference_t operator*() const - { return val_.get(); } + { + if ( ! val_) + boost::throw_exception( + invalid_result() ); + return val_.get(); + } pointer_t operator->() const - { return val_.get_ptr(); } + { + if ( ! val_) + boost::throw_exception( + invalid_result() ); + return val_.get_ptr(); + } }; }; diff --git a/include/boost/coroutine/v2/detail/pull_coroutine_base.hpp b/include/boost/coroutine/v2/detail/pull_coroutine_base.hpp index b5d049d..74cdc4d 100644 --- a/include/boost/coroutine/v2/detail/pull_coroutine_base.hpp +++ b/include/boost/coroutine/v2/detail/pull_coroutine_base.hpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -21,7 +22,7 @@ #include #include #include -#include +#include #ifdef BOOST_HAS_ABI_HEADERS # include BOOST_ABI_PREFIX @@ -130,8 +131,9 @@ public: R get() const { - BOOST_ASSERT( has_result() ); - + if ( ! has_result() ) + boost::throw_exception( + invalid_result() ); return result_.get(); } }; @@ -232,8 +234,9 @@ public: R & get() const { - BOOST_ASSERT( has_result() ); - + if ( ! has_result() ) + boost::throw_exception( + invalid_result() ); return * result_.get(); } }; diff --git a/include/boost/coroutine/v2/detail/pull_coroutine_object.hpp b/include/boost/coroutine/v2/detail/pull_coroutine_object.hpp index 08d0b76..30affdc 100644 --- a/include/boost/coroutine/v2/detail/pull_coroutine_object.hpp +++ b/include/boost/coroutine/v2/detail/pull_coroutine_object.hpp @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include #include diff --git a/include/boost/coroutine/v2/detail/push_coroutine_base.hpp b/include/boost/coroutine/v2/detail/push_coroutine_base.hpp index 595a167..511da61 100644 --- a/include/boost/coroutine/v2/detail/push_coroutine_base.hpp +++ b/include/boost/coroutine/v2/detail/push_coroutine_base.hpp @@ -17,7 +17,7 @@ #include #include -#include +#include #include #ifdef BOOST_HAS_ABI_HEADERS diff --git a/include/boost/coroutine/v2/detail/push_coroutine_object.hpp b/include/boost/coroutine/v2/detail/push_coroutine_object.hpp index 52a7569..0f840f2 100644 --- a/include/boost/coroutine/v2/detail/push_coroutine_object.hpp +++ b/include/boost/coroutine/v2/detail/push_coroutine_object.hpp @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/exceptions.cpp b/src/exceptions.cpp new file mode 100644 index 0000000..3b7761a --- /dev/null +++ b/src/exceptions.cpp @@ -0,0 +1,36 @@ + +// Copyright Oliver Kowalke 2009. +// 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) + +#include + +namespace boost { +namespace coroutines { + +class coroutine_error_category : public system::error_category +{ +public: + virtual const char* name() const BOOST_NOEXCEPT + { return "coroutine"; } + + virtual std::string message( int ev) const + { + switch (BOOST_SCOPED_ENUM_NATIVE(coroutine_errc)(ev)) + { + case coroutine_errc::no_data: + return std::string("Operation not permitted because coroutine " + "has no valid result."); + } + return std::string("unspecified coroutine_errc value\n"); + } +}; + +system::error_category const& coroutine_category() BOOST_NOEXCEPT +{ + static coroutines::coroutine_error_category cat; + return cat; +} + +}} diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 555c8ce..2c0b497 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -18,6 +18,7 @@ project boost/coroutine/test ../../test/build//boost_unit_test_framework /boost/context//boost_context /boost/coroutine//boost_coroutine + /boost/system//boost_system gcc-4.7,on:-fsplit-stack gcc-4.8,on:-fsplit-stack static diff --git a/test/test_coroutine.cpp b/test/test_coroutine.cpp index 1a82e86..c915866 100644 --- a/test/test_coroutine.cpp +++ b/test/test_coroutine.cpp @@ -197,6 +197,9 @@ void f19( coro::coroutine< const int* >::push_type & c, std::vector< const int * { c( ptr); } } +void f20( coro::coroutine< int >::push_type &) +{} + void test_move() { { @@ -510,6 +513,24 @@ void test_input_iterator() BOOST_CHECK_EQUAL( ( int)3, vec[2] ); BOOST_CHECK_EQUAL( ( int)4, vec[3] ); } + +void test_invalid_result() +{ + bool catched = false; + coro::coroutine< int >::pull_type coro( f20); + BOOST_CHECK( ! coro); + try + { + int i = coro.get(); + } + catch ( coro::invalid_result const& e) + { + boost::system::error_code ec = e.code(); + BOOST_CHECK_EQUAL( coro::coroutine_errc::no_data, ec.value()); + catched = true; + } + BOOST_CHECK( catched); +} #else typedef coro::coroutine< void() > coro_void_void; typedef coro::coroutine< int() > coro_int_void; @@ -1039,6 +1060,8 @@ boost::unit_test::test_suite * init_unit_test_suite( int, char* []) #ifndef BOOST_COROUTINES_UNIDIRECT test->add( BOOST_TEST_CASE( & test_pre) ); test->add( BOOST_TEST_CASE( & test_post) ); +#else + test->add( BOOST_TEST_CASE( & test_invalid_result) ); #endif test->add( BOOST_TEST_CASE( & test_ref) ); test->add( BOOST_TEST_CASE( & test_const_ref) );