BitMachine.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. //////////////////////////////////////////////////////////////////////////////
  2. // Copyright 2002-2006 Andreas Huber Doenni
  3. // Distributed under the Boost Software License, Version 1.0. (See accompany-
  4. // ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. //////////////////////////////////////////////////////////////////////////////
  6. //////////////////////////////////////////////////////////////////////////////
  7. #define NO_OF_BITS 3
  8. //////////////////////////////////////////////////////////////////////////////
  9. // This program demonstrates the fact that measures must be taken to hide some
  10. // of the complexity (e.g. in separate .cpp file) of a Boost.Statechart state
  11. // machine once a certain size is reached.
  12. // For this purpose, a state machine with exactly 2^NO_OF_BITS states (i.e.
  13. // BitState< 0 > .. BitState< 2^NO_OF_BITS - 1 >) is generated. For the events
  14. // EvFlipBit< 0 > .. EvFlipBit< NO_OF_BITS - 1 > there is a transition from
  15. // each state to the state with the corresponding bit toggled. That is, there
  16. // is a total of 2^NO_OF_BITS * NO_OF_BITS transitions.
  17. // E.g. if the state machine is currently in state BitState< 5 > and receives
  18. // EvFlipBit< 2 >, it transitions to state BitState< 1 >. If it is in
  19. // BitState< 15 > and receives EvFlipBit< 4 > it transitions to BitState< 31 >
  20. // etc.
  21. // The maximum size of such a state machine depends on your compiler. The
  22. // following table gives upper limits for NO_OF_BITS. From this, rough
  23. // estimates for the maximum size of any "naively" implemented Boost.Statechart
  24. // machine (i.e. no attempt is made to hide inner state implementation in a
  25. // .cpp file) can be deduced.
  26. //
  27. // NOTE: Due to the fact that the amount of generated code more than
  28. // *doubles* each time NO_OF_BITS is *incremented*, build times on most
  29. // compilers soar when NO_OF_BITS > 6.
  30. //
  31. // Compiler | max. NO_OF_BITS b | max. states s |
  32. // --------------|-------------------|----------------|
  33. // MSVC 7.1 | b < 6 | 32 < s < 64 |
  34. // GCC 3.4.2 (1) | b < 8 | 128 < s < 256 |
  35. //
  36. // (1) This is a practical rather than a hard limit, caused by a compiler
  37. // memory footprint that was significantly larger than the 1GB physical
  38. // memory installed in the test machine. The resulting frequent swapping
  39. // led to compilation times of hours rather than minutes.
  40. //////////////////////////////////////////////////////////////////////////////
  41. #include "UniqueObject.hpp"
  42. #include <boost/statechart/event.hpp>
  43. #include <boost/statechart/simple_state.hpp>
  44. #include <boost/statechart/state_machine.hpp>
  45. #include <boost/statechart/transition.hpp>
  46. #include <boost/mpl/list.hpp>
  47. #include <boost/mpl/front_inserter.hpp>
  48. #include <boost/mpl/transform_view.hpp>
  49. #include <boost/mpl/copy.hpp>
  50. #include <boost/mpl/range_c.hpp>
  51. #include <boost/mpl/integral_c.hpp>
  52. #include <boost/mpl/shift_left.hpp>
  53. #include <boost/mpl/bitxor.hpp>
  54. #include <boost/mpl/for_each.hpp>
  55. #include <boost/mpl/placeholders.hpp>
  56. #include <boost/mpl/aux_/lambda_support.hpp>
  57. #include <boost/config.hpp>
  58. #include <boost/intrusive_ptr.hpp>
  59. #include <iostream>
  60. #include <iomanip>
  61. #include <cstddef> // size_t
  62. #ifdef BOOST_INTEL
  63. # pragma warning( disable: 304 ) // access control not specified
  64. # pragma warning( disable: 444 ) // destructor for base is not virtual
  65. # pragma warning( disable: 981 ) // operands are evaluated in unspecified order
  66. #endif
  67. namespace sc = boost::statechart;
  68. namespace mpl = boost::mpl;
  69. //////////////////////////////////////////////////////////////////////////////
  70. struct IDisplay
  71. {
  72. virtual void Display() const = 0;
  73. };
  74. //////////////////////////////////////////////////////////////////////////////
  75. template< class BitNo >
  76. struct EvFlipBit : sc::event< EvFlipBit< BitNo > > {};
  77. template< class StateNo >
  78. struct BitState;
  79. struct BitMachine : sc::state_machine<
  80. BitMachine, BitState< mpl::integral_c< unsigned int, 0 > > > {};
  81. template< class BitNo, class StateNo >
  82. struct FlipTransition
  83. {
  84. private:
  85. typedef typename mpl::bitxor_<
  86. StateNo,
  87. mpl::shift_left< mpl::integral_c< unsigned int, 1 >, BitNo >
  88. >::type NextStateNo;
  89. public:
  90. typedef typename sc::transition<
  91. EvFlipBit< BitNo >, BitState< NextStateNo > > type;
  92. BOOST_MPL_AUX_LAMBDA_SUPPORT( 2, FlipTransition, (BitNo, StateNo) );
  93. };
  94. //////////////////////////////////////////////////////////////////////////////
  95. void DisplayBits( unsigned int number )
  96. {
  97. char buffer[ NO_OF_BITS + 1 ];
  98. buffer[ NO_OF_BITS ] = 0;
  99. for ( unsigned int bit = 0; bit < NO_OF_BITS; ++bit )
  100. {
  101. buffer[ bit ] = number & ( 1 << ( NO_OF_BITS - bit - 1 ) ) ? '1' : '0';
  102. }
  103. std::cout << "Current state: " << std::setw( 4 ) <<
  104. number << " (" << buffer << ")" << std::endl;
  105. }
  106. template< class StateNo >
  107. struct BitState : sc::simple_state< BitState< StateNo >, BitMachine >,
  108. UniqueObject< BitState< StateNo > >, IDisplay
  109. {
  110. void * operator new( std::size_t size )
  111. {
  112. return UniqueObject< BitState< StateNo > >::operator new( size );
  113. }
  114. void operator delete( void * p, std::size_t size )
  115. {
  116. UniqueObject< BitState< StateNo > >::operator delete( p, size );
  117. }
  118. typedef typename mpl::copy<
  119. typename mpl::transform_view<
  120. mpl::range_c< unsigned int, 0, NO_OF_BITS >,
  121. FlipTransition< mpl::placeholders::_, StateNo > >::type,
  122. mpl::front_inserter< mpl::list<> >
  123. >::type reactions;
  124. virtual void Display() const
  125. {
  126. DisplayBits( StateNo::value );
  127. }
  128. };
  129. void DisplayMachineState( const BitMachine & bitMachine )
  130. {
  131. bitMachine.state_cast< const IDisplay & >().Display();
  132. }
  133. //////////////////////////////////////////////////////////////////////////////
  134. boost::intrusive_ptr< const sc::event_base > pFlipBitEvents[ NO_OF_BITS ];
  135. struct EventInserter
  136. {
  137. template< class BitNo >
  138. void operator()( const BitNo & )
  139. {
  140. pFlipBitEvents[ BitNo::value ] = new EvFlipBit< BitNo >();
  141. }
  142. };
  143. void FillEventArray()
  144. {
  145. mpl::for_each< mpl::range_c< unsigned int, 0, NO_OF_BITS > >(
  146. EventInserter() );
  147. }
  148. //////////////////////////////////////////////////////////////////////////////
  149. void VisitAllStates( BitMachine & bitMachine, unsigned int msb )
  150. {
  151. if ( msb > 0 )
  152. {
  153. VisitAllStates( bitMachine, msb - 1 );
  154. }
  155. bitMachine.process_event( *pFlipBitEvents[ msb ] );
  156. DisplayMachineState( bitMachine );
  157. if ( msb > 0 )
  158. {
  159. VisitAllStates( bitMachine, msb - 1 );
  160. }
  161. }
  162. //////////////////////////////////////////////////////////////////////////////
  163. char GetKey()
  164. {
  165. char key;
  166. std::cin >> key;
  167. return key;
  168. }
  169. //////////////////////////////////////////////////////////////////////////////
  170. int main()
  171. {
  172. FillEventArray();
  173. const unsigned int noOfStates = 1 << NO_OF_BITS;
  174. std::cout << "Boost.Statechart BitMachine example\n";
  175. std::cout << "Machine configuration: " << noOfStates <<
  176. " states interconnected with " << noOfStates * NO_OF_BITS <<
  177. " transitions.\n\n";
  178. for ( unsigned int bit = 0; bit < NO_OF_BITS; ++bit )
  179. {
  180. std::cout << bit - 0 << "<CR>: Flips bit " << bit - 0 << "\n";
  181. }
  182. std::cout << "a<CR>: Goes through all states automatically\n";
  183. std::cout << "e<CR>: Exits the program\n\n";
  184. std::cout << "You may chain commands, e.g. 31<CR> flips bits 3 and 1\n\n";
  185. BitMachine bitMachine;
  186. bitMachine.initiate();
  187. char key = GetKey();
  188. while ( key != 'e' )
  189. {
  190. if ( ( key >= '0' ) && ( key < static_cast< char >( '0' + NO_OF_BITS ) ) )
  191. {
  192. bitMachine.process_event( *pFlipBitEvents[ key - '0' ] );
  193. DisplayMachineState( bitMachine );
  194. }
  195. else
  196. {
  197. switch( key )
  198. {
  199. case 'a':
  200. {
  201. VisitAllStates( bitMachine, NO_OF_BITS - 1 );
  202. }
  203. break;
  204. default:
  205. {
  206. std::cout << "Invalid key!\n";
  207. }
  208. }
  209. }
  210. key = GetKey();
  211. }
  212. return 0;
  213. }