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