446 lines
15 KiB
C++
446 lines
15 KiB
C++
|
#ifndef BOOST_STATECHART_PROCESSOR_CONTAINER_HPP_INCLUDED
|
||
|
#define BOOST_STATECHART_PROCESSOR_CONTAINER_HPP_INCLUDED
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
// Copyright 2002-2008 Andreas Huber Doenni
|
||
|
// Distributed under the Boost Software License, Version 1.0. (See accompany-
|
||
|
// ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
|
||
|
|
||
|
#include <boost/statechart/event_base.hpp>
|
||
|
#include <boost/statechart/event_processor.hpp>
|
||
|
|
||
|
#include <boost/assert.hpp>
|
||
|
#include <boost/ref.hpp>
|
||
|
#include <boost/noncopyable.hpp>
|
||
|
#include <boost/intrusive_ptr.hpp>
|
||
|
#include <boost/shared_ptr.hpp>
|
||
|
#include <boost/weak_ptr.hpp>
|
||
|
#include <boost/bind.hpp>
|
||
|
#include <boost/config.hpp> // BOOST_INTEL
|
||
|
|
||
|
#include <boost/detail/workaround.hpp>
|
||
|
#include <boost/detail/allocator_utilities.hpp>
|
||
|
|
||
|
#include <set>
|
||
|
#include <memory> // std::allocator, std::auto_ptr
|
||
|
|
||
|
|
||
|
|
||
|
namespace boost
|
||
|
{
|
||
|
namespace statechart
|
||
|
{
|
||
|
namespace detail
|
||
|
{
|
||
|
template<bool IsReferenceWrapper>
|
||
|
struct unwrap_impl
|
||
|
{
|
||
|
template< typename T >
|
||
|
struct apply { typedef T type; };
|
||
|
};
|
||
|
|
||
|
template<>
|
||
|
struct unwrap_impl<true>
|
||
|
{
|
||
|
template< typename T >
|
||
|
struct apply { typedef typename T::type & type; };
|
||
|
};
|
||
|
|
||
|
template<typename T>
|
||
|
struct unwrap
|
||
|
{
|
||
|
typedef typename unwrap_impl<
|
||
|
is_reference_wrapper< T >::value >::template apply< T >::type type;
|
||
|
};
|
||
|
}
|
||
|
|
||
|
|
||
|
template<
|
||
|
class Scheduler,
|
||
|
class WorkItem,
|
||
|
class Allocator = std::allocator< void > >
|
||
|
class processor_container : noncopyable
|
||
|
{
|
||
|
typedef event_processor< Scheduler > processor_base_type;
|
||
|
typedef std::auto_ptr< processor_base_type > processor_holder_type;
|
||
|
typedef shared_ptr< processor_holder_type > processor_holder_ptr_type;
|
||
|
|
||
|
public:
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
typedef weak_ptr< processor_holder_type > processor_handle;
|
||
|
|
||
|
class processor_context
|
||
|
{
|
||
|
processor_context(
|
||
|
Scheduler & scheduler, const processor_handle & handle
|
||
|
) :
|
||
|
scheduler_( scheduler ),
|
||
|
handle_( handle )
|
||
|
{
|
||
|
}
|
||
|
|
||
|
#if BOOST_WORKAROUND( BOOST_INTEL, BOOST_TESTED_AT( 800 ) )
|
||
|
public:
|
||
|
// for some reason Intel 8.0 seems to think that the following functions
|
||
|
// are inaccessible from event_processor<>::event_processor
|
||
|
#endif
|
||
|
|
||
|
Scheduler & my_scheduler() const { return scheduler_; }
|
||
|
const processor_handle & my_handle() const { return handle_; }
|
||
|
|
||
|
#if BOOST_WORKAROUND( BOOST_INTEL, BOOST_TESTED_AT( 800 ) )
|
||
|
private:
|
||
|
#endif
|
||
|
|
||
|
// avoids C4512 (assignment operator could not be generated)
|
||
|
processor_context & operator=( const processor_context & );
|
||
|
|
||
|
Scheduler & scheduler_;
|
||
|
const processor_handle handle_;
|
||
|
|
||
|
friend class processor_container;
|
||
|
friend class event_processor< Scheduler >;
|
||
|
};
|
||
|
|
||
|
template< class Processor >
|
||
|
WorkItem create_processor( processor_handle & handle, Scheduler & scheduler )
|
||
|
{
|
||
|
processor_holder_ptr_type pProcessor = make_processor_holder();
|
||
|
handle = pProcessor;
|
||
|
typedef void ( processor_container::*impl_fun_ptr )(
|
||
|
const processor_holder_ptr_type &, const processor_context & );
|
||
|
impl_fun_ptr pImpl =
|
||
|
&processor_container::template create_processor_impl0< Processor >;
|
||
|
return WorkItem(
|
||
|
boost::bind( pImpl, this, pProcessor,
|
||
|
processor_context( scheduler, handle ) ),
|
||
|
Allocator() );
|
||
|
}
|
||
|
|
||
|
template< class Processor, typename Arg1 >
|
||
|
WorkItem create_processor(
|
||
|
processor_handle & handle, Scheduler & scheduler, Arg1 arg1 )
|
||
|
{
|
||
|
processor_holder_ptr_type pProcessor = make_processor_holder();
|
||
|
handle = pProcessor;
|
||
|
typedef typename detail::unwrap< Arg1 >::type arg1_type;
|
||
|
typedef void ( processor_container::*impl_fun_ptr )(
|
||
|
const processor_holder_ptr_type &, const processor_context &,
|
||
|
arg1_type );
|
||
|
impl_fun_ptr pImpl =
|
||
|
&processor_container::template create_processor_impl1<
|
||
|
Processor, arg1_type >;
|
||
|
return WorkItem(
|
||
|
boost::bind( pImpl, this, pProcessor, processor_context( scheduler, handle ),
|
||
|
arg1 ),
|
||
|
Allocator() );
|
||
|
}
|
||
|
|
||
|
template< class Processor, typename Arg1, typename Arg2 >
|
||
|
WorkItem create_processor(
|
||
|
processor_handle & handle, Scheduler & scheduler, Arg1 arg1, Arg2 arg2 )
|
||
|
{
|
||
|
processor_holder_ptr_type pProcessor = make_processor_holder();
|
||
|
handle = pProcessor;
|
||
|
typedef typename detail::unwrap< Arg1 >::type arg1_type;
|
||
|
typedef typename detail::unwrap< Arg2 >::type arg2_type;
|
||
|
typedef void ( processor_container::*impl_fun_ptr )(
|
||
|
const processor_holder_ptr_type &, const processor_context &,
|
||
|
arg1_type, arg2_type );
|
||
|
impl_fun_ptr pImpl =
|
||
|
&processor_container::template create_processor_impl2<
|
||
|
Processor, arg1_type, arg2_type >;
|
||
|
return WorkItem(
|
||
|
boost::bind( pImpl, this, pProcessor, processor_context( scheduler, handle ),
|
||
|
arg1, arg2 ),
|
||
|
Allocator() );
|
||
|
}
|
||
|
|
||
|
template< class Processor, typename Arg1, typename Arg2, typename Arg3 >
|
||
|
WorkItem create_processor(
|
||
|
processor_handle & handle, Scheduler & scheduler,
|
||
|
Arg1 arg1, Arg2 arg2, Arg3 arg3 )
|
||
|
{
|
||
|
processor_holder_ptr_type pProcessor = make_processor_holder();
|
||
|
handle = pProcessor;
|
||
|
typedef typename detail::unwrap< Arg1 >::type arg1_type;
|
||
|
typedef typename detail::unwrap< Arg2 >::type arg2_type;
|
||
|
typedef typename detail::unwrap< Arg3 >::type arg3_type;
|
||
|
typedef void ( processor_container::*impl_fun_ptr )(
|
||
|
const processor_holder_ptr_type &, const processor_context &,
|
||
|
arg1_type, arg2_type, arg3_type );
|
||
|
impl_fun_ptr pImpl =
|
||
|
&processor_container::template create_processor_impl3<
|
||
|
Processor, arg1_type, arg2_type, arg3_type >;
|
||
|
return WorkItem(
|
||
|
boost::bind( pImpl, this, pProcessor, processor_context( scheduler, handle ),
|
||
|
arg1, arg2, arg3 ),
|
||
|
Allocator() );
|
||
|
}
|
||
|
|
||
|
template<
|
||
|
class Processor, typename Arg1, typename Arg2,
|
||
|
typename Arg3, typename Arg4 >
|
||
|
WorkItem create_processor(
|
||
|
processor_handle & handle, Scheduler & scheduler,
|
||
|
Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4 )
|
||
|
{
|
||
|
processor_holder_ptr_type pProcessor = make_processor_holder();
|
||
|
handle = pProcessor;
|
||
|
typedef typename detail::unwrap< Arg1 >::type arg1_type;
|
||
|
typedef typename detail::unwrap< Arg2 >::type arg2_type;
|
||
|
typedef typename detail::unwrap< Arg3 >::type arg3_type;
|
||
|
typedef typename detail::unwrap< Arg4 >::type arg4_type;
|
||
|
typedef void ( processor_container::*impl_fun_ptr )(
|
||
|
const processor_holder_ptr_type &, const processor_context &,
|
||
|
arg1_type, arg2_type, arg3_type, arg4_type );
|
||
|
impl_fun_ptr pImpl =
|
||
|
&processor_container::template create_processor_impl4<
|
||
|
Processor, arg1_type, arg2_type, arg3_type, arg4_type >;
|
||
|
return WorkItem(
|
||
|
boost::bind( pImpl, this, pProcessor, processor_context( scheduler, handle ),
|
||
|
arg1, arg2, arg3, arg4 ),
|
||
|
Allocator() );
|
||
|
}
|
||
|
|
||
|
template<
|
||
|
class Processor, typename Arg1, typename Arg2,
|
||
|
typename Arg3, typename Arg4, typename Arg5 >
|
||
|
WorkItem create_processor(
|
||
|
processor_handle & handle, Scheduler & scheduler,
|
||
|
Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5 )
|
||
|
{
|
||
|
processor_holder_ptr_type pProcessor = make_processor_holder();
|
||
|
handle = pProcessor;
|
||
|
typedef typename detail::unwrap< Arg1 >::type arg1_type;
|
||
|
typedef typename detail::unwrap< Arg2 >::type arg2_type;
|
||
|
typedef typename detail::unwrap< Arg3 >::type arg3_type;
|
||
|
typedef typename detail::unwrap< Arg4 >::type arg4_type;
|
||
|
typedef typename detail::unwrap< Arg5 >::type arg5_type;
|
||
|
typedef void ( processor_container::*impl_fun_ptr )(
|
||
|
const processor_holder_ptr_type &, const processor_context &,
|
||
|
arg1_type, arg2_type, arg3_type, arg4_type, arg5_type );
|
||
|
impl_fun_ptr pImpl =
|
||
|
&processor_container::template create_processor_impl5<
|
||
|
Processor, arg1_type, arg2_type, arg3_type, arg4_type, arg5_type >;
|
||
|
return WorkItem(
|
||
|
boost::bind( pImpl, this, pProcessor, processor_context( scheduler, handle ),
|
||
|
arg1, arg2, arg3, arg4, arg5 ),
|
||
|
Allocator() );
|
||
|
}
|
||
|
|
||
|
template<
|
||
|
class Processor, typename Arg1, typename Arg2,
|
||
|
typename Arg3, typename Arg4, typename Arg5, typename Arg6 >
|
||
|
WorkItem create_processor(
|
||
|
processor_handle & handle, Scheduler & scheduler,
|
||
|
Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5, Arg6 arg6 )
|
||
|
{
|
||
|
processor_holder_ptr_type pProcessor = make_processor_holder();
|
||
|
handle = pProcessor;
|
||
|
typedef typename detail::unwrap< Arg1 >::type arg1_type;
|
||
|
typedef typename detail::unwrap< Arg2 >::type arg2_type;
|
||
|
typedef typename detail::unwrap< Arg3 >::type arg3_type;
|
||
|
typedef typename detail::unwrap< Arg4 >::type arg4_type;
|
||
|
typedef typename detail::unwrap< Arg5 >::type arg5_type;
|
||
|
typedef typename detail::unwrap< Arg6 >::type arg6_type;
|
||
|
typedef void ( processor_container::*impl_fun_ptr )(
|
||
|
const processor_holder_ptr_type &, const processor_context &,
|
||
|
arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, arg6_type );
|
||
|
impl_fun_ptr pImpl =
|
||
|
&processor_container::template create_processor_impl6<
|
||
|
Processor,
|
||
|
arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, arg6_type >;
|
||
|
return WorkItem(
|
||
|
boost::bind( pImpl, this, pProcessor, processor_context( scheduler, handle ),
|
||
|
arg1, arg2, arg3, arg4, arg5, arg6 ),
|
||
|
Allocator() );
|
||
|
}
|
||
|
|
||
|
WorkItem destroy_processor( const processor_handle & processor )
|
||
|
{
|
||
|
return WorkItem(
|
||
|
boost::bind( &processor_container::destroy_processor_impl, this, processor ),
|
||
|
Allocator() );
|
||
|
}
|
||
|
|
||
|
WorkItem initiate_processor( const processor_handle & processor )
|
||
|
{
|
||
|
return WorkItem(
|
||
|
boost::bind( &processor_container::initiate_processor_impl, this,
|
||
|
processor ),
|
||
|
Allocator() );
|
||
|
}
|
||
|
|
||
|
WorkItem terminate_processor( const processor_handle & processor )
|
||
|
{
|
||
|
return WorkItem(
|
||
|
boost::bind( &processor_container::terminate_processor_impl, this,
|
||
|
processor ),
|
||
|
Allocator() );
|
||
|
}
|
||
|
|
||
|
typedef intrusive_ptr< const event_base > event_ptr_type;
|
||
|
|
||
|
WorkItem queue_event(
|
||
|
const processor_handle & processor, const event_ptr_type & pEvent )
|
||
|
{
|
||
|
BOOST_ASSERT( pEvent.get() != 0 );
|
||
|
|
||
|
return WorkItem(
|
||
|
boost::bind( &processor_container::queue_event_impl, this, processor,
|
||
|
pEvent ),
|
||
|
Allocator() );
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
processor_holder_ptr_type make_processor_holder()
|
||
|
{
|
||
|
return processor_holder_ptr_type( new processor_holder_type() );
|
||
|
}
|
||
|
|
||
|
template< class Processor >
|
||
|
void create_processor_impl0(
|
||
|
const processor_holder_ptr_type & pProcessor,
|
||
|
const processor_context & context )
|
||
|
{
|
||
|
processorSet_.insert( pProcessor );
|
||
|
processor_holder_type holder( new Processor( context ) );
|
||
|
*pProcessor = holder;
|
||
|
}
|
||
|
|
||
|
template< class Processor, typename Arg1 >
|
||
|
void create_processor_impl1(
|
||
|
const processor_holder_ptr_type & pProcessor,
|
||
|
const processor_context & context, Arg1 arg1 )
|
||
|
{
|
||
|
processorSet_.insert( pProcessor );
|
||
|
processor_holder_type holder( new Processor( context, arg1 ) );
|
||
|
*pProcessor = holder;
|
||
|
}
|
||
|
|
||
|
template< class Processor, typename Arg1, typename Arg2 >
|
||
|
void create_processor_impl2(
|
||
|
const processor_holder_ptr_type & pProcessor,
|
||
|
const processor_context & context, Arg1 arg1, Arg2 arg2 )
|
||
|
{
|
||
|
processorSet_.insert( pProcessor );
|
||
|
processor_holder_type holder( new Processor( context, arg1, arg2 ) );
|
||
|
*pProcessor = holder;
|
||
|
}
|
||
|
|
||
|
template< class Processor, typename Arg1, typename Arg2, typename Arg3 >
|
||
|
void create_processor_impl3(
|
||
|
const processor_holder_ptr_type & pProcessor,
|
||
|
const processor_context & context, Arg1 arg1, Arg2 arg2, Arg3 arg3 )
|
||
|
{
|
||
|
processorSet_.insert( pProcessor );
|
||
|
processor_holder_type holder(
|
||
|
new Processor( context, arg1, arg2, arg3 ) );
|
||
|
*pProcessor = holder;
|
||
|
}
|
||
|
|
||
|
template<
|
||
|
class Processor, typename Arg1, typename Arg2,
|
||
|
typename Arg3, typename Arg4 >
|
||
|
void create_processor_impl4(
|
||
|
const processor_holder_ptr_type & pProcessor,
|
||
|
const processor_context & context,
|
||
|
Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4 )
|
||
|
{
|
||
|
processorSet_.insert( pProcessor );
|
||
|
processor_holder_type holder(
|
||
|
new Processor( context, arg1, arg2, arg3, arg4 ) );
|
||
|
*pProcessor = holder;
|
||
|
}
|
||
|
|
||
|
template<
|
||
|
class Processor, typename Arg1, typename Arg2,
|
||
|
typename Arg3, typename Arg4, typename Arg5 >
|
||
|
void create_processor_impl5(
|
||
|
const processor_holder_ptr_type & pProcessor,
|
||
|
const processor_context & context,
|
||
|
Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5 )
|
||
|
{
|
||
|
processorSet_.insert( pProcessor );
|
||
|
processor_holder_type holder(
|
||
|
new Processor( context, arg1, arg2, arg3, arg4, arg5 ) );
|
||
|
*pProcessor = holder;
|
||
|
}
|
||
|
|
||
|
template<
|
||
|
class Processor, typename Arg1, typename Arg2,
|
||
|
typename Arg3, typename Arg4, typename Arg5, typename Arg6 >
|
||
|
void 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 )
|
||
|
{
|
||
|
processorSet_.insert( pProcessor );
|
||
|
processor_holder_type holder(
|
||
|
new Processor( context, arg1, arg2, arg3, arg4, arg5, arg6 ) );
|
||
|
*pProcessor = holder;
|
||
|
}
|
||
|
|
||
|
void destroy_processor_impl( const processor_handle & processor )
|
||
|
{
|
||
|
const processor_holder_ptr_type pProcessor = processor.lock();
|
||
|
|
||
|
if ( pProcessor != 0 )
|
||
|
{
|
||
|
processorSet_.erase( pProcessor );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void initiate_processor_impl( const processor_handle & processor )
|
||
|
{
|
||
|
const processor_holder_ptr_type pProcessor = processor.lock();
|
||
|
|
||
|
if ( pProcessor != 0 )
|
||
|
{
|
||
|
( *pProcessor )->initiate();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void terminate_processor_impl( const processor_handle & processor )
|
||
|
{
|
||
|
const processor_holder_ptr_type pProcessor = processor.lock();
|
||
|
|
||
|
if ( pProcessor != 0 )
|
||
|
{
|
||
|
( *pProcessor )->terminate();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void queue_event_impl(
|
||
|
const processor_handle & processor, const event_ptr_type & pEvent )
|
||
|
{
|
||
|
const processor_holder_ptr_type pProcessor = processor.lock();
|
||
|
|
||
|
if ( pProcessor != 0 )
|
||
|
{
|
||
|
( *pProcessor )->process_event( *pEvent );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
typedef std::set<
|
||
|
processor_holder_ptr_type,
|
||
|
std::less< processor_holder_ptr_type >,
|
||
|
typename boost::detail::allocator::rebind_to<
|
||
|
Allocator, processor_holder_ptr_type >::type
|
||
|
> event_processor_set_type;
|
||
|
|
||
|
event_processor_set_type processorSet_;
|
||
|
};
|
||
|
|
||
|
|
||
|
} // namespace statechart
|
||
|
} // namespace boost
|
||
|
|
||
|
|
||
|
|
||
|
#endif
|