• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 //          Copyright Oliver Kowalke 2013.
3 // Distributed under the Boost Software License, Version 1.0.
4 //    (See accompanying file LICENSE_1_0.txt or copy at
5 //          http://www.boost.org/LICENSE_1_0.txt)
6 
7 #ifndef BOOST_FIBERS_PACKAGED_TASK_HPP
8 #define BOOST_FIBERS_PACKAGED_TASK_HPP
9 
10 #include <algorithm>
11 #include <memory>
12 #include <type_traits>
13 #include <utility>
14 
15 #include <boost/config.hpp>
16 
17 #include <boost/fiber/detail/disable_overload.hpp>
18 #include <boost/fiber/exceptions.hpp>
19 #include <boost/fiber/future/detail/task_base.hpp>
20 #include <boost/fiber/future/detail/task_object.hpp>
21 #include <boost/fiber/future/future.hpp>
22 
23 namespace boost {
24 namespace fibers {
25 
26 template< typename Signature >
27 class packaged_task;
28 
29 template< typename R, typename ... Args >
30 class packaged_task< R( Args ... ) > {
31 private:
32     typedef typename detail::task_base< R, Args ... >::ptr_type   ptr_type;
33 
34     bool            obtained_{ false };
35     ptr_type        task_{};
36 
37 public:
38     packaged_task() = default;
39 
40     template< typename Fn,
41               typename = detail::disable_overload< packaged_task, Fn >
42     >
packaged_task(Fn && fn)43     explicit packaged_task( Fn && fn) :
44         packaged_task{ std::allocator_arg,
45                        std::allocator< packaged_task >{},
46                        std::forward< Fn >( fn)  } {
47     }
48 
49     template< typename Fn,
50               typename Allocator
51     >
packaged_task(std::allocator_arg_t,Allocator const & alloc,Fn && fn)52     explicit packaged_task( std::allocator_arg_t, Allocator const& alloc, Fn && fn) {
53         typedef detail::task_object<
54             typename std::decay< Fn >::type, Allocator, R, Args ...
55         >                                       object_type;
56         typedef std::allocator_traits<
57             typename object_type::allocator_type
58         >                                       traits_type;
59         typedef pointer_traits< typename traits_type::pointer > ptrait_type;
60 
61         typename object_type::allocator_type a{ alloc };
62         typename traits_type::pointer ptr{ traits_type::allocate( a, 1) };
63         typename ptrait_type::element_type* p = boost::to_address(ptr);
64         try {
65             traits_type::construct( a, p, a, std::forward< Fn >( fn) );
66         } catch (...) {
67             traits_type::deallocate( a, ptr, 1);
68             throw;
69         }
70         task_.reset(p);
71     }
72 
~packaged_task()73     ~packaged_task() {
74         if ( task_ && obtained_) {
75             task_->owner_destroyed();
76         }
77     }
78 
79     packaged_task( packaged_task const&) = delete;
80     packaged_task & operator=( packaged_task const&) = delete;
81 
packaged_task(packaged_task && other)82     packaged_task( packaged_task && other) noexcept :
83         obtained_{ other.obtained_ },
84         task_{ std::move( other.task_)  } {
85         other.obtained_ = false;
86     }
87 
operator =(packaged_task && other)88     packaged_task & operator=( packaged_task && other) noexcept {
89         if ( BOOST_LIKELY( this != & other) ) {
90             packaged_task tmp{ std::move( other) };
91             swap( tmp);
92         }
93         return * this;
94     }
95 
swap(packaged_task & other)96     void swap( packaged_task & other) noexcept {
97         std::swap( obtained_, other.obtained_);
98         task_.swap( other.task_);
99     }
100 
valid() const101     bool valid() const noexcept {
102         return nullptr != task_.get();
103     }
104 
get_future()105     future< R > get_future() {
106         if ( obtained_) {
107             throw future_already_retrieved{};
108         }
109         if ( BOOST_UNLIKELY( ! valid() ) ) {
110             throw packaged_task_uninitialized{};
111         }
112         obtained_ = true;
113         return future< R >{
114              boost::static_pointer_cast< detail::shared_state< R > >( task_) };
115     }
116 
operator ()(Args...args)117     void operator()( Args ... args) {
118         if ( BOOST_UNLIKELY( ! valid() ) ) {
119             throw packaged_task_uninitialized{};
120         }
121         task_->run( std::forward< Args >( args) ... );
122     }
123 
reset()124     void reset() {
125         if ( BOOST_UNLIKELY( ! valid() ) ) {
126             throw packaged_task_uninitialized{};
127         }
128         packaged_task tmp;
129         tmp.task_ = task_;
130         task_ = tmp.task_->reset();
131         obtained_ = false;
132     }
133 };
134 
135 template< typename Signature >
swap(packaged_task<Signature> & l,packaged_task<Signature> & r)136 void swap( packaged_task< Signature > & l, packaged_task< Signature > & r) noexcept {
137     l.swap( r);
138 }
139 
140 }}
141 
142 #endif // BOOST_FIBERS_PACKAGED_TASK_HPP
143