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