123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222 |
- // Copyright Oliver Kowalke 2013.
- // 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_FIBERS_PROMISE_HPP
- #define BOOST_FIBERS_PROMISE_HPP
- #include <algorithm>
- #include <memory>
- #include <utility>
- #include <boost/config.hpp>
- #include <boost/core/pointer_traits.hpp>
- #include <boost/fiber/exceptions.hpp>
- #include <boost/fiber/future/detail/shared_state.hpp>
- #include <boost/fiber/future/detail/shared_state_object.hpp>
- #include <boost/fiber/future/future.hpp>
- namespace boost {
- namespace fibers {
- namespace detail {
- template< typename R >
- struct promise_base {
- typedef typename shared_state< R >::ptr_type ptr_type;
- bool obtained_{ false };
- ptr_type future_{};
- promise_base() :
- promise_base{ std::allocator_arg, std::allocator< promise_base >{} } {
- }
- template< typename Allocator >
- promise_base( std::allocator_arg_t, Allocator alloc) {
- typedef detail::shared_state_object< R, Allocator > object_type;
- typedef std::allocator_traits< typename object_type::allocator_type > traits_type;
- typedef pointer_traits< typename traits_type::pointer > ptrait_type;
- typename object_type::allocator_type a{ alloc };
- typename traits_type::pointer ptr{ traits_type::allocate( a, 1) };
- typename ptrait_type::element_type* p = boost::to_address(ptr);
- try {
- traits_type::construct( a, p, a);
- } catch (...) {
- traits_type::deallocate( a, ptr, 1);
- throw;
- }
- future_.reset(p);
- }
- ~promise_base() {
- if ( future_ && obtained_) {
- future_->owner_destroyed();
- }
- }
- promise_base( promise_base const&) = delete;
- promise_base & operator=( promise_base const&) = delete;
- promise_base( promise_base && other) noexcept :
- obtained_{ other.obtained_ },
- future_{ std::move( other.future_) } {
- other.obtained_ = false;
- }
- promise_base & operator=( promise_base && other) noexcept {
- if ( BOOST_LIKELY( this != & other) ) {
- promise_base tmp{ std::move( other) };
- swap( tmp);
- }
- return * this;
- }
- future< R > get_future() {
- if ( BOOST_UNLIKELY( obtained_) ) {
- throw future_already_retrieved{};
- }
- if ( BOOST_UNLIKELY( ! future_) ) {
- throw promise_uninitialized{};
- }
- obtained_ = true;
- return future< R >{ future_ };
- }
- void swap( promise_base & other) noexcept {
- std::swap( obtained_, other.obtained_);
- future_.swap( other.future_);
- }
- void set_exception( std::exception_ptr p) {
- if ( BOOST_UNLIKELY( ! future_) ) {
- throw promise_uninitialized{};
- }
- future_->set_exception( p);
- }
- };
- }
- template< typename R >
- class promise : private detail::promise_base< R > {
- private:
- typedef detail::promise_base< R > base_type;
- public:
- promise() = default;
- template< typename Allocator >
- promise( std::allocator_arg_t, Allocator alloc) :
- base_type{ std::allocator_arg, alloc } {
- }
- promise( promise const&) = delete;
- promise & operator=( promise const&) = delete;
- promise( promise && other) noexcept = default;
- promise & operator=( promise && other) = default;
- void set_value( R const& value) {
- if ( BOOST_UNLIKELY( ! base_type::future_) ) {
- throw promise_uninitialized{};
- }
- base_type::future_->set_value( value);
- }
- void set_value( R && value) {
- if ( BOOST_UNLIKELY( ! base_type::future_) ) {
- throw promise_uninitialized{};
- }
- base_type::future_->set_value( std::move( value) );
- }
- void swap( promise & other) noexcept {
- base_type::swap( other);
- }
- using base_type::get_future;
- using base_type::set_exception;
- };
- template< typename R >
- class promise< R & > : private detail::promise_base< R & > {
- private:
- typedef detail::promise_base< R & > base_type;
- public:
- promise() = default;
- template< typename Allocator >
- promise( std::allocator_arg_t, Allocator alloc) :
- base_type{ std::allocator_arg, alloc } {
- }
- promise( promise const&) = delete;
- promise & operator=( promise const&) = delete;
- promise( promise && other) noexcept = default;
- promise & operator=( promise && other) noexcept = default;
- void set_value( R & value) {
- if ( BOOST_UNLIKELY( ! base_type::future_) ) {
- throw promise_uninitialized{};
- }
- base_type::future_->set_value( value);
- }
- void swap( promise & other) noexcept {
- base_type::swap( other);
- }
- using base_type::get_future;
- using base_type::set_exception;
- };
- template<>
- class promise< void > : private detail::promise_base< void > {
- private:
- typedef detail::promise_base< void > base_type;
- public:
- promise() = default;
- template< typename Allocator >
- promise( std::allocator_arg_t, Allocator alloc) :
- base_type{ std::allocator_arg, alloc } {
- }
- promise( promise const&) = delete;
- promise & operator=( promise const&) = delete;
- promise( promise && other) noexcept = default;
- promise & operator=( promise && other) noexcept = default;
- inline
- void set_value() {
- if ( BOOST_UNLIKELY( ! base_type::future_) ) {
- throw promise_uninitialized{};
- }
- base_type::future_->set_value();
- }
- inline
- void swap( promise & other) noexcept {
- base_type::swap( other);
- }
- using base_type::get_future;
- using base_type::set_exception;
- };
- template< typename R >
- void swap( promise< R > & l, promise< R > & r) noexcept {
- l.swap( r);
- }
- }}
- #endif // BOOST_FIBERS_PROMISE_HPP
|