From abbc507d13e7cac7a9439db75e7f4cd52842bbc6 Mon Sep 17 00:00:00 2001 From: Oliver Kowalke Date: Wed, 2 Dec 2015 17:20:08 +0100 Subject: [PATCH] re-factor futures --- include/boost/fiber/context.hpp | 2 +- include/boost/fiber/future/async.hpp | 16 +- .../fiber/future/detail/shared_state.hpp | 426 ++++----------- .../future/detail/shared_state_object.hpp | 4 +- .../boost/fiber/future/detail/task_object.hpp | 12 +- include/boost/fiber/future/future.hpp | 512 +++++++----------- include/boost/fiber/future/packaged_task.hpp | 55 +- include/boost/fiber/future/promise.hpp | 148 +++-- src/context.cpp | 2 +- 9 files changed, 417 insertions(+), 760 deletions(-) diff --git a/include/boost/fiber/context.hpp b/include/boost/fiber/context.hpp index 870f600f..3c14d768 100644 --- a/include/boost/fiber/context.hpp +++ b/include/boost/fiber/context.hpp @@ -427,7 +427,7 @@ public: }; struct context_initializer { - context_initializer() noexcept; + context_initializer(); ~context_initializer() noexcept; }; diff --git a/include/boost/fiber/future/async.hpp b/include/boost/fiber/future/async.hpp index b89fc4b3..e7087f33 100644 --- a/include/boost/fiber/future/async.hpp +++ b/include/boost/fiber/future/async.hpp @@ -25,10 +25,10 @@ future< typename std::result_of< Fn( Args ... ) >::type > async( Fn && fn, Args && ... args) { typedef typename std::result_of< Fn( Args ... ) >::type result_type; - packaged_task< result_type( typename std::decay< Args >::type ... ) > pt( - std::forward< Fn >( fn) ); - future< result_type > f( pt.get_future() ); - fiber( std::move( pt), std::forward< Args >( args) ... ).detach(); + packaged_task< result_type( typename std::decay< Args >::type ... ) > pt{ + std::forward< Fn >( fn) }; + future< result_type > f{ pt.get_future() }; + fiber{ std::move( pt), std::forward< Args >( args) ... }.detach(); return f; } @@ -37,10 +37,10 @@ future< typename std::result_of< Fn( Args ... ) >::type > async( std::allocator_arg_t, StackAllocator salloc, Fn && fn, Args && ... args) { typedef typename std::result_of< Fn( Args ... ) >::type result_type; - packaged_task< result_type( typename std::decay< Args >::type ... ) > pt( - std::forward< Fn >( fn) ); - future< result_type > f( pt.get_future() ); - fiber( salloc, std::move( pt), std::forward< Args >( args) ... ).detach(); + packaged_task< result_type( typename std::decay< Args >::type ... ) > pt{ + std::forward< Fn >( fn) }; + future< result_type > f{ pt.get_future() }; + fiber{ salloc, std::move( pt), std::forward< Args >( args) ... }.detach(); return f; } diff --git a/include/boost/fiber/future/detail/shared_state.hpp b/include/boost/fiber/future/detail/shared_state.hpp index 87020b5c..f52eba28 100644 --- a/include/boost/fiber/future/detail/shared_state.hpp +++ b/include/boost/fiber/future/detail/shared_state.hpp @@ -34,17 +34,17 @@ namespace boost { namespace fibers { namespace detail { -template< typename R > -class shared_state { +class shared_state_base { private: - std::atomic< std::size_t > use_count_{ 0 }; - mutable mutex mtx_{}; - mutable condition waiters_{}; - bool ready_{ false }; - typename std::aligned_storage< sizeof( R), alignof( R) >::type storage_[1]{}; - std::exception_ptr except_{}; + std::atomic< std::size_t > use_count_{ 0 }; + mutable condition waiters_{}; - void mark_ready_and_notify_( std::unique_lock< mutex > & lk) { +protected: + mutable mutex mtx_{}; + bool ready_{ false }; + std::exception_ptr except_{}; + + void mark_ready_and_notify_( std::unique_lock< mutex > & lk) noexcept { ready_ = true; lk.unlock(); waiters_.notify_all(); @@ -58,6 +58,103 @@ private: } } + void set_exception_( std::exception_ptr except, std::unique_lock< mutex > & lk) { + if ( ready_) { + throw promise_already_satisfied(); + } + except_ = except; + mark_ready_and_notify_( lk); + } + + std::exception_ptr get_exception_ptr_( std::unique_lock< mutex > & lk) { + wait_( lk); + return except_; + } + + void wait_( std::unique_lock< mutex > & lk) const { + waiters_.wait( lk, [this](){ return ready_; }); + } + + template< class Rep, class Period > + future_status wait_for_( std::unique_lock< mutex > & lk, + std::chrono::duration< Rep, Period > const& timeout_duration) const { + return waiters_.wait_for( lk, timeout_duration, [this](){ return ready_; }) + ? future_status::ready + : future_status::timeout; + } + + template< typename Clock, typename Duration > + future_status wait_until_( std::unique_lock< mutex > & lk, + std::chrono::time_point< Clock, Duration > const& timeout_time) const { + return waiters_.wait_until( lk, timeout_time, [this](){ return ready_; }) + ? future_status::ready + : future_status::timeout; + } + + virtual void deallocate_future() noexcept = 0; + +public: + shared_state_base() = default; + + virtual ~shared_state_base() noexcept = default; + + shared_state_base( shared_state_base const&) = delete; + shared_state_base & operator=( shared_state_base const&) = delete; + + void owner_destroyed() { + std::unique_lock< mutex > lk( mtx_); + owner_destroyed_( lk); + } + + void set_exception( std::exception_ptr except) { + std::unique_lock< mutex > lk( mtx_); + set_exception_( except, lk); + } + + std::exception_ptr get_exception_ptr() { + std::unique_lock< mutex > lk( mtx_); + return get_exception_ptr_( lk); + } + + void wait() const { + std::unique_lock< mutex > lk( mtx_); + wait_( lk); + } + + template< class Rep, class Period > + future_status wait_for( std::chrono::duration< Rep, Period > const& timeout_duration) const { + std::unique_lock< mutex > lk( mtx_); + return wait_for_( lk, timeout_duration); + } + + template< typename Clock, typename Duration > + future_status wait_until( std::chrono::time_point< Clock, Duration > const& timeout_time) const { + std::unique_lock< mutex > lk( mtx_); + return wait_until_( lk, timeout_time); + } + + void reset() noexcept { + ready_ = false; + } + + friend inline + void intrusive_ptr_add_ref( shared_state_base * p) noexcept { + ++p->use_count_; + } + + friend inline + void intrusive_ptr_release( shared_state_base * p) noexcept { + if ( 0 == --p->use_count_) { + p->deallocate_future(); + } + } +}; + +template< typename R > +class shared_state : public shared_state_base { +private: + typename std::aligned_storage< sizeof( R), alignof( R) >::type storage_[1]{}; + void set_value_( R const& value, std::unique_lock< mutex > & lk) { if ( ready_) { throw promise_already_satisfied(); @@ -74,14 +171,6 @@ private: mark_ready_and_notify_( lk); } - void set_exception_( std::exception_ptr except, std::unique_lock< mutex > & lk) { - if ( ready_) { - throw promise_already_satisfied(); - } - except_ = except; - mark_ready_and_notify_( lk); - } - R & get_( std::unique_lock< mutex > & lk) { wait_( lk); if ( except_) { @@ -90,34 +179,6 @@ private: return * reinterpret_cast< R * >( storage_); } - std::exception_ptr get_exception_ptr_( std::unique_lock< mutex > & lk) { - wait_( lk); - return except_; - } - - void wait_( std::unique_lock< mutex > & lk) const { - waiters_.wait( lk, [this](){ return ready_; }); - } - - template< class Rep, class Period > - future_status wait_for_( std::unique_lock< mutex > & lk, - std::chrono::duration< Rep, Period > const& timeout_duration) const { - return waiters_.wait_for( lk, timeout_duration, [this](){ return ready_; }) - ? future_status::ready - : future_status::timeout; - } - - template< typename Clock, typename Duration > - future_status wait_until_( std::unique_lock< mutex > & lk, - std::chrono::time_point< Clock, Duration > const& timeout_time) const { - return waiters_.wait_until( lk, timeout_time, [this](){ return ready_; }) - ? future_status::ready - : future_status::timeout; - } - -protected: - virtual void deallocate_future() = 0; - public: typedef intrusive_ptr< shared_state > ptr_t; @@ -132,11 +193,6 @@ public: shared_state( shared_state const&) = delete; shared_state & operator=( shared_state const&) = delete; - void owner_destroyed() { - std::unique_lock< mutex > lk( mtx_); - owner_destroyed_( lk); - } - void set_value( R const& value) { std::unique_lock< mutex > lk( mtx_); set_value_( value, lk); @@ -147,78 +203,16 @@ public: set_value_( std::move( value), lk); } - void set_exception( std::exception_ptr except) { - std::unique_lock< mutex > lk( mtx_); - set_exception_( except, lk); - } - R & get() { std::unique_lock< mutex > lk( mtx_); return get_( lk); } - - std::exception_ptr get_exception_ptr() { - std::unique_lock< mutex > lk( mtx_); - return get_exception_ptr_( lk); - } - - void wait() const { - std::unique_lock< mutex > lk( mtx_); - wait_( lk); - } - - template< class Rep, class Period > - future_status wait_for( std::chrono::duration< Rep, Period > const& timeout_duration) const { - std::unique_lock< mutex > lk( mtx_); - return wait_for_( lk, timeout_duration); - } - - template< typename Clock, typename Duration > - future_status wait_until( std::chrono::time_point< Clock, Duration > const& timeout_time) const { - std::unique_lock< mutex > lk( mtx_); - return wait_until_( lk, timeout_time); - } - - void reset() { - ready_ = false; - } - - friend inline - void intrusive_ptr_add_ref( shared_state * p) noexcept { - ++p->use_count_; - } - - friend inline - void intrusive_ptr_release( shared_state * p) { - if ( 0 == --p->use_count_) { - p->deallocate_future(); - } - } }; template< typename R > -class shared_state< R & > { +class shared_state< R & > : public shared_state_base { private: - std::atomic< std::size_t > use_count_{ 0 }; - mutable mutex mtx_{}; - mutable condition waiters_{}; - bool ready_{ false }; R * value_{ nullptr }; - std::exception_ptr except_{}; - - void mark_ready_and_notify_( std::unique_lock< mutex > & lk) { - ready_ = true; - lk.unlock(); - waiters_.notify_all(); - } - - void owner_destroyed_( std::unique_lock< mutex > & lk) { - if ( ! ready_) { - set_exception_( - std::make_exception_ptr( broken_promise() ), - lk); - } - } void set_value_( R & value, std::unique_lock< mutex > & lk) { if ( ready_) { @@ -228,14 +222,6 @@ private: mark_ready_and_notify_( lk); } - void set_exception_( std::exception_ptr except, std::unique_lock< mutex > & lk) { - if ( ready_) { - throw promise_already_satisfied(); - } - except_ = except; - mark_ready_and_notify_( lk); - } - R & get_( std::unique_lock< mutex > & lk) { wait_( lk); if ( except_) { @@ -244,129 +230,30 @@ private: return * value_; } - std::exception_ptr get_exception_ptr_( std::unique_lock< mutex > & lk) { - wait_( lk); - return except_; - } - - void wait_( std::unique_lock< mutex > & lk) const { - waiters_.wait( lk, [this](){ return ready_; }); - } - - template< class Rep, class Period > - future_status wait_for_( std::unique_lock< mutex > & lk, - std::chrono::duration< Rep, Period > const& timeout_duration) const { - return waiters_.wait_for( lk, timeout_duration, [this](){ return ready_; }) - ? future_status::ready - : future_status::timeout; - } - - template< typename Clock, typename Duration > - future_status wait_until_( std::unique_lock< mutex > & lk, - std::chrono::time_point< Clock, Duration > const& timeout_time) const { - return waiters_.wait_until( lk, timeout_time, [this](){ return ready_; }) - ? future_status::ready - : future_status::timeout; - } - -protected: - virtual void deallocate_future() = 0; - public: typedef intrusive_ptr< shared_state > ptr_t; shared_state() = default; - virtual ~shared_state() noexcept { - } + virtual ~shared_state() noexcept = default; shared_state( shared_state const&) = delete; shared_state & operator=( shared_state const&) = delete; - void owner_destroyed() { - std::unique_lock< mutex > lk( mtx_); - owner_destroyed_( lk); - } - void set_value( R & value) { std::unique_lock< mutex > lk( mtx_); set_value_( value, lk); } - void set_exception( std::exception_ptr except) { - std::unique_lock< mutex > lk( mtx_); - set_exception_( except, lk); - } - R & get() { std::unique_lock< mutex > lk( mtx_); return get_( lk); } - - std::exception_ptr get_exception_ptr() { - std::unique_lock< mutex > lk( mtx_); - return get_exception_ptr_( lk); - } - - void wait() const { - std::unique_lock< mutex > lk( mtx_); - wait_( lk); - } - - template< class Rep, class Period > - future_status wait_for( std::chrono::duration< Rep, Period > const& timeout_duration) const { - std::unique_lock< mutex > lk( mtx_); - return wait_for_( lk, timeout_duration); - } - - template< typename Clock, typename Duration > - future_status wait_until( std::chrono::time_point< Clock, Duration > const& timeout_time) const { - std::unique_lock< mutex > lk( mtx_); - return wait_until_( lk, timeout_time); - } - - void reset() { - ready_ = false; - } - - friend inline - void intrusive_ptr_add_ref( shared_state * p) noexcept { - ++p->use_count_; - } - - friend inline - void intrusive_ptr_release( shared_state * p) { - if ( 0 == --p->use_count_) { - p->deallocate_future(); - } - } }; template<> -class shared_state< void > { +class shared_state< void > : public shared_state_base { private: - std::atomic< std::size_t > use_count_{ 0 }; - mutable mutex mtx_{}; - mutable condition waiters_{}; - bool ready_{ false }; - std::exception_ptr except_{}; - - inline - void mark_ready_and_notify_( std::unique_lock< mutex > & lk) { - ready_ = true; - lk.unlock(); - waiters_.notify_all(); - } - - inline - void owner_destroyed_( std::unique_lock< mutex > & lk) { - if ( ! ready_) { - set_exception_( - std::make_exception_ptr( broken_promise() ), - lk); - } - } - inline void set_value_( std::unique_lock< mutex > & lk) { if ( ready_) { @@ -375,15 +262,6 @@ private: mark_ready_and_notify_( lk); } - inline - void set_exception_( std::exception_ptr except, std::unique_lock< mutex > & lk) { - if ( ready_) { - throw promise_already_satisfied(); - } - except_ = except; - mark_ready_and_notify_( lk); - } - inline void get_( std::unique_lock< mutex > & lk) { wait_( lk); @@ -392,111 +270,27 @@ private: } } - inline - std::exception_ptr get_exception_ptr_( std::unique_lock< mutex > & lk) { - wait_( lk); - return except_; - } - - inline - void wait_( std::unique_lock< mutex > & lk) const { - waiters_.wait( lk, [this](){ return ready_; }); - } - - template< class Rep, class Period > - future_status wait_for_( std::unique_lock< mutex > & lk, - std::chrono::duration< Rep, Period > const& timeout_duration) const { - return waiters_.wait_for( lk, timeout_duration, [this](){ return ready_; }) - ? future_status::ready - : future_status::timeout; - } - - template< typename Clock, typename Duration > - future_status wait_until_( std::unique_lock< mutex > & lk, - std::chrono::time_point< Clock, Duration > const& timeout_time) const { - return waiters_.wait_until( lk, timeout_time, [this](){ return ready_; }) - ? future_status::ready - : future_status::timeout; - } - -protected: - virtual void deallocate_future() = 0; - public: typedef intrusive_ptr< shared_state > ptr_t; shared_state() = default; - virtual ~shared_state() noexcept { - } + virtual ~shared_state() noexcept = default; shared_state( shared_state const&) = delete; shared_state & operator=( shared_state const&) = delete; - inline - void owner_destroyed() { - std::unique_lock< mutex > lk( mtx_); - owner_destroyed_( lk); - } - inline void set_value() { std::unique_lock< mutex > lk( mtx_); set_value_( lk); } - inline - void set_exception( std::exception_ptr except) { - std::unique_lock< mutex > lk( mtx_); - set_exception_( except, lk); - } - inline void get() { std::unique_lock< mutex > lk( mtx_); get_( lk); } - - inline - std::exception_ptr get_exception_ptr() { - std::unique_lock< mutex > lk( mtx_); - return get_exception_ptr_( lk); - } - - inline - void wait() const { - std::unique_lock< mutex > lk( mtx_); - wait_( lk); - } - - template< class Rep, class Period > - future_status wait_for( std::chrono::duration< Rep, Period > const& timeout_duration) const { - std::unique_lock< mutex > lk( mtx_); - return wait_for_( lk, timeout_duration); - } - - template< typename Clock, typename Duration > - future_status wait_until( std::chrono::time_point< Clock, Duration > const& timeout_time) const { - std::unique_lock< mutex > lk( mtx_); - return wait_until_( lk, timeout_time); - } - - inline - void reset() { - ready_ = false; - } - - friend inline - void intrusive_ptr_add_ref( shared_state * p) noexcept { - ++p->use_count_; - } - - friend inline - void intrusive_ptr_release( shared_state * p) { - if ( 0 == --p->use_count_) { - p->deallocate_future(); - } - } }; }}} diff --git a/include/boost/fiber/future/detail/shared_state_object.hpp b/include/boost/fiber/future/detail/shared_state_object.hpp index 8def4ed7..f869bbd8 100644 --- a/include/boost/fiber/future/detail/shared_state_object.hpp +++ b/include/boost/fiber/future/detail/shared_state_object.hpp @@ -32,14 +32,14 @@ public: } protected: - void deallocate_future() { + void deallocate_future() noexcept override final { destroy_( alloc_, this); } private: allocator_t alloc_; - static void destroy_( allocator_t & alloc, shared_state_object * p) { + static void destroy_( allocator_t & alloc, shared_state_object * p) noexcept { alloc.destroy( p); alloc.deallocate( p, 1); } diff --git a/include/boost/fiber/future/detail/task_object.hpp b/include/boost/fiber/future/detail/task_object.hpp index 21d8d435..0e906e87 100644 --- a/include/boost/fiber/future/detail/task_object.hpp +++ b/include/boost/fiber/future/detail/task_object.hpp @@ -37,7 +37,7 @@ public: alloc_( alloc) { } - void run( Args && ... args) { + void run( Args && ... args) override final { try { this->set_value( boost::context::detail::do_invoke( @@ -48,7 +48,7 @@ public: } protected: - void deallocate_future() { + void deallocate_future() noexcept override final { destroy_( alloc_, this); } @@ -56,7 +56,7 @@ private: Fn fn_; allocator_t alloc_; - static void destroy_( allocator_t & alloc, task_object * p) { + static void destroy_( allocator_t & alloc, task_object * p) noexcept { alloc.destroy( p); alloc.deallocate( p, 1); } @@ -75,7 +75,7 @@ public: alloc_( alloc) { } - void run( Args && ... args) { + void run( Args && ... args) override final { try { boost::context::detail::do_invoke( fn_, std::make_tuple( std::forward< Args >( args) ... ) ); @@ -86,7 +86,7 @@ public: } protected: - void deallocate_future() { + void deallocate_future() noexcept override final { destroy_( alloc_, this); } @@ -94,7 +94,7 @@ private: Fn fn_; allocator_t alloc_; - static void destroy_( allocator_t & alloc, task_object * p) { + static void destroy_( allocator_t & alloc, task_object * p) noexcept { alloc.destroy( p); alloc.deallocate( p, 1); } diff --git a/include/boost/fiber/future/future.hpp b/include/boost/fiber/future/future.hpp index d07f8ed0..dafaadc3 100644 --- a/include/boost/fiber/future/future.hpp +++ b/include/boost/fiber/future/future.hpp @@ -20,556 +20,446 @@ namespace boost { namespace fibers { +namespace detail { template< typename R > -class packaged_task; +struct future_base { + typedef typename shared_state< R >::ptr_t ptr_t; -template< typename R > -class promise; + ptr_t state_{}; + + constexpr future_base() noexcept = default; + + explicit future_base( ptr_t const& p) noexcept : + state_{ p } { + } + + ~future_base() noexcept = default; + + future_base( future_base const& other) : + state_{ other.state_ } { + } + + future_base( future_base && other) noexcept : + state_{ other.state_ } { + other.state_.reset(); + } + + future_base & operator=( future_base const& other) noexcept { + if ( this == & other) return * this; + state_ = other.state_; + return * this; + } + + future_base & operator=( future_base && other) noexcept { + if ( this == & other) return * this; + state_ = other.state_; + other.state_.reset(); + return * this; + } + + bool valid() const noexcept { + return nullptr != state_.get(); + } + + std::exception_ptr get_exception_ptr() { + if ( ! valid() ) { + throw future_uninitialized{}; + } + return state_->get_exception_ptr(); + } + + void wait() const { + if ( ! valid() ) { + throw future_uninitialized{}; + } + state_->wait(); + } + + template< class Rep, class Period > + future_status wait_for( std::chrono::duration< Rep, Period > const& timeout_duration) const { + if ( ! valid() ) { + throw future_uninitialized{}; + } + return state_->wait_for( timeout_duration); + } + + template< typename Clock, typename Duration > + future_status wait_until( std::chrono::time_point< Clock, Duration > const& timeout_time) const { + if ( ! valid() ) { + throw future_uninitialized{}; + } + return state_->wait_until( timeout_time); + } +}; + +} template< typename R > class shared_future; template< typename R > -class future { +class future : private detail::future_base< R > { private: - typedef typename detail::shared_state< R >::ptr_t ptr_t; + typedef detail::future_base< R > base_t; friend class shared_future< R >; - ptr_t state_; - public: - future() noexcept : - state_() { - } + constexpr future() noexcept = default; - explicit future( ptr_t const& p) noexcept : - state_( p) { - } - - ~future() noexcept { + explicit future( typename base_t::ptr_t const& p) noexcept : + base_t{ p } { } future( future const&) = delete; future & operator=( future const&) = delete; - future( future< R > && other) noexcept : - state_( std::move( other.state_) ) { + future( future && other) noexcept : + base_t{ std::forward< future >( other) } { } - future & operator=( future< R > && other) noexcept { - if ( this != & other) { - state_ = std::move( other.state_); - } + future & operator=( future && other) noexcept { + if ( this == & other) return * this; + base_t::operator=( std::forward< future >( other) ); return * this; } - bool valid() const noexcept { - return nullptr != state_.get(); - } - shared_future< R > share(); R get() { - if ( ! valid() ) { - throw future_uninitialized(); + if ( ! base_t::valid() ) { + throw future_uninitialized{}; } - ptr_t tmp; - tmp.swap( state_); + typename base_t::ptr_t tmp{}; + tmp.swap( base_t::state_); return std::move( tmp->get() ); } - std::exception_ptr get_exception_ptr() { - if ( ! valid() ) { - throw future_uninitialized(); - } - return state_->get_exception_ptr(); - } - - void wait() const { - if ( ! valid() ) { - throw future_uninitialized(); - } - state_->wait(); - } + using base_t::valid; + using base_t::get_exception_ptr; + using base_t::wait; template< class Rep, class Period > future_status wait_for( std::chrono::duration< Rep, Period > const& timeout_duration) const { - if ( ! valid() ) { - throw future_uninitialized(); - } - return state_->wait_for( timeout_duration); + return base_t::wait_for( timeout_duration); } template< typename Clock, typename Duration > future_status wait_until( std::chrono::time_point< Clock, Duration > const& timeout_time) const { - if ( ! valid() ) { - throw future_uninitialized(); - } - return state_->wait_until( timeout_time); + return base_t::wait_until( timeout_time); } }; template< typename R > -class future< R & > { +class future< R & > : private detail::future_base< R & > { private: - typedef typename detail::shared_state< R & >::ptr_t ptr_t; + typedef detail::future_base< R & > base_t; friend class shared_future< R & >; - ptr_t state_; - public: - future() noexcept : - state_() { - } + constexpr future() noexcept = default; - explicit future( ptr_t const& p) noexcept : - state_( p) { - } - - ~future() noexcept { + explicit future( typename base_t::ptr_t const& p) noexcept : + base_t{ p } { } future( future const&) = delete; future & operator=( future const&) = delete; - future( future< R & > && other) noexcept : - state_( std::move( other.state_) ) { + future( future && other) noexcept : + base_t{ std::forward< future >( other) } { } - future & operator=( future< R & > && other) noexcept { - if ( this != & other) { - state_ = std::move( other.state_); - } + future & operator=( future && other) noexcept { + if ( this == & other) return * this; + base_t::operator=( std::forward< future >( other) ); return * this; } - bool valid() const noexcept { - return nullptr != state_.get(); - } - shared_future< R & > share(); R & get() { - if ( ! valid() ) { - throw future_uninitialized(); + if ( ! base_t::valid() ) { + throw future_uninitialized{}; } - ptr_t tmp; - tmp.swap( state_); + typename base_t::ptr_t tmp{}; + tmp.swap( base_t::state_); return tmp->get(); } - std::exception_ptr get_exception_ptr() { - if ( ! valid() ) { - throw future_uninitialized(); - } - return state_->get_exception_ptr(); - } - - void wait() const { - if ( ! valid() ) { - throw future_uninitialized(); - } - state_->wait(); - } + using base_t::valid; + using base_t::get_exception_ptr; + using base_t::wait; template< class Rep, class Period > future_status wait_for( std::chrono::duration< Rep, Period > const& timeout_duration) const { - if ( ! valid() ) { - throw future_uninitialized(); - } - return state_->wait_for( timeout_duration); + return base_t::wait_for( timeout_duration); } template< typename Clock, typename Duration > future_status wait_until( std::chrono::time_point< Clock, Duration > const& timeout_time) const { - if ( ! valid() ) { - throw future_uninitialized(); - } - return state_->wait_until( timeout_time); + return base_t::wait_until( timeout_time); } }; template<> -class future< void > { +class future< void > : private detail::future_base< void > { private: - typedef detail::shared_state< void >::ptr_t ptr_t; + typedef detail::future_base< void > base_t; friend class shared_future< void >; - ptr_t state_; - public: - future() noexcept : - state_() { - } + constexpr future() noexcept = default; - explicit future( ptr_t const& p) noexcept : - state_( p) { - } - - ~future() noexcept { + explicit future( base_t::ptr_t const& p) noexcept : + base_t{ p } { } future( future const&) = delete; future & operator=( future const&) = delete; inline - future( future< void > && other) noexcept : - state_( std::move( other.state_) ) { + future( future && other) noexcept : + base_t{ std::forward< future >( other) } { } inline - future & operator=( future< void > && other) noexcept { - if ( this != & other) { - state_ = std::move( other.state_); - } + future & operator=( future && other) noexcept { + if ( this == & other) return * this; + base_t::operator=( std::forward< future >( other) ); return * this; } - inline - bool valid() const noexcept { - return nullptr != state_.get(); - } - shared_future< void > share(); inline void get() { - if ( ! valid() ) { - throw future_uninitialized(); + if ( ! base_t::valid() ) { + throw future_uninitialized{}; } - ptr_t tmp; - tmp.swap( state_); + base_t::ptr_t tmp{}; + tmp.swap( base_t::state_); tmp->get(); } - inline - std::exception_ptr get_exception_ptr() { - if ( ! valid() ) { - throw future_uninitialized(); - } - return state_->get_exception_ptr(); - } - - inline - void wait() const { - if ( ! valid() ) { - throw future_uninitialized(); - } - state_->wait(); - } + using base_t::valid; + using base_t::get_exception_ptr; + using base_t::wait; template< class Rep, class Period > future_status wait_for( std::chrono::duration< Rep, Period > const& timeout_duration) const { - if ( ! valid() ) { - throw future_uninitialized(); - } - return state_->wait_for( timeout_duration); + return base_t::wait_for( timeout_duration); } template< typename Clock, typename Duration > future_status wait_until( std::chrono::time_point< Clock, Duration > const& timeout_time) const { - if ( ! valid() ) { - throw future_uninitialized(); - } - return state_->wait_until( timeout_time); + return base_t::wait_until( timeout_time); } }; template< typename R > -class shared_future { +class shared_future : private detail::future_base< R > { private: - typedef typename detail::shared_state< R >::ptr_t ptr_t; + typedef detail::future_base< R > base_t; - friend class future< R >; - - ptr_t state_; - - explicit shared_future( ptr_t const& p) noexcept : - state_( p) { + explicit shared_future( typename base_t::ptr_t const& p) noexcept : + base_t{ p } { } public: - shared_future() noexcept : - state_() { - } + constexpr shared_future() noexcept = default; - ~shared_future() noexcept { - } + ~shared_future() noexcept = default; shared_future( shared_future const& other) : - state_( other.state_) { + base_t{ other } { } shared_future( shared_future && other) noexcept : - state_( std::move( other.state_) ) { + base_t{ std::forward< shared_future >( other) } { } shared_future( future< R > && other) noexcept : - state_( std::move( other.state_) ) { + base_t{ std::forward< future< R > >( other) } { } shared_future & operator=( shared_future const& other) noexcept { - if ( this != & other) { - state_ = other.state_; - } + if ( this == & other) return * this; + base_t::operator=( other); return * this; } shared_future & operator=( shared_future && other) noexcept { - if ( this != & other) { - state_= std::move( other.state_); - } + if ( this == & other) return * this; + base_t::operator=( std::forward< shared_future >( other) ); return * this; } shared_future & operator=( future< R > && other) noexcept { - state_ = std::move( other.state_); + base_t::operator=( std::forward< future< R > >( other) ); return * this; } - bool valid() const noexcept { - return nullptr != state_.get(); - } - R const& get() const { if ( ! valid() ) { - throw future_uninitialized(); + throw future_uninitialized{}; } - return state_->get(); + return base_t::state_->get(); } - std::exception_ptr get_exception_ptr() { - if ( ! valid() ) { - throw future_uninitialized(); - } - return state_->get_exception_ptr(); - } - - void wait() const { - if ( ! valid() ) { - throw future_uninitialized(); - } - state_->wait(); - } + using base_t::valid; + using base_t::get_exception_ptr; + using base_t::wait; template< class Rep, class Period > future_status wait_for( std::chrono::duration< Rep, Period > const& timeout_duration) const { - if ( ! valid() ) { - throw future_uninitialized(); - } - return state_->wait_for( timeout_duration); + return base_t::wait_for( timeout_duration); } template< typename Clock, typename Duration > future_status wait_until( std::chrono::time_point< Clock, Duration > const& timeout_time) const { - if ( ! valid() ) { - throw future_uninitialized(); - } - return state_->wait_until( timeout_time); + return base_t::wait_until( timeout_time); } }; template< typename R > -class shared_future< R & > { +class shared_future< R & > : private detail::future_base< R & > { private: - typedef typename detail::shared_state< R & >::ptr_t ptr_t; + typedef detail::future_base< R & > base_t; - friend class future< R & >; - - ptr_t state_; - - explicit shared_future( ptr_t const& p) noexcept : - state_( p) { + explicit shared_future( typename base_t::ptr_t const& p) noexcept : + base_t{ p } { } public: - shared_future() noexcept : - state_() { - } + constexpr shared_future() noexcept = default; - ~shared_future() noexcept { - } + ~shared_future() noexcept = default; shared_future( shared_future const& other) : - state_( other.state_) { + base_t{ other } { } shared_future( shared_future && other) noexcept : - state_( std::move( other.state_) ) { + base_t{ std::forward< shared_future >( other) } { } shared_future( future< R & > && other) noexcept : - state_( std::move( other.state_) ) { + base_t{ std::forward< future< R & > >( other) } { } shared_future & operator=( shared_future const& other) noexcept { - if ( this != & other) { - state_ = other.state_; - } + if ( this == & other) return * this; + base_t::operator=( other); return * this; } shared_future & operator=( shared_future && other) noexcept { - if ( this != & other) { - state_ = std::move( other.state_); - } + if ( this == & other) return * this; + base_t::operator=( std::forward< shared_future >( other) ); return * this; } shared_future & operator=( future< R & > && other) noexcept { - state_ = std::move( other.state_); + base_t::operator=( std::forward< future< R & > >( other) ); return * this; } - bool valid() const noexcept { - return nullptr != state_.get(); - } - R & get() const { if ( ! valid() ) { - throw future_uninitialized(); + throw future_uninitialized{}; } - return state_->get(); + return base_t::state_->get(); } - std::exception_ptr get_exception_ptr() { - if ( ! valid() ) { - throw future_uninitialized(); - } - return state_->get_exception_ptr(); - } - - void wait() const { - if ( ! valid() ) { - throw future_uninitialized(); - } - state_->wait(); - } + using base_t::valid; + using base_t::get_exception_ptr; + using base_t::wait; template< class Rep, class Period > future_status wait_for( std::chrono::duration< Rep, Period > const& timeout_duration) const { - if ( ! valid() ) { - throw future_uninitialized(); - } - return state_->wait_for( timeout_duration); + return base_t::wait_for( timeout_duration); } template< typename Clock, typename Duration > future_status wait_until( std::chrono::time_point< Clock, Duration > const& timeout_time) const { - if ( ! valid() ) { - throw future_uninitialized(); - } - return state_->wait_until( timeout_time); + return base_t::wait_until( timeout_time); } }; template<> -class shared_future< void > { +class shared_future< void > : private detail::future_base< void > { private: - typedef detail::shared_state< void >::ptr_t ptr_t; + typedef detail::future_base< void > base_t; - friend class future< void >; - - ptr_t state_; - - shared_future( ptr_t const& p) noexcept : - state_( p) { + explicit shared_future( base_t::ptr_t const& p) noexcept : + base_t{ p } { } public: - shared_future() noexcept : - state_() { - } + constexpr shared_future() noexcept = default; - ~shared_future() noexcept { - } + ~shared_future() noexcept = default; inline shared_future( shared_future const& other) : - state_( other.state_) { + base_t{ other } { } inline shared_future( shared_future && other) noexcept : - state_( std::move( other.state_) ) { + base_t{ std::forward< shared_future >( other) } { } inline shared_future( future< void > && other) noexcept : - state_( std::move( other.state_) ) { + base_t{ std::forward< future< void > >( other) } { } inline - shared_future & operator=( shared_future const& other) noexcept - { - if ( this != & other) { - state_ = other.state_; - } + shared_future & operator=( shared_future const& other) noexcept { + if ( this == & other) return * this; + base_t::operator=( other); return * this; } inline shared_future & operator=( shared_future && other) noexcept { - if ( this != & other) { - state_ = std::move( other.state_); - } + if ( this == & other) return * this; + base_t::operator=( std::forward< shared_future >( other) ); return * this; } inline shared_future & operator=( future< void > && other) noexcept { - state_ = std::move( other.state_); + base_t::operator=( std::forward< future< void > >( other) ); return * this; } - inline - bool valid() const noexcept { - return nullptr != state_.get(); - } - inline void get() const { if ( ! valid() ) { - throw future_uninitialized(); + throw future_uninitialized{}; } - state_->get(); + base_t::state_->get(); } - inline - std::exception_ptr get_exception_ptr() { - if ( ! valid() ) { - throw future_uninitialized(); - } - return state_->get_exception_ptr(); - } - - inline - void wait() const { - if ( ! valid() ) { - throw future_uninitialized(); - } - state_->wait(); - } + using base_t::valid; + using base_t::get_exception_ptr; + using base_t::wait; template< class Rep, class Period > future_status wait_for( std::chrono::duration< Rep, Period > const& timeout_duration) const { - if ( ! valid() ) { - throw future_uninitialized(); - } - return state_->wait_for( timeout_duration); + return base_t::wait_for( timeout_duration); } template< typename Clock, typename Duration > future_status wait_until( std::chrono::time_point< Clock, Duration > const& timeout_time) const { - if ( ! valid() ) { - throw future_uninitialized(); - } - return state_->wait_until( timeout_time); + return base_t::wait_until( timeout_time); } }; @@ -577,28 +467,28 @@ public: template< typename R > shared_future< R > future< R >::share() { - if ( ! valid() ) { - throw future_uninitialized(); + if ( ! base_t::valid() ) { + throw future_uninitialized{}; } - return shared_future< R >( std::move( * this) ); + return shared_future< R >{ std::move( * this) }; } template< typename R > shared_future< R & > future< R & >::share() { - if ( ! valid() ) { - throw future_uninitialized(); + if ( ! base_t::valid() ) { + throw future_uninitialized{}; } - return shared_future< R & >( std::move( * this) ); + return shared_future< R & >{ std::move( * this) }; } inline shared_future< void > future< void >::share() { - if ( ! valid() ) { - throw future_uninitialized(); + if ( ! base_t::valid() ) { + throw future_uninitialized{}; } - return shared_future< void >( std::move( * this) ); + return shared_future< void >{ std::move( * this) }; } }} diff --git a/include/boost/fiber/future/packaged_task.hpp b/include/boost/fiber/future/packaged_task.hpp index 4f98d0d8..ef179937 100644 --- a/include/boost/fiber/future/packaged_task.hpp +++ b/include/boost/fiber/future/packaged_task.hpp @@ -29,25 +29,20 @@ class packaged_task< R( Args ... ) > { private: typedef typename detail::task_base< R, Args ... >::ptr_t ptr_t; - bool obtained_; - ptr_t task_; + bool obtained_{ false }; + ptr_t task_{}; public: - packaged_task() noexcept : - obtained_( false), - task_() { - } + constexpr packaged_task() noexcept = default; - ~packaged_task() { + ~packaged_task() noexcept { if ( task_) { task_->owner_destroyed(); } } template< typename Fn > - explicit packaged_task( Fn && fn) : - obtained_( false), - task_() { + explicit packaged_task( Fn && fn) { typedef detail::task_object< Fn, std::allocator< packaged_task< R() > >, @@ -55,42 +50,38 @@ public: Args ... > object_t; std::allocator< packaged_task< R() > > alloc; - typename object_t::allocator_t a( alloc); - task_ = ptr_t( + typename object_t::allocator_t a{ alloc }; + task_ = ptr_t{ // placement new - ::new( a.allocate( 1) ) object_t( a, std::forward< Fn >( fn) ) ); + ::new( a.allocate( 1) ) object_t{ a, std::forward< Fn >( fn) } }; } template< typename Fn, typename Allocator > - explicit packaged_task( std::allocator_arg_t, Allocator const& alloc, Fn && fn) : - obtained_( false), - task_() { + explicit packaged_task( std::allocator_arg_t, Allocator const& alloc, Fn && fn) { typedef detail::task_object< Fn, Allocator, R > object_t; - typename object_t::allocator_t a( alloc); - task_ = ptr_t( + typename object_t::allocator_t a{ alloc }; + task_ = ptr_t{ // placement new - ::new( a.allocate( 1) ) object_t( a, std::forward< Fn >( fn) ) ); + ::new( a.allocate( 1) ) object_t{ a, std::forward< Fn >( fn) } }; } packaged_task( packaged_task const&) = delete; packaged_task & operator=( packaged_task const&) = delete; packaged_task( packaged_task && other) noexcept : - obtained_( other.obtained_), - task_( std::move( other.task_) ) { + obtained_{ other.obtained_ }, + task_{ std::move( other.task_) } { other.obtained_ = false; } packaged_task & operator=( packaged_task && other) noexcept { - if ( this != & other) { - obtained_ = other.obtained_; - other.obtained_ = false; - task_ = std::move( other.task_); - } + if ( this == & other) return * this; + packaged_task tmp{ std::move( other) }; + swap( tmp); return * this; } @@ -105,26 +96,26 @@ public: future< R > get_future() { if ( obtained_) { - throw future_already_retrieved(); + throw future_already_retrieved{}; } if ( ! valid() ) { - throw packaged_task_uninitialized(); + throw packaged_task_uninitialized{}; } obtained_ = true; - return future< R >( - boost::static_pointer_cast< detail::shared_state< R > >( task_) ); + return future< R >{ + boost::static_pointer_cast< detail::shared_state< R > >( task_) }; } void operator()( Args && ... args) { if ( ! valid() ) { - throw packaged_task_uninitialized(); + throw packaged_task_uninitialized{}; } task_->run( std::forward< Args >( args) ... ); } void reset() { if ( ! valid() ) { - throw packaged_task_uninitialized(); + throw packaged_task_uninitialized{}; } obtained_ = false; task_->reset(); diff --git a/include/boost/fiber/future/promise.hpp b/include/boost/fiber/future/promise.hpp index db4a5c23..e84816d1 100644 --- a/include/boost/fiber/future/promise.hpp +++ b/include/boost/fiber/future/promise.hpp @@ -26,35 +26,31 @@ class promise { private: typedef typename detail::shared_state< R >::ptr_t ptr_t; - bool obtained_; - ptr_t future_; + bool obtained_{ false }; + ptr_t future_{}; public: - promise() : - obtained_( false), - future_() { + promise() { typedef detail::shared_state_object< R, std::allocator< promise< R > > > object_t; std::allocator< promise< R > > alloc; - typename object_t::allocator_t a( alloc); - future_ = ptr_t( + typename object_t::allocator_t a{ alloc }; + future_ = ptr_t{ // placement new - ::new( a.allocate( 1) ) object_t( a) ); + ::new( a.allocate( 1) ) object_t{ a } }; } template< typename Allocator > - promise( std::allocator_arg_t, Allocator alloc) : - obtained_( false), - future_() { + promise( std::allocator_arg_t, Allocator alloc) { typedef detail::shared_state_object< R, Allocator > object_t; - typename object_t::allocator_t a( alloc); - future_ = ptr_t( + typename object_t::allocator_t a{ alloc }; + future_ = ptr_t{ // placement new - ::new( a.allocate( 1) ) object_t( a) ); + ::new( a.allocate( 1) ) object_t{ a } }; } - ~promise() { + ~promise() noexcept { if ( future_) { future_->owner_destroyed(); } @@ -64,17 +60,15 @@ public: promise & operator=( promise const&) = delete; promise( promise && other) noexcept : - obtained_( other.obtained_), - future_( std::move( other.future_) ) { + obtained_{ other.obtained_ }, + future_{ std::move( other.future_) } { other.obtained_ = false; } promise & operator=( promise && other) noexcept { - if ( this != & other) { - obtained_ = other.obtained_; - other.obtained_ = false; - future_ = std::move( other.future_); - } + if ( this == & other) return * this; + promise tmp{ std::move( other) }; + swap( tmp); return * this; } @@ -85,32 +79,32 @@ public: future< R > get_future() { if ( obtained_) { - throw future_already_retrieved(); + throw future_already_retrieved{}; } if ( ! future_) { - throw promise_uninitialized(); + throw promise_uninitialized{}; } obtained_ = true; - return future< R >( future_); + return future< R >{ future_ }; } void set_value( R const& value) { if ( ! future_) { - throw promise_uninitialized(); + throw promise_uninitialized{}; } future_->set_value( value); } void set_value( R && value) { if ( ! future_) { - throw promise_uninitialized(); + throw promise_uninitialized{}; } future_->set_value( std::move( value) ); } void set_exception( std::exception_ptr p) { if ( ! future_) { - throw promise_uninitialized(); + throw promise_uninitialized{}; } future_->set_exception( p); } @@ -121,35 +115,31 @@ class promise< R & > { private: typedef typename detail::shared_state< R & >::ptr_t ptr_t; - bool obtained_; - ptr_t future_; + bool obtained_{ false }; + ptr_t future_{}; public: - promise() : - obtained_( false), - future_() { + promise() { typedef detail::shared_state_object< R &, std::allocator< promise< R & > > > object_t; - std::allocator< promise< R > > alloc; - typename object_t::allocator_t a( alloc); - future_ = ptr_t( + std::allocator< promise< R > > alloc{}; + typename object_t::allocator_t a{ alloc }; + future_ = ptr_t{ // placement new - ::new( a.allocate( 1) ) object_t( a) ); + ::new( a.allocate( 1) ) object_t{ a } }; } template< typename Allocator > - promise( std::allocator_arg_t, Allocator alloc) : - obtained_( false), - future_() { + promise( std::allocator_arg_t, Allocator alloc) { typedef detail::shared_state_object< R &, Allocator > object_t; - typename object_t::allocator_t a( alloc); - future_ = ptr_t( + typename object_t::allocator_t a{ alloc }; + future_ = ptr_t{ // placement new - ::new( a.allocate( 1) ) object_t( a) ); + ::new( a.allocate( 1) ) object_t{ a } }; } - ~promise() { + ~promise() noexcept { if ( future_) { future_->owner_destroyed(); } @@ -159,17 +149,15 @@ public: promise & operator=( promise const&) = delete; promise( promise && other) noexcept : - obtained_( other.obtained_), - future_( std::move( other.future_) ) { + obtained_{ other.obtained_ }, + future_{ std::move( other.future_) } { other.obtained_ = false; } promise & operator=( promise && other) noexcept { - if ( this != & other) { - obtained_ = other.obtained_; - other.obtained_ = false; - future_ = std::move( other.future_); - } + if ( this == & other) return * this; + promise tmp{ std::move( other) }; + swap( tmp); return * this; } @@ -180,25 +168,25 @@ public: future< R & > get_future() { if ( obtained_) { - throw future_already_retrieved(); + throw future_already_retrieved{}; } if ( ! future_) { - throw promise_uninitialized(); + throw promise_uninitialized{}; } obtained_ = true; - return future< R & >( future_); + return future< R & >{ future_ }; } void set_value( R & value) { if ( ! future_) { - throw promise_uninitialized(); + throw promise_uninitialized{}; } future_->set_value( value); } void set_exception( std::exception_ptr p) { if ( ! future_) { - throw promise_uninitialized(); + throw promise_uninitialized{}; } future_->set_exception( p); } @@ -209,35 +197,31 @@ class promise< void > { private: typedef detail::shared_state< void >::ptr_t ptr_t; - bool obtained_; - ptr_t future_; + bool obtained_{ false }; + ptr_t future_{}; public: - promise() : - obtained_( false), - future_() { + promise() { typedef detail::shared_state_object< void, std::allocator< promise< void > > > object_t; - std::allocator< promise< void > > alloc; - object_t::allocator_t a( alloc); - future_ = ptr_t( + std::allocator< promise< void > > alloc{}; + object_t::allocator_t a{ alloc }; + future_ = ptr_t{ // placement new - ::new( a.allocate( 1) ) object_t( a) ); + ::new( a.allocate( 1) ) object_t{ a } }; } template< typename Allocator > - promise( std::allocator_arg_t, Allocator alloc) : - obtained_( false), - future_() { + promise( std::allocator_arg_t, Allocator alloc) { typedef detail::shared_state_object< void, Allocator > object_t; typename object_t::allocator_t a( alloc); - future_ = ptr_t( + future_ = ptr_t{ // placement new - ::new( a.allocate( 1) ) object_t( a) ); + ::new( a.allocate( 1) ) object_t{ a } }; } - ~promise() { + ~promise() noexcept { if ( future_) { future_->owner_destroyed(); } @@ -248,18 +232,16 @@ public: inline promise( promise && other) noexcept : - obtained_( other.obtained_), - future_( std::move( other.future_) ) { + obtained_{ other.obtained_ }, + future_{ std::move( other.future_) } { other.obtained_ = false; } inline promise & operator=( promise && other) noexcept { - if ( this != & other) { - obtained_ = other.obtained_; - other.obtained_ = false; - future_ = std::move( other.future_); - } + if ( this == & other) return * this; + promise tmp{ std::move( other) }; + swap( tmp); return * this; } @@ -272,19 +254,19 @@ public: inline future< void > get_future() { if ( obtained_) { - throw future_already_retrieved(); + throw future_already_retrieved{}; } if ( ! future_) { - throw promise_uninitialized(); + throw promise_uninitialized{}; } obtained_ = true; - return future< void >( future_); + return future< void >{ future_ }; } inline void set_value() { if ( ! future_) { - throw promise_uninitialized(); + throw promise_uninitialized{}; } future_->set_value(); } @@ -292,7 +274,7 @@ public: inline void set_exception( std::exception_ptr p) { if ( ! future_) { - throw promise_uninitialized(); + throw promise_uninitialized{}; } future_->set_exception( p); } diff --git a/src/context.cpp b/src/context.cpp index c45b41b8..038b1b14 100644 --- a/src/context.cpp +++ b/src/context.cpp @@ -58,7 +58,7 @@ static auto make_dispatcher_context( scheduler * sched) { thread_local static std::size_t counter; // schwarz counter -context_initializer::context_initializer() noexcept { +context_initializer::context_initializer() { if ( 0 == counter++) { # if defined(BOOST_NO_CXX14_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN) // allocate memory for main context and scheduler