#ifndef FUTURE_HPP_INCLUDED #define FUTURE_HPP_INCLUDED // Copyright (c) 2007 Peter Dimov // // Distributed under the Boost Software License, Version 1.0. // http://www.boost.org/LICENSE_1_0.txt #include "event.hpp" #include "exception_ptr.hpp" #include "thread.hpp" #include #include #include class future_result_moved: public std::exception { public: char const * what() const throw() { return "std::future_result_moved"; } }; template< class R > class future_impl { private: event ready_; boost::optional r_; exception_ptr e_; std::thread::handle th_; future_impl( future_impl const & ); future_impl & operator=( future_impl const & ); public: future_impl() { } bool has_value() const // throw() { return try_join() && e_ == 0; } bool has_exception() const // throw() { return try_join() && e_ != 0; } void join() // throw( thread::cancel_exception ) { int r = ready_.wait(); if( r != 0 ) throw std::thread_error( r ); } bool try_join() // throw() { return ready_.try_wait() == 0; } bool timed_join( timespec const & abstime ) // throw( thread::cancel_exception ) { int r = ready_.timed_wait( abstime ); if( r == 0 ) return true; if( r == ETIMEDOUT ) return false; throw std::thread_error( r ); } std::thread::handle get_cancel_handle() { std::basic_lock< event > lock( ready_ ); return th_; } void cancel() { std::thread::cancel( get_cancel_handle() ); } R copy() // throw( thread::cancel_exception, ... ) { join(); if( e_ != 0 ) { rethrow_exception( e_ ); } assert( r_.is_initialized() ); return r_.get(); } R move() { join(); if( e_ != 0 ) { rethrow_exception( e_ ); } assert( r_.is_initialized() ); e_ = copy_exception( future_result_moved() ); return r_.get(); // std::move( r_.get() ) } void set_value( R const & r ) { std::basic_lock< event > lock( ready_ ); if( !ready_.unlocked_is_set() ) { try { r_.reset( r ); } catch( ... ) { e_ = current_exception(); } th_ = std::thread::handle(); ready_.unlocked_set(); } } void set_exception( exception_ptr p ) // throw() { std::basic_lock< event > lock( ready_ ); if( !ready_.unlocked_is_set() ) { e_ = p; th_ = std::thread::handle(); ready_.unlocked_set(); } } void set_cancel_handle( std::thread::handle const & th ) { std::basic_lock< event > lock( ready_ ); th_ = th; } }; template< class R > class future { private: boost::shared_ptr< future_impl > pi_; public: future(): pi_( new future_impl() ) { } bool has_value() const { return pi_->has_value(); } bool has_exception() const { return pi_->has_exception(); } void join() { return pi_->join(); } bool try_join() { return pi_->try_join(); } bool timed_join( timespec const & abstime ) { return pi_->timed_join( abstime ); } void cancel() { pi_->cancel(); } operator R() const { return pi_->copy(); } R get() const { return pi_->copy(); } R move() { return pi_->move(); } void set_value( R const & r ) { pi_->set_value( r ); } void set_exception( exception_ptr p ) // throw() { pi_->set_exception( p ); } void set_cancel_handle( std::thread::handle const & th ) { pi_->set_thread_handle( th ); } }; template< class R > class future< R& >: private future< R* > { private: typedef future< R* > base_type; public: using base_type::has_value; using base_type::has_exception; using base_type::join; using base_type::try_join; using base_type::timed_join; using base_type::cancel; operator R&() const { return *base_type::get(); } R& get() const { return *base_type::get(); } void set_value( R & r ) { base_type::set_value( &r ); } using base_type::set_exception; using base_type::set_cancel_handle; }; /* R&& template< class R > class future< R&& >: private future< R > { private: typedef future< R > base_type; public: future() { } template< class R > future( future const & f ): base_type( f ) { } using base_type::has_value; using base_type::has_exception; using base_type::join; using base_type::try_join; using base_type::timed_join; using base_type::cancel; operator R() { return base_type::move(); } R get() { return base_type::move(); } using base_type::move; using base_type::set_value; using base_type::set_exception; using base_type::set_cancel_handle; }; */ template<> class future< void >: private future< int > { private: typedef future< int > base_type; public: using base_type::has_value; using base_type::has_exception; using base_type::join; using base_type::try_join; using base_type::timed_join; using base_type::cancel; void get() const { base_type::get(); } void set_value() { base_type::set_value( 0 ); } using base_type::set_exception; using base_type::set_cancel_handle; }; #endif // #ifndef FUTURE_HPP_INCLUDED