summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/statechart/example/BitMachine/BitMachine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/boost/libs/statechart/example/BitMachine/BitMachine.cpp')
-rw-r--r--src/boost/libs/statechart/example/BitMachine/BitMachine.cpp264
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;
+}