• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::unique_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< none > >
64 class processor_container : noncopyable
65 {
66   typedef event_processor< Scheduler > processor_base_type;
67 #ifdef BOOST_NO_AUTO_PTR
68   typedef std::unique_ptr< processor_base_type > processor_holder_type;
69 #else
70   typedef std::auto_ptr< processor_base_type > processor_holder_type;
71 #endif
72   typedef shared_ptr< processor_holder_type > processor_holder_ptr_type;
73 
74   public:
75     //////////////////////////////////////////////////////////////////////////
76     typedef weak_ptr< processor_holder_type > processor_handle;
77 
78     class processor_context
79     {
processor_context(Scheduler & scheduler,const processor_handle & handle)80         processor_context(
81           Scheduler & scheduler, const processor_handle & handle
82         ) :
83           scheduler_( scheduler ),
84           handle_( handle )
85         {
86         }
87 
88       #if BOOST_WORKAROUND( BOOST_INTEL, BOOST_TESTED_AT( 800 ) )
89       public:
90       // for some reason Intel 8.0 seems to think that the following functions
91       // are inaccessible from event_processor<>::event_processor
92       #endif
93 
my_scheduler() const94         Scheduler & my_scheduler() const { return scheduler_; }
my_handle() const95         const processor_handle & my_handle() const { return handle_; }
96 
97       #if BOOST_WORKAROUND( BOOST_INTEL, BOOST_TESTED_AT( 800 ) )
98       private:
99       #endif
100 
101         // avoids C4512 (assignment operator could not be generated)
102         processor_context & operator=( const processor_context & );
103 
104         Scheduler & scheduler_;
105         const processor_handle handle_;
106 
107         friend class processor_container;
108         friend class event_processor< Scheduler >;
109     };
110 
111     template< class Processor >
create_processor(processor_handle & handle,Scheduler & scheduler)112     WorkItem create_processor( processor_handle & handle, Scheduler & scheduler )
113     {
114       processor_holder_ptr_type pProcessor = make_processor_holder();
115       handle = pProcessor;
116       typedef void ( processor_container::*impl_fun_ptr )(
117         const processor_holder_ptr_type &, const processor_context & );
118       impl_fun_ptr pImpl =
119         &processor_container::template create_processor_impl0< Processor >;
120       return WorkItem(
121         boost::bind( pImpl, this, pProcessor,
122           processor_context( scheduler, handle ) ),
123         Allocator() );
124     }
125 
126     template< class Processor, typename Arg1 >
create_processor(processor_handle & handle,Scheduler & scheduler,Arg1 arg1)127     WorkItem create_processor(
128       processor_handle & handle, Scheduler & scheduler, Arg1 arg1 )
129     {
130       processor_holder_ptr_type pProcessor = make_processor_holder();
131       handle = pProcessor;
132       typedef typename detail::unwrap< Arg1 >::type arg1_type;
133       typedef void ( processor_container::*impl_fun_ptr )(
134         const processor_holder_ptr_type &, const processor_context &,
135         arg1_type );
136       impl_fun_ptr pImpl =
137         &processor_container::template create_processor_impl1<
138           Processor, arg1_type >;
139       return WorkItem(
140         boost::bind( pImpl, this, pProcessor, processor_context( scheduler, handle ),
141           arg1 ),
142         Allocator() );
143     }
144 
145     template< class Processor, typename Arg1, typename Arg2 >
create_processor(processor_handle & handle,Scheduler & scheduler,Arg1 arg1,Arg2 arg2)146     WorkItem create_processor(
147       processor_handle & handle, Scheduler & scheduler, Arg1 arg1, Arg2 arg2 )
148     {
149       processor_holder_ptr_type pProcessor = make_processor_holder();
150       handle = pProcessor;
151       typedef typename detail::unwrap< Arg1 >::type arg1_type;
152       typedef typename detail::unwrap< Arg2 >::type arg2_type;
153       typedef void ( processor_container::*impl_fun_ptr )(
154         const processor_holder_ptr_type &, const processor_context &,
155          arg1_type, arg2_type );
156       impl_fun_ptr pImpl =
157         &processor_container::template create_processor_impl2<
158           Processor, arg1_type, arg2_type >;
159       return WorkItem(
160         boost::bind( pImpl, this, pProcessor, processor_context( scheduler, handle ),
161           arg1, arg2 ),
162         Allocator() );
163     }
164 
165     template< class Processor, typename Arg1, typename Arg2, typename Arg3 >
create_processor(processor_handle & handle,Scheduler & scheduler,Arg1 arg1,Arg2 arg2,Arg3 arg3)166     WorkItem create_processor(
167       processor_handle & handle, Scheduler & scheduler,
168       Arg1 arg1, Arg2 arg2, Arg3 arg3 )
169     {
170       processor_holder_ptr_type pProcessor = make_processor_holder();
171       handle = pProcessor;
172       typedef typename detail::unwrap< Arg1 >::type arg1_type;
173       typedef typename detail::unwrap< Arg2 >::type arg2_type;
174       typedef typename detail::unwrap< Arg3 >::type arg3_type;
175       typedef void ( processor_container::*impl_fun_ptr )(
176         const processor_holder_ptr_type &, const processor_context &,
177         arg1_type, arg2_type, arg3_type );
178       impl_fun_ptr pImpl =
179         &processor_container::template create_processor_impl3<
180           Processor, arg1_type, arg2_type, arg3_type >;
181       return WorkItem(
182         boost::bind( pImpl, this, pProcessor, processor_context( scheduler, handle ),
183           arg1, arg2, arg3 ),
184         Allocator() );
185     }
186 
187     template<
188       class Processor, typename Arg1, typename Arg2,
189       typename Arg3, typename Arg4 >
create_processor(processor_handle & handle,Scheduler & scheduler,Arg1 arg1,Arg2 arg2,Arg3 arg3,Arg4 arg4)190     WorkItem create_processor(
191       processor_handle & handle, Scheduler & scheduler,
192       Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4 )
193     {
194       processor_holder_ptr_type pProcessor = make_processor_holder();
195       handle = pProcessor;
196       typedef typename detail::unwrap< Arg1 >::type arg1_type;
197       typedef typename detail::unwrap< Arg2 >::type arg2_type;
198       typedef typename detail::unwrap< Arg3 >::type arg3_type;
199       typedef typename detail::unwrap< Arg4 >::type arg4_type;
200       typedef void ( processor_container::*impl_fun_ptr )(
201         const processor_holder_ptr_type &, const processor_context &,
202         arg1_type, arg2_type, arg3_type, arg4_type );
203       impl_fun_ptr pImpl =
204         &processor_container::template create_processor_impl4<
205           Processor, arg1_type, arg2_type, arg3_type, arg4_type >;
206       return WorkItem(
207         boost::bind( pImpl, this, pProcessor, processor_context( scheduler, handle ),
208           arg1, arg2, arg3, arg4 ),
209         Allocator() );
210     }
211 
212     template<
213       class Processor, typename Arg1, typename Arg2,
214       typename Arg3, typename Arg4, typename Arg5 >
create_processor(processor_handle & handle,Scheduler & scheduler,Arg1 arg1,Arg2 arg2,Arg3 arg3,Arg4 arg4,Arg5 arg5)215     WorkItem create_processor(
216       processor_handle & handle, Scheduler & scheduler,
217       Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5 )
218     {
219       processor_holder_ptr_type pProcessor = make_processor_holder();
220       handle = pProcessor;
221       typedef typename detail::unwrap< Arg1 >::type arg1_type;
222       typedef typename detail::unwrap< Arg2 >::type arg2_type;
223       typedef typename detail::unwrap< Arg3 >::type arg3_type;
224       typedef typename detail::unwrap< Arg4 >::type arg4_type;
225       typedef typename detail::unwrap< Arg5 >::type arg5_type;
226       typedef void ( processor_container::*impl_fun_ptr )(
227         const processor_holder_ptr_type &, const processor_context &,
228         arg1_type, arg2_type, arg3_type, arg4_type, arg5_type );
229       impl_fun_ptr pImpl =
230         &processor_container::template create_processor_impl5<
231           Processor, arg1_type, arg2_type, arg3_type, arg4_type, arg5_type >;
232       return WorkItem(
233         boost::bind( pImpl, this, pProcessor, processor_context( scheduler, handle ),
234           arg1, arg2, arg3, arg4, arg5 ),
235         Allocator() );
236     }
237 
238     template<
239       class Processor, typename Arg1, typename Arg2,
240       typename Arg3, typename Arg4, typename Arg5, typename Arg6 >
create_processor(processor_handle & handle,Scheduler & scheduler,Arg1 arg1,Arg2 arg2,Arg3 arg3,Arg4 arg4,Arg5 arg5,Arg6 arg6)241     WorkItem create_processor(
242       processor_handle & handle, Scheduler & scheduler,
243       Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5, Arg6 arg6 )
244     {
245       processor_holder_ptr_type pProcessor = make_processor_holder();
246       handle = pProcessor;
247       typedef typename detail::unwrap< Arg1 >::type arg1_type;
248       typedef typename detail::unwrap< Arg2 >::type arg2_type;
249       typedef typename detail::unwrap< Arg3 >::type arg3_type;
250       typedef typename detail::unwrap< Arg4 >::type arg4_type;
251       typedef typename detail::unwrap< Arg5 >::type arg5_type;
252       typedef typename detail::unwrap< Arg6 >::type arg6_type;
253       typedef void ( processor_container::*impl_fun_ptr )(
254         const processor_holder_ptr_type &, const processor_context &,
255         arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, arg6_type );
256       impl_fun_ptr pImpl =
257         &processor_container::template create_processor_impl6<
258           Processor,
259           arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, arg6_type >;
260       return WorkItem(
261         boost::bind( pImpl, this, pProcessor, processor_context( scheduler, handle ),
262           arg1, arg2, arg3, arg4, arg5, arg6 ),
263         Allocator() );
264     }
265 
destroy_processor(const processor_handle & processor)266     WorkItem destroy_processor( const processor_handle & processor )
267     {
268       return WorkItem(
269         boost::bind( &processor_container::destroy_processor_impl, this, processor ),
270         Allocator() );
271     }
272 
initiate_processor(const processor_handle & processor)273     WorkItem initiate_processor( const processor_handle & processor )
274     {
275       return WorkItem(
276         boost::bind( &processor_container::initiate_processor_impl, this,
277           processor ),
278         Allocator() );
279     }
280 
terminate_processor(const processor_handle & processor)281     WorkItem terminate_processor( const processor_handle & processor )
282     {
283       return WorkItem(
284         boost::bind( &processor_container::terminate_processor_impl, this,
285           processor ),
286         Allocator() );
287     }
288 
289     typedef intrusive_ptr< const event_base > event_ptr_type;
290 
queue_event(const processor_handle & processor,const event_ptr_type & pEvent)291     WorkItem queue_event(
292       const processor_handle & processor, const event_ptr_type & pEvent )
293     {
294       BOOST_ASSERT( pEvent.get() != 0 );
295 
296       return WorkItem(
297         boost::bind( &processor_container::queue_event_impl, this, processor,
298           pEvent ),
299         Allocator() );
300     }
301 
302   private:
303     //////////////////////////////////////////////////////////////////////////
make_processor_holder()304     processor_holder_ptr_type make_processor_holder()
305     {
306       return processor_holder_ptr_type( new processor_holder_type() );
307     }
308 
309     template< class Processor >
create_processor_impl0(const processor_holder_ptr_type & pProcessor,const processor_context & context)310     void create_processor_impl0(
311       const processor_holder_ptr_type & pProcessor,
312       const processor_context & context )
313     {
314       processorSet_.insert( pProcessor );
315       *pProcessor = processor_holder_type( new Processor( context ) );
316     }
317 
318     template< class Processor, typename Arg1 >
create_processor_impl1(const processor_holder_ptr_type & pProcessor,const processor_context & context,Arg1 arg1)319     void create_processor_impl1(
320       const processor_holder_ptr_type & pProcessor,
321       const processor_context & context, Arg1 arg1 )
322     {
323       processorSet_.insert( pProcessor );
324       *pProcessor = processor_holder_type( new Processor( context, arg1 ) );
325     }
326 
327     template< class Processor, typename Arg1, typename Arg2 >
create_processor_impl2(const processor_holder_ptr_type & pProcessor,const processor_context & context,Arg1 arg1,Arg2 arg2)328     void create_processor_impl2(
329       const processor_holder_ptr_type & pProcessor,
330       const processor_context & context, Arg1 arg1, Arg2 arg2 )
331     {
332       processorSet_.insert( pProcessor );
333       *pProcessor = processor_holder_type( new Processor( context, arg1, arg2 ) );
334     }
335 
336     template< class Processor, typename Arg1, typename Arg2, typename Arg3 >
create_processor_impl3(const processor_holder_ptr_type & pProcessor,const processor_context & context,Arg1 arg1,Arg2 arg2,Arg3 arg3)337     void create_processor_impl3(
338       const processor_holder_ptr_type & pProcessor,
339       const processor_context & context, Arg1 arg1, Arg2 arg2, Arg3 arg3 )
340     {
341       processorSet_.insert( pProcessor );
342       *pProcessor = processor_holder_type( new Processor( context, arg1, arg2, arg3 ) );
343     }
344 
345     template<
346       class Processor, typename Arg1, typename Arg2,
347       typename Arg3, typename Arg4 >
create_processor_impl4(const processor_holder_ptr_type & pProcessor,const processor_context & context,Arg1 arg1,Arg2 arg2,Arg3 arg3,Arg4 arg4)348     void create_processor_impl4(
349       const processor_holder_ptr_type & pProcessor,
350       const processor_context & context,
351       Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4 )
352     {
353       processorSet_.insert( pProcessor );
354       *pProcessor = processor_holder_type( new Processor( context, arg1, arg2, arg3, arg4 ) );
355     }
356 
357     template<
358       class Processor, typename Arg1, typename Arg2,
359       typename Arg3, typename Arg4, typename Arg5 >
create_processor_impl5(const processor_holder_ptr_type & pProcessor,const processor_context & context,Arg1 arg1,Arg2 arg2,Arg3 arg3,Arg4 arg4,Arg5 arg5)360     void create_processor_impl5(
361       const processor_holder_ptr_type & pProcessor,
362       const processor_context & context,
363       Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5 )
364     {
365       processorSet_.insert( pProcessor );
366       *pProcessor = processor_holder_type( new Processor( context, arg1, arg2, arg3, arg4, arg5 ) );
367     }
368 
369     template<
370       class Processor, typename Arg1, typename Arg2,
371       typename Arg3, typename Arg4, typename Arg5, typename Arg6 >
create_processor_impl6(const processor_holder_ptr_type & pProcessor,const processor_context & context,Arg1 arg1,Arg2 arg2,Arg3 arg3,Arg4 arg4,Arg5 arg5,Arg6 arg6)372     void create_processor_impl6(
373       const processor_holder_ptr_type & pProcessor,
374       const processor_context & context,
375       Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5, Arg6 arg6 )
376     {
377       processorSet_.insert( pProcessor );
378       *pProcessor = processor_holder_type( new Processor( context, arg1, arg2, arg3, arg4, arg5, arg6 ) );
379     }
380 
destroy_processor_impl(const processor_handle & processor)381     void destroy_processor_impl( const processor_handle & processor )
382     {
383       const processor_holder_ptr_type pProcessor = processor.lock();
384 
385       if ( pProcessor != 0 )
386       {
387         processorSet_.erase( pProcessor );
388       }
389     }
390 
initiate_processor_impl(const processor_handle & processor)391     void initiate_processor_impl( const processor_handle & processor )
392     {
393       const processor_holder_ptr_type pProcessor = processor.lock();
394 
395       if ( pProcessor != 0 )
396       {
397         ( *pProcessor )->initiate();
398       }
399     }
400 
terminate_processor_impl(const processor_handle & processor)401     void terminate_processor_impl( const processor_handle & processor )
402     {
403       const processor_holder_ptr_type pProcessor = processor.lock();
404 
405       if ( pProcessor != 0 )
406       {
407         ( *pProcessor )->terminate();
408       }
409     }
410 
queue_event_impl(const processor_handle & processor,const event_ptr_type & pEvent)411     void queue_event_impl(
412       const processor_handle & processor, const event_ptr_type & pEvent )
413     {
414       const processor_holder_ptr_type pProcessor = processor.lock();
415 
416       if ( pProcessor != 0 )
417       {
418         ( *pProcessor )->process_event( *pEvent );
419       }
420     }
421 
422     typedef std::set<
423       processor_holder_ptr_type,
424       std::less< processor_holder_ptr_type >,
425       typename boost::detail::allocator::rebind_to<
426         Allocator, processor_holder_ptr_type >::type
427     > event_processor_set_type;
428 
429     event_processor_set_type processorSet_;
430 };
431 
432 
433 } // namespace statechart
434 } // namespace boost
435 
436 
437 
438 #endif
439