]>
Commit | Line | Data |
---|---|---|
b32b8144 FG |
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_DETAIL_TASK_OBJECT_H | |
8 | #define BOOST_FIBERS_DETAIL_TASK_OBJECT_H | |
9 | ||
10 | #include <exception> | |
11 | #include <memory> | |
12 | #include <tuple> | |
13 | #include <utility> | |
14 | ||
15 | #include <boost/config.hpp> | |
16 | #if defined(BOOST_NO_CXX17_STD_APPLY) | |
17 | #include <boost/context/detail/apply.hpp> | |
18 | #endif | |
19 | #include <boost/core/pointer_traits.hpp> | |
20 | ||
21 | #include <boost/fiber/detail/config.hpp> | |
22 | #include <boost/fiber/future/detail/task_base.hpp> | |
23 | ||
24 | #ifdef BOOST_HAS_ABI_HEADERS | |
25 | # include BOOST_ABI_PREFIX | |
26 | #endif | |
27 | ||
28 | namespace boost { | |
29 | namespace fibers { | |
30 | namespace detail { | |
31 | ||
32 | template< typename Fn, typename Allocator, typename R, typename ... Args > | |
33 | class task_object : public task_base< R, Args ... > { | |
34 | private: | |
35 | typedef task_base< R, Args ... > base_type; | |
36 | ||
37 | public: | |
38 | typedef typename std::allocator_traits< Allocator >::template rebind_alloc< | |
39 | task_object | |
40 | > allocator_type; | |
41 | ||
42 | task_object( allocator_type const& alloc, Fn const& fn) : | |
43 | base_type{}, | |
44 | fn_{ fn }, | |
45 | alloc_{ alloc } { | |
46 | } | |
47 | ||
48 | task_object( allocator_type const& alloc, Fn && fn) : | |
49 | base_type{}, | |
50 | fn_{ std::move( fn) }, | |
51 | alloc_{ alloc } { | |
52 | } | |
53 | ||
54 | void run( Args && ... args) override final { | |
55 | try { | |
56 | this->set_value( | |
57 | #if defined(BOOST_NO_CXX17_STD_APPLY) | |
58 | boost::context::detail::apply( | |
59 | fn_, std::make_tuple( std::forward< Args >( args) ... ) ) | |
60 | #else | |
61 | std::apply( | |
62 | fn_, std::make_tuple( std::forward< Args >( args) ... ) ) | |
63 | #endif | |
64 | ); | |
65 | } catch (...) { | |
66 | this->set_exception( std::current_exception() ); | |
67 | } | |
68 | } | |
69 | ||
70 | typename base_type::ptr_type reset() override final { | |
71 | typedef std::allocator_traits< allocator_type > traity_type; | |
72 | typedef pointer_traits< typename traity_type::pointer> ptrait_type; | |
73 | ||
74 | typename traity_type::pointer ptr{ traity_type::allocate( alloc_, 1) }; | |
75 | typename ptrait_type::element_type* p = boost::to_address(ptr); | |
76 | try { | |
77 | traity_type::construct( alloc_, p, alloc_, std::move( fn_) ); | |
78 | } catch (...) { | |
79 | traity_type::deallocate( alloc_, ptr, 1); | |
80 | throw; | |
81 | } | |
82 | return { p }; | |
83 | } | |
84 | ||
85 | protected: | |
86 | void deallocate_future() noexcept override final { | |
87 | destroy_( alloc_, this); | |
88 | } | |
89 | ||
90 | private: | |
91 | Fn fn_; | |
92 | allocator_type alloc_; | |
93 | ||
94 | static void destroy_( allocator_type const& alloc, task_object * p) noexcept { | |
95 | allocator_type a{ alloc }; | |
96 | a.destroy( p); | |
97 | a.deallocate( p, 1); | |
98 | } | |
99 | }; | |
100 | ||
101 | template< typename Fn, typename Allocator, typename ... Args > | |
102 | class task_object< Fn, Allocator, void, Args ... > : public task_base< void, Args ... > { | |
103 | private: | |
104 | typedef task_base< void, Args ... > base_type; | |
105 | ||
106 | public: | |
107 | typedef typename Allocator::template rebind< | |
108 | task_object< Fn, Allocator, void, Args ... > | |
109 | >::other allocator_type; | |
110 | ||
111 | task_object( allocator_type const& alloc, Fn const& fn) : | |
112 | base_type{}, | |
113 | fn_{ fn }, | |
114 | alloc_{ alloc } { | |
115 | } | |
116 | ||
117 | task_object( allocator_type const& alloc, Fn && fn) : | |
118 | base_type{}, | |
119 | fn_{ std::move( fn) }, | |
120 | alloc_{ alloc } { | |
121 | } | |
122 | ||
123 | void run( Args && ... args) override final { | |
124 | try { | |
125 | #if defined(BOOST_NO_CXX17_STD_APPLY) | |
126 | boost::context::detail::apply( | |
127 | fn_, std::make_tuple( std::forward< Args >( args) ... ) ); | |
128 | #else | |
129 | std::apply( | |
130 | fn_, std::make_tuple( std::forward< Args >( args) ... ) ); | |
131 | #endif | |
132 | this->set_value(); | |
133 | } catch (...) { | |
134 | this->set_exception( std::current_exception() ); | |
135 | } | |
136 | } | |
137 | ||
138 | typename base_type::ptr_type reset() override final { | |
139 | typedef std::allocator_traits< allocator_type > traity_type; | |
140 | typedef pointer_traits< typename traity_type::pointer> ptrait_type; | |
141 | ||
142 | typename traity_type::pointer ptr{ traity_type::allocate( alloc_, 1) }; | |
143 | typename ptrait_type::element_type* p = boost::to_address(ptr); | |
144 | try { | |
145 | traity_type::construct( alloc_, p, alloc_, std::move( fn_) ); | |
146 | } catch (...) { | |
147 | traity_type::deallocate( alloc_, ptr, 1); | |
148 | throw; | |
149 | } | |
150 | return { p }; | |
151 | } | |
152 | ||
153 | protected: | |
154 | void deallocate_future() noexcept override final { | |
155 | destroy_( alloc_, this); | |
156 | } | |
157 | ||
158 | private: | |
159 | Fn fn_; | |
160 | allocator_type alloc_; | |
161 | ||
162 | static void destroy_( allocator_type const& alloc, task_object * p) noexcept { | |
163 | allocator_type a{ alloc }; | |
164 | a.destroy( p); | |
165 | a.deallocate( p, 1); | |
166 | } | |
167 | }; | |
168 | ||
169 | }}} | |
170 | ||
171 | #ifdef BOOST_HAS_ABI_HEADERS | |
172 | # include BOOST_ABI_SUFFIX | |
173 | #endif | |
174 | ||
175 | #endif // BOOST_FIBERS_DETAIL_TASK_OBJECT_H |