////////////////////////////////////////////////////////////////////////////// // 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) ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // This is a quick-and-dirty handcrafted state machine with two states and two // transitions employing GOF-visitation (two virtual calls per event). // It is used to make speed comparisons with Boost.Statechart machines. ////////////////////////////////////////////////////////////////////////////// #include #include #include #include #ifdef BOOST_NO_STDC_NAMESPACE namespace std { using ::clock_t; using ::clock; } #endif #ifdef BOOST_INTEL # pragma warning( disable: 304 ) // access control not specified #endif ////////////////////////////////////////////////////////////////////////////// class EvFlipBit; class state_base { public: virtual ~state_base() {}; virtual const state_base & react( const EvFlipBit & toEvent ) const = 0; protected: state_base() {} }; template< class Derived > class state : public state_base { public: state() : state_base() { } static const Derived & instance() { return instance_; } private: static const Derived instance_; }; template< class Derived > const Derived state< Derived >::instance_; ////////////////////////////////////////////////////////////////////////////// class event_base { public: virtual ~event_base() {} protected: event_base() {} public: virtual const state_base & send( const state_base & toState ) const = 0; }; template< class Derived > class event : public event_base { protected: event() {} private: virtual const state_base & send( const state_base & toState ) const { return toState.react( *static_cast< const Derived * >( this ) ); } }; ////////////////////////////////////////////////////////////////////////////// class EvFlipBit : public event< EvFlipBit > { public: EvFlipBit() : event < EvFlipBit >() { } }; const EvFlipBit flip; class BitMachine { public: ////////////////////////////////////////////////////////////////////////// BitMachine() : pCurrentState_( &Off::instance() ) {} void process_event( const event_base & evt ) { pCurrentState_ = &evt.send( *pCurrentState_ ); } private: ////////////////////////////////////////////////////////////////////////// struct On : state< On > { On() : state() { } virtual const state_base & react( const EvFlipBit & ) const { return Off::instance(); } }; struct Off : state< Off > { Off() : state() { } virtual const state_base & react( const EvFlipBit & ) const { return On::instance(); } }; const state_base * pCurrentState_; }; ////////////////////////////////////////////////////////////////////////////// char GetKey() { char key; std::cin >> key; return key; } ////////////////////////////////////////////////////////////////////////////// int main() { // common prime factors of 2^n-1 for n in [1,8] const unsigned int noOfEvents = 3 * 3 * 5 * 7 * 17 * 31 * 127; unsigned long eventsSentTotal = 0; std::cout << "Boost.Statechart Handcrafted example\n"; std::cout << "Machine configuration: " << 2 << " states interconnected with " << 2 << " transitions.\n\n"; std::cout << "p: Performance test\n"; std::cout << "e: Exits the program\n\n"; std::cout << "You may chain commands, e.g. pe performs a test and then exits the program\n\n"; BitMachine bitMachine; char key = GetKey(); while ( key != 'e' ) { switch ( key ) { case 'p': { std::cout << "\nSending " << noOfEvents << " events. Please wait...\n"; const unsigned long startEvents2 = eventsSentTotal; const std::clock_t startTime2 = std::clock(); for ( unsigned int eventNo = 0; eventNo < noOfEvents; ++eventNo ) { bitMachine.process_event( flip ); ++eventsSentTotal; } const std::clock_t elapsedTime2 = std::clock() - startTime2; const unsigned int eventsSent2 = eventsSentTotal - startEvents2; std::cout << "Time to dispatch one event and\n" << "perform the resulting transition: "; std::cout << elapsedTime2 * 1000.0 / eventsSent2 << " microseconds\n\n"; } break; default: { std::cout << "Invalid key!\n"; } } key = GetKey(); } return 0; }