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