diff options
Diffstat (limited to 'src/boost/libs/statechart/example/BitMachine/BitMachine.cpp')
-rw-r--r-- | src/boost/libs/statechart/example/BitMachine/BitMachine.cpp | 264 |
1 files changed, 264 insertions, 0 deletions
diff --git a/src/boost/libs/statechart/example/BitMachine/BitMachine.cpp b/src/boost/libs/statechart/example/BitMachine/BitMachine.cpp new file mode 100644 index 000000000..89478a5a4 --- /dev/null +++ b/src/boost/libs/statechart/example/BitMachine/BitMachine.cpp @@ -0,0 +1,264 @@ +////////////////////////////////////////////////////////////////////////////// +// Copyright 2002-2006 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) +////////////////////////////////////////////////////////////////////////////// + + + +////////////////////////////////////////////////////////////////////////////// +#define NO_OF_BITS 3 +////////////////////////////////////////////////////////////////////////////// +// This program demonstrates the fact that measures must be taken to hide some +// of the complexity (e.g. in separate .cpp file) of a Boost.Statechart state +// machine once a certain size is reached. +// For this purpose, a state machine with exactly 2^NO_OF_BITS states (i.e. +// BitState< 0 > .. BitState< 2^NO_OF_BITS - 1 >) is generated. For the events +// EvFlipBit< 0 > .. EvFlipBit< NO_OF_BITS - 1 > there is a transition from +// each state to the state with the corresponding bit toggled. That is, there +// is a total of 2^NO_OF_BITS * NO_OF_BITS transitions. +// E.g. if the state machine is currently in state BitState< 5 > and receives +// EvFlipBit< 2 >, it transitions to state BitState< 1 >. If it is in +// BitState< 15 > and receives EvFlipBit< 4 > it transitions to BitState< 31 > +// etc. +// The maximum size of such a state machine depends on your compiler. The +// following table gives upper limits for NO_OF_BITS. From this, rough +// estimates for the maximum size of any "naively" implemented Boost.Statechart +// machine (i.e. no attempt is made to hide inner state implementation in a +// .cpp file) can be deduced. +// +// NOTE: Due to the fact that the amount of generated code more than +// *doubles* each time NO_OF_BITS is *incremented*, build times on most +// compilers soar when NO_OF_BITS > 6. +// +// Compiler | max. NO_OF_BITS b | max. states s | +// --------------|-------------------|----------------| +// MSVC 7.1 | b < 6 | 32 < s < 64 | +// GCC 3.4.2 (1) | b < 8 | 128 < s < 256 | +// +// (1) This is a practical rather than a hard limit, caused by a compiler +// memory footprint that was significantly larger than the 1GB physical +// memory installed in the test machine. The resulting frequent swapping +// led to compilation times of hours rather than minutes. +////////////////////////////////////////////////////////////////////////////// + + + +#include "UniqueObject.hpp" + +#include <boost/statechart/event.hpp> +#include <boost/statechart/simple_state.hpp> +#include <boost/statechart/state_machine.hpp> +#include <boost/statechart/transition.hpp> + +#include <boost/mpl/list.hpp> +#include <boost/mpl/front_inserter.hpp> +#include <boost/mpl/transform_view.hpp> +#include <boost/mpl/copy.hpp> +#include <boost/mpl/range_c.hpp> +#include <boost/mpl/integral_c.hpp> +#include <boost/mpl/shift_left.hpp> +#include <boost/mpl/bitxor.hpp> +#include <boost/mpl/for_each.hpp> +#include <boost/mpl/placeholders.hpp> +#include <boost/mpl/aux_/lambda_support.hpp> + +#include <boost/config.hpp> +#include <boost/intrusive_ptr.hpp> + +#include <iostream> +#include <iomanip> +#include <cstddef> // size_t + +#ifdef BOOST_INTEL +# pragma warning( disable: 304 ) // access control not specified +# pragma warning( disable: 444 ) // destructor for base is not virtual +# pragma warning( disable: 981 ) // operands are evaluated in unspecified order +#endif + + + +namespace sc = boost::statechart; +namespace mpl = boost::mpl; + + + +////////////////////////////////////////////////////////////////////////////// +struct IDisplay +{ + virtual void Display() const = 0; +}; + +////////////////////////////////////////////////////////////////////////////// +template< class BitNo > +struct EvFlipBit : sc::event< EvFlipBit< BitNo > > {}; + +template< class StateNo > +struct BitState; + +struct BitMachine : sc::state_machine< + BitMachine, BitState< mpl::integral_c< unsigned int, 0 > > > {}; + +template< class BitNo, class StateNo > +struct FlipTransition +{ + private: + typedef typename mpl::bitxor_< + StateNo, + mpl::shift_left< mpl::integral_c< unsigned int, 1 >, BitNo > + >::type NextStateNo; + + public: + typedef typename sc::transition< + EvFlipBit< BitNo >, BitState< NextStateNo > > type; + + BOOST_MPL_AUX_LAMBDA_SUPPORT( 2, FlipTransition, (BitNo, StateNo) ); +}; + +////////////////////////////////////////////////////////////////////////////// +void DisplayBits( unsigned int number ) +{ + char buffer[ NO_OF_BITS + 1 ]; + buffer[ NO_OF_BITS ] = 0; + + for ( unsigned int bit = 0; bit < NO_OF_BITS; ++bit ) + { + buffer[ bit ] = number & ( 1 << ( NO_OF_BITS - bit - 1 ) ) ? '1' : '0'; + } + + std::cout << "Current state: " << std::setw( 4 ) << + number << " (" << buffer << ")" << std::endl; +} + +template< class StateNo > +struct BitState : sc::simple_state< BitState< StateNo >, BitMachine >, + UniqueObject< BitState< StateNo > >, IDisplay +{ + void * operator new( std::size_t size ) + { + return UniqueObject< BitState< StateNo > >::operator new( size ); + } + + void operator delete( void * p, std::size_t size ) + { + UniqueObject< BitState< StateNo > >::operator delete( p, size ); + } + + typedef typename mpl::copy< + typename mpl::transform_view< + mpl::range_c< unsigned int, 0, NO_OF_BITS >, + FlipTransition< mpl::placeholders::_, StateNo > >::type, + mpl::front_inserter< mpl::list<> > + >::type reactions; + + virtual void Display() const + { + DisplayBits( StateNo::value ); + } +}; + + +void DisplayMachineState( const BitMachine & bitMachine ) +{ + bitMachine.state_cast< const IDisplay & >().Display(); +} + +////////////////////////////////////////////////////////////////////////////// +boost::intrusive_ptr< const sc::event_base > pFlipBitEvents[ NO_OF_BITS ]; + +struct EventInserter +{ + template< class BitNo > + void operator()( const BitNo & ) + { + pFlipBitEvents[ BitNo::value ] = new EvFlipBit< BitNo >(); + } +}; + +void FillEventArray() +{ + mpl::for_each< mpl::range_c< unsigned int, 0, NO_OF_BITS > >( + EventInserter() ); +} + +////////////////////////////////////////////////////////////////////////////// +void VisitAllStates( BitMachine & bitMachine, unsigned int msb ) +{ + if ( msb > 0 ) + { + VisitAllStates( bitMachine, msb - 1 ); + } + + bitMachine.process_event( *pFlipBitEvents[ msb ] ); + DisplayMachineState( bitMachine ); + + if ( msb > 0 ) + { + VisitAllStates( bitMachine, msb - 1 ); + } +} + +////////////////////////////////////////////////////////////////////////////// +char GetKey() +{ + char key; + std::cin >> key; + return key; +} + + +////////////////////////////////////////////////////////////////////////////// +int main() +{ + FillEventArray(); + + const unsigned int noOfStates = 1 << NO_OF_BITS; + std::cout << "Boost.Statechart BitMachine example\n"; + std::cout << "Machine configuration: " << noOfStates << + " states interconnected with " << noOfStates * NO_OF_BITS << + " transitions.\n\n"; + + for ( unsigned int bit = 0; bit < NO_OF_BITS; ++bit ) + { + std::cout << bit - 0 << "<CR>: Flips bit " << bit - 0 << "\n"; + } + + std::cout << "a<CR>: Goes through all states automatically\n"; + std::cout << "e<CR>: Exits the program\n\n"; + std::cout << "You may chain commands, e.g. 31<CR> flips bits 3 and 1\n\n"; + + + BitMachine bitMachine; + bitMachine.initiate(); + + char key = GetKey(); + + while ( key != 'e' ) + { + if ( ( key >= '0' ) && ( key < static_cast< char >( '0' + NO_OF_BITS ) ) ) + { + bitMachine.process_event( *pFlipBitEvents[ key - '0' ] ); + DisplayMachineState( bitMachine ); + } + else + { + switch( key ) + { + case 'a': + { + VisitAllStates( bitMachine, NO_OF_BITS - 1 ); + } + break; + + default: + { + std::cout << "Invalid key!\n"; + } + } + } + + key = GetKey(); + } + + return 0; +} |