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 | ////////////////////////////////////////////////////////////////////////////// |
---|
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 | { |
---|
137 | void * operator new( std::size_t size ) |
---|
138 | { |
---|
139 | return UniqueObject< BitState< StateNo > >::operator new( size ); |
---|
140 | } |
---|
141 | |
---|
142 | 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 | |
---|
154 | virtual void Display() const |
---|
155 | { |
---|
156 | DisplayBits( StateNo::value ); |
---|
157 | } |
---|
158 | }; |
---|
159 | |
---|
160 | |
---|
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 > |
---|
172 | void operator()( const BitNo & ) |
---|
173 | { |
---|
174 | pFlipBitEvents[ BitNo::value ] = new EvFlipBit< BitNo >(); |
---|
175 | } |
---|
176 | }; |
---|
177 | |
---|
178 | void FillEventArray() |
---|
179 | { |
---|
180 | mpl::for_each< mpl::range_c< unsigned int, 0, NO_OF_BITS > >( |
---|
181 | EventInserter() ); |
---|
182 | } |
---|
183 | |
---|
184 | ////////////////////////////////////////////////////////////////////////////// |
---|
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 | ////////////////////////////////////////////////////////////////////////////// |
---|
202 | char GetKey() |
---|
203 | { |
---|
204 | char key; |
---|
205 | std::cin >> key; |
---|
206 | return key; |
---|
207 | } |
---|
208 | |
---|
209 | |
---|
210 | ////////////////////////////////////////////////////////////////////////////// |
---|
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 | } |
---|