File indexing completed on 2025-01-30 09:35:35
0001
0002
0003
0004
0005
0006
0007 #ifndef BOOST_FIBERS_PACKAGED_TASK_HPP
0008 #define BOOST_FIBERS_PACKAGED_TASK_HPP
0009
0010 #include <algorithm>
0011 #include <memory>
0012 #include <type_traits>
0013 #include <utility>
0014
0015 #include <boost/config.hpp>
0016
0017 #include <boost/fiber/detail/disable_overload.hpp>
0018 #include <boost/fiber/exceptions.hpp>
0019 #include <boost/fiber/future/detail/task_base.hpp>
0020 #include <boost/fiber/future/detail/task_object.hpp>
0021 #include <boost/fiber/future/future.hpp>
0022
0023 namespace boost {
0024 namespace fibers {
0025
0026 template< typename Signature >
0027 class packaged_task;
0028
0029 template< typename R, typename ... Args >
0030 class packaged_task< R( Args ... ) > {
0031 private:
0032 typedef typename detail::task_base< R, Args ... >::ptr_type ptr_type;
0033
0034 bool obtained_{ false };
0035 ptr_type task_{};
0036
0037 public:
0038 packaged_task() = default;
0039
0040 template< typename Fn,
0041 typename = detail::disable_overload< packaged_task, Fn >
0042 >
0043 explicit packaged_task( Fn && fn) :
0044 packaged_task{ std::allocator_arg,
0045 std::allocator< packaged_task >{},
0046 std::forward< Fn >( fn) } {
0047 }
0048
0049 template< typename Fn,
0050 typename Allocator
0051 >
0052 explicit packaged_task( std::allocator_arg_t, Allocator const& alloc, Fn && fn) {
0053 typedef detail::task_object<
0054 typename std::decay< Fn >::type, Allocator, R, Args ...
0055 > object_type;
0056 typedef std::allocator_traits<
0057 typename object_type::allocator_type
0058 > traits_type;
0059 typedef pointer_traits< typename traits_type::pointer > ptrait_type;
0060
0061 typename object_type::allocator_type a{ alloc };
0062 typename traits_type::pointer ptr{ traits_type::allocate( a, 1) };
0063 typename ptrait_type::element_type* p = boost::to_address(ptr);
0064 try {
0065 traits_type::construct( a, p, a, std::forward< Fn >( fn) );
0066 } catch (...) {
0067 traits_type::deallocate( a, ptr, 1);
0068 throw;
0069 }
0070 task_.reset(p);
0071 }
0072
0073 ~packaged_task() {
0074 if ( task_ && obtained_) {
0075 task_->owner_destroyed();
0076 }
0077 }
0078
0079 packaged_task( packaged_task const&) = delete;
0080 packaged_task & operator=( packaged_task const&) = delete;
0081
0082 packaged_task( packaged_task && other) noexcept :
0083 obtained_{ other.obtained_ },
0084 task_{ std::move( other.task_) } {
0085 other.obtained_ = false;
0086 }
0087
0088 packaged_task & operator=( packaged_task && other) noexcept {
0089 if ( BOOST_LIKELY( this != & other) ) {
0090 packaged_task tmp{ std::move( other) };
0091 swap( tmp);
0092 }
0093 return * this;
0094 }
0095
0096 void swap( packaged_task & other) noexcept {
0097 std::swap( obtained_, other.obtained_);
0098 task_.swap( other.task_);
0099 }
0100
0101 bool valid() const noexcept {
0102 return nullptr != task_.get();
0103 }
0104
0105 future< R > get_future() {
0106 if ( obtained_) {
0107 throw future_already_retrieved{};
0108 }
0109 if ( BOOST_UNLIKELY( ! valid() ) ) {
0110 throw packaged_task_uninitialized{};
0111 }
0112 obtained_ = true;
0113 return future< R >{
0114 boost::static_pointer_cast< detail::shared_state< R > >( task_) };
0115 }
0116
0117 void operator()( Args ... args) {
0118 if ( BOOST_UNLIKELY( ! valid() ) ) {
0119 throw packaged_task_uninitialized{};
0120 }
0121 task_->run( std::forward< Args >( args) ... );
0122 }
0123
0124 void reset() {
0125 if ( BOOST_UNLIKELY( ! valid() ) ) {
0126 throw packaged_task_uninitialized{};
0127 }
0128 packaged_task tmp;
0129 tmp.task_ = task_;
0130 task_ = tmp.task_->reset();
0131 obtained_ = false;
0132 }
0133 };
0134
0135 template< typename Signature >
0136 void swap( packaged_task< Signature > & l, packaged_task< Signature > & r) noexcept {
0137 l.swap( r);
0138 }
0139
0140 }}
0141
0142 #endif