]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | |
2 | // Copyright Oliver Kowalke 2014. | |
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 | namespace detail { | |
8 | ||
9 | template< typename Ctx, typename Fn > | |
10 | transfer_t context_ontop_void( transfer_t t) { | |
11 | auto tpl = static_cast< std::tuple< Fn > * >( t.data); | |
12 | BOOST_ASSERT( nullptr != tpl); | |
13 | typename std::decay< Fn >::type fn = std::forward< Fn >( std::get< 0 >( * tpl) ); | |
14 | Ctx ctx{ t.fctx }; | |
15 | // execute function | |
16 | ctx = apply( | |
17 | fn, | |
18 | std::forward_as_tuple( std::move( ctx) ) ); | |
19 | return { exchange( ctx.fctx_, nullptr), nullptr }; | |
20 | } | |
21 | ||
22 | template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params > | |
23 | class record_void { | |
24 | private: | |
25 | StackAlloc salloc_; | |
26 | stack_context sctx_; | |
27 | typename std::decay< Fn >::type fn_; | |
28 | std::tuple< typename std::decay< Params >::type ... > params_; | |
29 | ||
30 | static void destroy( record_void * p) noexcept { | |
31 | StackAlloc salloc = p->salloc_; | |
32 | stack_context sctx = p->sctx_; | |
33 | // deallocate record | |
34 | p->~record_void(); | |
35 | // destroy stack with stack allocator | |
36 | salloc.deallocate( sctx); | |
37 | } | |
38 | ||
39 | public: | |
40 | record_void( stack_context sctx, StackAlloc const& salloc, | |
41 | Fn && fn, Params && ... params) noexcept : | |
42 | salloc_( salloc), | |
43 | sctx_( sctx), | |
44 | fn_( std::forward< Fn >( fn) ), | |
45 | params_( std::forward< Params >( params) ... ) { | |
46 | } | |
47 | ||
48 | record_void( record_void const&) = delete; | |
49 | record_void & operator=( record_void const&) = delete; | |
50 | ||
51 | void deallocate() noexcept { | |
52 | destroy( this); | |
53 | } | |
54 | ||
55 | transfer_t run( transfer_t t) { | |
56 | Ctx from{ t.fctx }; | |
57 | // invoke context-function | |
58 | Ctx cc = apply( | |
59 | fn_, | |
60 | std::tuple_cat( | |
61 | params_, | |
62 | std::forward_as_tuple( std::move( from) ) ) ); | |
63 | return { exchange( cc.fctx_, nullptr), nullptr }; | |
64 | } | |
65 | }; | |
66 | ||
67 | template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params > | |
68 | fcontext_t context_create_void( StackAlloc salloc, Fn && fn, Params && ... params) { | |
69 | typedef record_void< Ctx, StackAlloc, Fn, Params ... > record_t; | |
70 | ||
71 | auto sctx = salloc.allocate(); | |
72 | // reserve space for control structure | |
73 | #if defined(BOOST_NO_CXX11_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN) | |
74 | const std::size_t size = sctx.size - sizeof( record_t); | |
75 | void * sp = static_cast< char * >( sctx.sp) - sizeof( record_t); | |
76 | #else | |
77 | constexpr std::size_t func_alignment = 64; // alignof( record_t); | |
78 | constexpr std::size_t func_size = sizeof( record_t); | |
79 | // reserve space on stack | |
80 | void * sp = static_cast< char * >( sctx.sp) - func_size - func_alignment; | |
81 | // align sp pointer | |
82 | std::size_t space = func_size + func_alignment; | |
83 | sp = std::align( func_alignment, func_size, sp, space); | |
84 | BOOST_ASSERT( nullptr != sp); | |
85 | // calculate remaining size | |
86 | const std::size_t size = sctx.size - ( static_cast< char * >( sctx.sp) - static_cast< char * >( sp) ); | |
87 | #endif | |
88 | // create fast-context | |
89 | const fcontext_t fctx = make_fcontext( sp, size, & context_entry< record_t >); | |
90 | BOOST_ASSERT( nullptr != fctx); | |
91 | // placment new for control structure on context-stack | |
92 | auto rec = ::new ( sp) record_t{ | |
93 | sctx, salloc, std::forward< Fn >( fn), std::forward< Params >( params) ... }; | |
94 | // transfer control structure to context-stack | |
95 | return jump_fcontext( fctx, rec).fctx; | |
96 | } | |
97 | ||
98 | template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params > | |
99 | fcontext_t context_create_void( preallocated palloc, StackAlloc salloc, Fn && fn, Params && ... params) { | |
100 | typedef record_void< Ctx, StackAlloc, Fn, Params ... > record_t; | |
101 | ||
102 | // reserve space for control structure | |
103 | #if defined(BOOST_NO_CXX11_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN) | |
104 | const std::size_t size = palloc.size - sizeof( record_t); | |
105 | void * sp = static_cast< char * >( palloc.sp) - sizeof( record_t); | |
106 | #else | |
107 | constexpr std::size_t func_alignment = 64; // alignof( record_t); | |
108 | constexpr std::size_t func_size = sizeof( record_t); | |
109 | // reserve space on stack | |
110 | void * sp = static_cast< char * >( palloc.sp) - func_size - func_alignment; | |
111 | // align sp pointer | |
112 | std::size_t space = func_size + func_alignment; | |
113 | sp = std::align( func_alignment, func_size, sp, space); | |
114 | BOOST_ASSERT( nullptr != sp); | |
115 | // calculate remaining size | |
116 | const std::size_t size = palloc.size - ( static_cast< char * >( palloc.sp) - static_cast< char * >( sp) ); | |
117 | #endif | |
118 | // create fast-context | |
119 | const fcontext_t fctx = make_fcontext( sp, size, & context_entry< record_t >); | |
120 | BOOST_ASSERT( nullptr != fctx); | |
121 | // placment new for control structure on context-stack | |
122 | auto rec = ::new ( sp) record_t{ | |
123 | palloc.sctx, salloc, std::forward< Fn >( fn), std::forward< Params >( params) ... }; | |
124 | // transfer control structure to context-stack | |
125 | return jump_fcontext( fctx, rec).fctx; | |
126 | } | |
127 | ||
128 | } | |
129 | ||
130 | template<> | |
131 | class execution_context< void > { | |
132 | private: | |
133 | template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params > | |
134 | friend class detail::record_void; | |
135 | ||
136 | template< typename Ctx, typename Fn > | |
137 | friend detail::transfer_t detail::context_ontop_void( detail::transfer_t); | |
138 | ||
139 | detail::fcontext_t fctx_{ nullptr }; | |
140 | ||
141 | execution_context( detail::fcontext_t fctx) noexcept : | |
142 | fctx_( fctx) { | |
143 | } | |
144 | ||
145 | public: | |
146 | constexpr execution_context() noexcept = default; | |
147 | ||
148 | #if defined(BOOST_USE_SEGMENTED_STACKS) | |
149 | // segmented-stack requires to preserve the segments of the `current` context | |
150 | // which is not possible (no global pointer to current context) | |
151 | template< typename Fn, typename ... Params > | |
152 | execution_context( std::allocator_arg_t, segmented_stack, Fn &&, Params && ...) = delete; | |
153 | ||
154 | template< typename Fn, typename ... Params > | |
155 | execution_context( std::allocator_arg_t, preallocated, segmented_stack, Fn &&, Params && ...) = delete; | |
156 | #else | |
157 | template< typename Fn, | |
158 | typename ... Params, | |
159 | typename = detail::disable_overload< execution_context, Fn > | |
160 | > | |
161 | execution_context( Fn && fn, Params && ... params) : | |
162 | // deferred execution of fn and its arguments | |
163 | // arguments are stored in std::tuple<> | |
164 | // non-type template parameter pack via std::index_sequence_for<> | |
165 | // preserves the number of arguments | |
166 | // used to extract the function arguments from std::tuple<> | |
167 | fctx_( detail::context_create_void< execution_context >( | |
168 | fixedsize_stack(), | |
169 | std::forward< Fn >( fn), | |
170 | std::forward< Params >( params) ... ) ) { | |
171 | } | |
172 | ||
173 | template< typename StackAlloc, | |
174 | typename Fn, | |
175 | typename ... Params | |
176 | > | |
177 | execution_context( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Params && ... params) : | |
178 | // deferred execution of fn and its arguments | |
179 | // arguments are stored in std::tuple<> | |
180 | // non-type template parameter pack via std::index_sequence_for<> | |
181 | // preserves the number of arguments | |
182 | // used to extract the function arguments from std::tuple<> | |
183 | fctx_( detail::context_create_void< execution_context >( | |
184 | salloc, | |
185 | std::forward< Fn >( fn), | |
186 | std::forward< Params >( params) ... ) ) { | |
187 | } | |
188 | ||
189 | template< typename StackAlloc, | |
190 | typename Fn, | |
191 | typename ... Params | |
192 | > | |
193 | execution_context( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Params && ... params) : | |
194 | // deferred execution of fn and its arguments | |
195 | // arguments are stored in std::tuple<> | |
196 | // non-type template parameter pack via std::index_sequence_for<> | |
197 | // preserves the number of arguments | |
198 | // used to extract the function arguments from std::tuple<> | |
199 | fctx_( detail::context_create_void< execution_context >( | |
200 | palloc, salloc, | |
201 | std::forward< Fn >( fn), | |
202 | std::forward< Params >( params) ... ) ) { | |
203 | } | |
204 | #endif | |
205 | ||
206 | ~execution_context() { | |
207 | if ( nullptr != fctx_) { | |
208 | detail::ontop_fcontext( detail::exchange( fctx_, nullptr), nullptr, detail::context_unwind); | |
209 | } | |
210 | } | |
211 | ||
212 | execution_context( execution_context && other) noexcept : | |
213 | fctx_( other.fctx_) { | |
214 | other.fctx_ = nullptr; | |
215 | } | |
216 | ||
217 | execution_context & operator=( execution_context && other) noexcept { | |
218 | if ( this != & other) { | |
219 | execution_context tmp = std::move( other); | |
220 | swap( tmp); | |
221 | } | |
222 | return * this; | |
223 | } | |
224 | ||
225 | execution_context( execution_context const& other) noexcept = delete; | |
226 | execution_context & operator=( execution_context const& other) noexcept = delete; | |
227 | ||
228 | execution_context operator()() { | |
229 | BOOST_ASSERT( nullptr != fctx_); | |
230 | detail::transfer_t t = detail::jump_fcontext( detail::exchange( fctx_, nullptr), nullptr); | |
231 | return execution_context( t.fctx); | |
232 | } | |
233 | ||
234 | template< typename Fn > | |
235 | execution_context operator()( exec_ontop_arg_t, Fn && fn) { | |
236 | BOOST_ASSERT( nullptr != fctx_); | |
237 | std::tuple< Fn > p = std::forward_as_tuple( fn); | |
238 | detail::transfer_t t = detail::ontop_fcontext( | |
239 | detail::exchange( fctx_, nullptr), | |
240 | & p, | |
241 | detail::context_ontop_void< execution_context, Fn >); | |
242 | return execution_context( t.fctx); | |
243 | } | |
244 | ||
245 | explicit operator bool() const noexcept { | |
246 | return nullptr != fctx_; | |
247 | } | |
248 | ||
249 | bool operator!() const noexcept { | |
250 | return nullptr == fctx_; | |
251 | } | |
252 | ||
253 | bool operator==( execution_context const& other) const noexcept { | |
254 | return fctx_ == other.fctx_; | |
255 | } | |
256 | ||
257 | bool operator!=( execution_context const& other) const noexcept { | |
258 | return fctx_ != other.fctx_; | |
259 | } | |
260 | ||
261 | bool operator<( execution_context const& other) const noexcept { | |
262 | return fctx_ < other.fctx_; | |
263 | } | |
264 | ||
265 | bool operator>( execution_context const& other) const noexcept { | |
266 | return other.fctx_ < fctx_; | |
267 | } | |
268 | ||
269 | bool operator<=( execution_context const& other) const noexcept { | |
270 | return ! ( * this > other); | |
271 | } | |
272 | ||
273 | bool operator>=( execution_context const& other) const noexcept { | |
274 | return ! ( * this < other); | |
275 | } | |
276 | ||
277 | template< typename charT, class traitsT > | |
278 | friend std::basic_ostream< charT, traitsT > & | |
279 | operator<<( std::basic_ostream< charT, traitsT > & os, execution_context const& other) { | |
280 | if ( nullptr != other.fctx_) { | |
281 | return os << other.fctx_; | |
282 | } else { | |
283 | return os << "{not-a-context}"; | |
284 | } | |
285 | } | |
286 | ||
287 | void swap( execution_context & other) noexcept { | |
288 | std::swap( fctx_, other.fctx_); | |
289 | } | |
290 | }; |