]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | #ifndef BOOST_STATECHART_PROCESSOR_CONTAINER_HPP_INCLUDED |
2 | #define BOOST_STATECHART_PROCESSOR_CONTAINER_HPP_INCLUDED | |
3 | ////////////////////////////////////////////////////////////////////////////// | |
4 | // Copyright 2002-2008 Andreas Huber Doenni | |
5 | // Distributed under the Boost Software License, Version 1.0. (See accompany- | |
6 | // ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
7 | ////////////////////////////////////////////////////////////////////////////// | |
8 | ||
9 | ||
10 | ||
11 | #include <boost/statechart/event_base.hpp> | |
12 | #include <boost/statechart/event_processor.hpp> | |
13 | ||
14 | #include <boost/assert.hpp> | |
15 | #include <boost/ref.hpp> | |
16 | #include <boost/noncopyable.hpp> | |
17 | #include <boost/intrusive_ptr.hpp> | |
18 | #include <boost/shared_ptr.hpp> | |
19 | #include <boost/weak_ptr.hpp> | |
20 | #include <boost/bind.hpp> | |
21 | #include <boost/config.hpp> // BOOST_INTEL | |
22 | ||
23 | #include <boost/detail/workaround.hpp> | |
24 | #include <boost/detail/allocator_utilities.hpp> | |
25 | ||
26 | #include <set> | |
27 | #include <memory> // std::allocator, std::auto_ptr | |
28 | ||
29 | ||
30 | ||
31 | namespace boost | |
32 | { | |
33 | namespace statechart | |
34 | { | |
35 | namespace detail | |
36 | { | |
37 | template<bool IsReferenceWrapper> | |
38 | struct unwrap_impl | |
39 | { | |
40 | template< typename T > | |
41 | struct apply { typedef T type; }; | |
42 | }; | |
43 | ||
44 | template<> | |
45 | struct unwrap_impl<true> | |
46 | { | |
47 | template< typename T > | |
48 | struct apply { typedef typename T::type & type; }; | |
49 | }; | |
50 | ||
51 | template<typename T> | |
52 | struct unwrap | |
53 | { | |
54 | typedef typename unwrap_impl< | |
55 | is_reference_wrapper< T >::value >::template apply< T >::type type; | |
56 | }; | |
57 | } | |
58 | ||
59 | ||
60 | template< | |
61 | class Scheduler, | |
62 | class WorkItem, | |
63 | class Allocator = std::allocator< void > > | |
64 | class processor_container : noncopyable | |
65 | { | |
66 | typedef event_processor< Scheduler > processor_base_type; | |
67 | typedef std::auto_ptr< processor_base_type > processor_holder_type; | |
68 | typedef shared_ptr< processor_holder_type > processor_holder_ptr_type; | |
69 | ||
70 | public: | |
71 | ////////////////////////////////////////////////////////////////////////// | |
72 | typedef weak_ptr< processor_holder_type > processor_handle; | |
73 | ||
74 | class processor_context | |
75 | { | |
76 | processor_context( | |
77 | Scheduler & scheduler, const processor_handle & handle | |
78 | ) : | |
79 | scheduler_( scheduler ), | |
80 | handle_( handle ) | |
81 | { | |
82 | } | |
83 | ||
84 | #if BOOST_WORKAROUND( BOOST_INTEL, BOOST_TESTED_AT( 800 ) ) | |
85 | public: | |
86 | // for some reason Intel 8.0 seems to think that the following functions | |
87 | // are inaccessible from event_processor<>::event_processor | |
88 | #endif | |
89 | ||
90 | Scheduler & my_scheduler() const { return scheduler_; } | |
91 | const processor_handle & my_handle() const { return handle_; } | |
92 | ||
93 | #if BOOST_WORKAROUND( BOOST_INTEL, BOOST_TESTED_AT( 800 ) ) | |
94 | private: | |
95 | #endif | |
96 | ||
97 | // avoids C4512 (assignment operator could not be generated) | |
98 | processor_context & operator=( const processor_context & ); | |
99 | ||
100 | Scheduler & scheduler_; | |
101 | const processor_handle handle_; | |
102 | ||
103 | friend class processor_container; | |
104 | friend class event_processor< Scheduler >; | |
105 | }; | |
106 | ||
107 | template< class Processor > | |
108 | WorkItem create_processor( processor_handle & handle, Scheduler & scheduler ) | |
109 | { | |
110 | processor_holder_ptr_type pProcessor = make_processor_holder(); | |
111 | handle = pProcessor; | |
112 | typedef void ( processor_container::*impl_fun_ptr )( | |
113 | const processor_holder_ptr_type &, const processor_context & ); | |
114 | impl_fun_ptr pImpl = | |
115 | &processor_container::template create_processor_impl0< Processor >; | |
116 | return WorkItem( | |
117 | boost::bind( pImpl, this, pProcessor, | |
118 | processor_context( scheduler, handle ) ), | |
119 | Allocator() ); | |
120 | } | |
121 | ||
122 | template< class Processor, typename Arg1 > | |
123 | WorkItem create_processor( | |
124 | processor_handle & handle, Scheduler & scheduler, Arg1 arg1 ) | |
125 | { | |
126 | processor_holder_ptr_type pProcessor = make_processor_holder(); | |
127 | handle = pProcessor; | |
128 | typedef typename detail::unwrap< Arg1 >::type arg1_type; | |
129 | typedef void ( processor_container::*impl_fun_ptr )( | |
130 | const processor_holder_ptr_type &, const processor_context &, | |
131 | arg1_type ); | |
132 | impl_fun_ptr pImpl = | |
133 | &processor_container::template create_processor_impl1< | |
134 | Processor, arg1_type >; | |
135 | return WorkItem( | |
136 | boost::bind( pImpl, this, pProcessor, processor_context( scheduler, handle ), | |
137 | arg1 ), | |
138 | Allocator() ); | |
139 | } | |
140 | ||
141 | template< class Processor, typename Arg1, typename Arg2 > | |
142 | WorkItem create_processor( | |
143 | processor_handle & handle, Scheduler & scheduler, Arg1 arg1, Arg2 arg2 ) | |
144 | { | |
145 | processor_holder_ptr_type pProcessor = make_processor_holder(); | |
146 | handle = pProcessor; | |
147 | typedef typename detail::unwrap< Arg1 >::type arg1_type; | |
148 | typedef typename detail::unwrap< Arg2 >::type arg2_type; | |
149 | typedef void ( processor_container::*impl_fun_ptr )( | |
150 | const processor_holder_ptr_type &, const processor_context &, | |
151 | arg1_type, arg2_type ); | |
152 | impl_fun_ptr pImpl = | |
153 | &processor_container::template create_processor_impl2< | |
154 | Processor, arg1_type, arg2_type >; | |
155 | return WorkItem( | |
156 | boost::bind( pImpl, this, pProcessor, processor_context( scheduler, handle ), | |
157 | arg1, arg2 ), | |
158 | Allocator() ); | |
159 | } | |
160 | ||
161 | template< class Processor, typename Arg1, typename Arg2, typename Arg3 > | |
162 | WorkItem create_processor( | |
163 | processor_handle & handle, Scheduler & scheduler, | |
164 | Arg1 arg1, Arg2 arg2, Arg3 arg3 ) | |
165 | { | |
166 | processor_holder_ptr_type pProcessor = make_processor_holder(); | |
167 | handle = pProcessor; | |
168 | typedef typename detail::unwrap< Arg1 >::type arg1_type; | |
169 | typedef typename detail::unwrap< Arg2 >::type arg2_type; | |
170 | typedef typename detail::unwrap< Arg3 >::type arg3_type; | |
171 | typedef void ( processor_container::*impl_fun_ptr )( | |
172 | const processor_holder_ptr_type &, const processor_context &, | |
173 | arg1_type, arg2_type, arg3_type ); | |
174 | impl_fun_ptr pImpl = | |
175 | &processor_container::template create_processor_impl3< | |
176 | Processor, arg1_type, arg2_type, arg3_type >; | |
177 | return WorkItem( | |
178 | boost::bind( pImpl, this, pProcessor, processor_context( scheduler, handle ), | |
179 | arg1, arg2, arg3 ), | |
180 | Allocator() ); | |
181 | } | |
182 | ||
183 | template< | |
184 | class Processor, typename Arg1, typename Arg2, | |
185 | typename Arg3, typename Arg4 > | |
186 | WorkItem create_processor( | |
187 | processor_handle & handle, Scheduler & scheduler, | |
188 | Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4 ) | |
189 | { | |
190 | processor_holder_ptr_type pProcessor = make_processor_holder(); | |
191 | handle = pProcessor; | |
192 | typedef typename detail::unwrap< Arg1 >::type arg1_type; | |
193 | typedef typename detail::unwrap< Arg2 >::type arg2_type; | |
194 | typedef typename detail::unwrap< Arg3 >::type arg3_type; | |
195 | typedef typename detail::unwrap< Arg4 >::type arg4_type; | |
196 | typedef void ( processor_container::*impl_fun_ptr )( | |
197 | const processor_holder_ptr_type &, const processor_context &, | |
198 | arg1_type, arg2_type, arg3_type, arg4_type ); | |
199 | impl_fun_ptr pImpl = | |
200 | &processor_container::template create_processor_impl4< | |
201 | Processor, arg1_type, arg2_type, arg3_type, arg4_type >; | |
202 | return WorkItem( | |
203 | boost::bind( pImpl, this, pProcessor, processor_context( scheduler, handle ), | |
204 | arg1, arg2, arg3, arg4 ), | |
205 | Allocator() ); | |
206 | } | |
207 | ||
208 | template< | |
209 | class Processor, typename Arg1, typename Arg2, | |
210 | typename Arg3, typename Arg4, typename Arg5 > | |
211 | WorkItem create_processor( | |
212 | processor_handle & handle, Scheduler & scheduler, | |
213 | Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5 ) | |
214 | { | |
215 | processor_holder_ptr_type pProcessor = make_processor_holder(); | |
216 | handle = pProcessor; | |
217 | typedef typename detail::unwrap< Arg1 >::type arg1_type; | |
218 | typedef typename detail::unwrap< Arg2 >::type arg2_type; | |
219 | typedef typename detail::unwrap< Arg3 >::type arg3_type; | |
220 | typedef typename detail::unwrap< Arg4 >::type arg4_type; | |
221 | typedef typename detail::unwrap< Arg5 >::type arg5_type; | |
222 | typedef void ( processor_container::*impl_fun_ptr )( | |
223 | const processor_holder_ptr_type &, const processor_context &, | |
224 | arg1_type, arg2_type, arg3_type, arg4_type, arg5_type ); | |
225 | impl_fun_ptr pImpl = | |
226 | &processor_container::template create_processor_impl5< | |
227 | Processor, arg1_type, arg2_type, arg3_type, arg4_type, arg5_type >; | |
228 | return WorkItem( | |
229 | boost::bind( pImpl, this, pProcessor, processor_context( scheduler, handle ), | |
230 | arg1, arg2, arg3, arg4, arg5 ), | |
231 | Allocator() ); | |
232 | } | |
233 | ||
234 | template< | |
235 | class Processor, typename Arg1, typename Arg2, | |
236 | typename Arg3, typename Arg4, typename Arg5, typename Arg6 > | |
237 | WorkItem create_processor( | |
238 | processor_handle & handle, Scheduler & scheduler, | |
239 | Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5, Arg6 arg6 ) | |
240 | { | |
241 | processor_holder_ptr_type pProcessor = make_processor_holder(); | |
242 | handle = pProcessor; | |
243 | typedef typename detail::unwrap< Arg1 >::type arg1_type; | |
244 | typedef typename detail::unwrap< Arg2 >::type arg2_type; | |
245 | typedef typename detail::unwrap< Arg3 >::type arg3_type; | |
246 | typedef typename detail::unwrap< Arg4 >::type arg4_type; | |
247 | typedef typename detail::unwrap< Arg5 >::type arg5_type; | |
248 | typedef typename detail::unwrap< Arg6 >::type arg6_type; | |
249 | typedef void ( processor_container::*impl_fun_ptr )( | |
250 | const processor_holder_ptr_type &, const processor_context &, | |
251 | arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, arg6_type ); | |
252 | impl_fun_ptr pImpl = | |
253 | &processor_container::template create_processor_impl6< | |
254 | Processor, | |
255 | arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, arg6_type >; | |
256 | return WorkItem( | |
257 | boost::bind( pImpl, this, pProcessor, processor_context( scheduler, handle ), | |
258 | arg1, arg2, arg3, arg4, arg5, arg6 ), | |
259 | Allocator() ); | |
260 | } | |
261 | ||
262 | WorkItem destroy_processor( const processor_handle & processor ) | |
263 | { | |
264 | return WorkItem( | |
265 | boost::bind( &processor_container::destroy_processor_impl, this, processor ), | |
266 | Allocator() ); | |
267 | } | |
268 | ||
269 | WorkItem initiate_processor( const processor_handle & processor ) | |
270 | { | |
271 | return WorkItem( | |
272 | boost::bind( &processor_container::initiate_processor_impl, this, | |
273 | processor ), | |
274 | Allocator() ); | |
275 | } | |
276 | ||
277 | WorkItem terminate_processor( const processor_handle & processor ) | |
278 | { | |
279 | return WorkItem( | |
280 | boost::bind( &processor_container::terminate_processor_impl, this, | |
281 | processor ), | |
282 | Allocator() ); | |
283 | } | |
284 | ||
285 | typedef intrusive_ptr< const event_base > event_ptr_type; | |
286 | ||
287 | WorkItem queue_event( | |
288 | const processor_handle & processor, const event_ptr_type & pEvent ) | |
289 | { | |
290 | BOOST_ASSERT( pEvent.get() != 0 ); | |
291 | ||
292 | return WorkItem( | |
293 | boost::bind( &processor_container::queue_event_impl, this, processor, | |
294 | pEvent ), | |
295 | Allocator() ); | |
296 | } | |
297 | ||
298 | private: | |
299 | ////////////////////////////////////////////////////////////////////////// | |
300 | processor_holder_ptr_type make_processor_holder() | |
301 | { | |
302 | return processor_holder_ptr_type( new processor_holder_type() ); | |
303 | } | |
304 | ||
305 | template< class Processor > | |
306 | void create_processor_impl0( | |
307 | const processor_holder_ptr_type & pProcessor, | |
308 | const processor_context & context ) | |
309 | { | |
310 | processorSet_.insert( pProcessor ); | |
311 | processor_holder_type holder( new Processor( context ) ); | |
312 | *pProcessor = holder; | |
313 | } | |
314 | ||
315 | template< class Processor, typename Arg1 > | |
316 | void create_processor_impl1( | |
317 | const processor_holder_ptr_type & pProcessor, | |
318 | const processor_context & context, Arg1 arg1 ) | |
319 | { | |
320 | processorSet_.insert( pProcessor ); | |
321 | processor_holder_type holder( new Processor( context, arg1 ) ); | |
322 | *pProcessor = holder; | |
323 | } | |
324 | ||
325 | template< class Processor, typename Arg1, typename Arg2 > | |
326 | void create_processor_impl2( | |
327 | const processor_holder_ptr_type & pProcessor, | |
328 | const processor_context & context, Arg1 arg1, Arg2 arg2 ) | |
329 | { | |
330 | processorSet_.insert( pProcessor ); | |
331 | processor_holder_type holder( new Processor( context, arg1, arg2 ) ); | |
332 | *pProcessor = holder; | |
333 | } | |
334 | ||
335 | template< class Processor, typename Arg1, typename Arg2, typename Arg3 > | |
336 | void create_processor_impl3( | |
337 | const processor_holder_ptr_type & pProcessor, | |
338 | const processor_context & context, Arg1 arg1, Arg2 arg2, Arg3 arg3 ) | |
339 | { | |
340 | processorSet_.insert( pProcessor ); | |
341 | processor_holder_type holder( | |
342 | new Processor( context, arg1, arg2, arg3 ) ); | |
343 | *pProcessor = holder; | |
344 | } | |
345 | ||
346 | template< | |
347 | class Processor, typename Arg1, typename Arg2, | |
348 | typename Arg3, typename Arg4 > | |
349 | void create_processor_impl4( | |
350 | const processor_holder_ptr_type & pProcessor, | |
351 | const processor_context & context, | |
352 | Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4 ) | |
353 | { | |
354 | processorSet_.insert( pProcessor ); | |
355 | processor_holder_type holder( | |
356 | new Processor( context, arg1, arg2, arg3, arg4 ) ); | |
357 | *pProcessor = holder; | |
358 | } | |
359 | ||
360 | template< | |
361 | class Processor, typename Arg1, typename Arg2, | |
362 | typename Arg3, typename Arg4, typename Arg5 > | |
363 | void create_processor_impl5( | |
364 | const processor_holder_ptr_type & pProcessor, | |
365 | const processor_context & context, | |
366 | Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5 ) | |
367 | { | |
368 | processorSet_.insert( pProcessor ); | |
369 | processor_holder_type holder( | |
370 | new Processor( context, arg1, arg2, arg3, arg4, arg5 ) ); | |
371 | *pProcessor = holder; | |
372 | } | |
373 | ||
374 | template< | |
375 | class Processor, typename Arg1, typename Arg2, | |
376 | typename Arg3, typename Arg4, typename Arg5, typename Arg6 > | |
377 | void create_processor_impl6( | |
378 | const processor_holder_ptr_type & pProcessor, | |
379 | const processor_context & context, | |
380 | Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5, Arg6 arg6 ) | |
381 | { | |
382 | processorSet_.insert( pProcessor ); | |
383 | processor_holder_type holder( | |
384 | new Processor( context, arg1, arg2, arg3, arg4, arg5, arg6 ) ); | |
385 | *pProcessor = holder; | |
386 | } | |
387 | ||
388 | void destroy_processor_impl( const processor_handle & processor ) | |
389 | { | |
390 | const processor_holder_ptr_type pProcessor = processor.lock(); | |
391 | ||
392 | if ( pProcessor != 0 ) | |
393 | { | |
394 | processorSet_.erase( pProcessor ); | |
395 | } | |
396 | } | |
397 | ||
398 | void initiate_processor_impl( const processor_handle & processor ) | |
399 | { | |
400 | const processor_holder_ptr_type pProcessor = processor.lock(); | |
401 | ||
402 | if ( pProcessor != 0 ) | |
403 | { | |
404 | ( *pProcessor )->initiate(); | |
405 | } | |
406 | } | |
407 | ||
408 | void terminate_processor_impl( const processor_handle & processor ) | |
409 | { | |
410 | const processor_holder_ptr_type pProcessor = processor.lock(); | |
411 | ||
412 | if ( pProcessor != 0 ) | |
413 | { | |
414 | ( *pProcessor )->terminate(); | |
415 | } | |
416 | } | |
417 | ||
418 | void queue_event_impl( | |
419 | const processor_handle & processor, const event_ptr_type & pEvent ) | |
420 | { | |
421 | const processor_holder_ptr_type pProcessor = processor.lock(); | |
422 | ||
423 | if ( pProcessor != 0 ) | |
424 | { | |
425 | ( *pProcessor )->process_event( *pEvent ); | |
426 | } | |
427 | } | |
428 | ||
429 | typedef std::set< | |
430 | processor_holder_ptr_type, | |
431 | std::less< processor_holder_ptr_type >, | |
432 | typename boost::detail::allocator::rebind_to< | |
433 | Allocator, processor_holder_ptr_type >::type | |
434 | > event_processor_set_type; | |
435 | ||
436 | event_processor_set_type processorSet_; | |
437 | }; | |
438 | ||
439 | ||
440 | } // namespace statechart | |
441 | } // namespace boost | |
442 | ||
443 | ||
444 | ||
445 | #endif |