123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479 |
- // Copyright 2010 Christophe Henry
- // henry UNDERSCORE christophe AT hotmail DOT com
- // This is an extended version of the state machine available in the boost::mpl library
- // Distributed under the same license as the original.
- // Copyright for the original version:
- // Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
- // under the Boost Software License, Version 1.0. (See accompanying
- // file LICENSE_1_0.txt or copy at
- // http://www.boost.org/LICENSE_1_0.txt)
- #define FUSION_MAX_VECTOR_SIZE 20
- #include <boost/msm/back/state_machine.hpp>
- #include "char_event_dispatcher.hpp"
- #include <boost/msm/front/state_machine_def.hpp>
- #include <boost/msm/front/functor_row.hpp>
- #include <boost/timer.hpp>
- namespace msm = boost::msm;
- namespace mpl = boost::mpl;
- using namespace msm::front;
- #include <iostream>
- #ifdef WIN32
- #include "windows.h"
- #else
- #include <sys/time.h>
- #endif
- // events
- struct end_sub {template <class Event> end_sub(Event const&){}};
- struct other_char {};
- struct default_char {};
- struct eos {};
- namespace test_fsm // Concrete FSM implementation
- {
- // Concrete FSM implementation
- struct parsing_ : public msm::front::state_machine_def<parsing_>
- {
- // no need for exception handling or message queue
- typedef int no_exception_thrown;
- typedef int no_message_queue;
- struct Waiting : public msm::front::state<>
- {
- // optional entry/exit methods
- //template <class Event,class FSM>
- //void on_entry(Event const&,FSM& ) {std::cout << "entering: Waiting" << std::endl;}
- //template <class Event,class FSM>
- //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Waiting" << std::endl;}
- };
- struct Digit1 : public msm::front::state<>
- {
- // optional entry/exit methods
- //template <class Event,class FSM>
- //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit1" << std::endl;}
- //template <class Event,class FSM>
- //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit1" << std::endl;}
- };
- struct Digit2 : public msm::front::state<>
- {
- // optional entry/exit methods
- //template <class Event,class FSM>
- //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit2" << std::endl;}
- //template <class Event,class FSM>
- //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit2" << std::endl;}
- };
- struct Digit3 : public msm::front::state<>
- {
- // optional entry/exit methods
- //template <class Event,class FSM>
- //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit3" << std::endl;}
- //template <class Event,class FSM>
- //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit3" << std::endl;}
- };
- struct Digit4 : public msm::front::state<>
- {
- // optional entry/exit methods
- //template <class Event,class FSM>
- //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit4" << std::endl;}
- //template <class Event,class FSM>
- //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit4" << std::endl;}
- };
- struct MinusChar1 : public msm::front::state<>
- {
- // optional entry/exit methods
- //template <class Event,class FSM>
- //void on_entry(Event const&,FSM& ) {std::cout << "entering: MinusChar1" << std::endl;}
- //template <class Event,class FSM>
- //void on_exit(Event const&,FSM& ) {std::cout << "leaving: MinusChar1" << std::endl;}
- };
- struct Digit5 : public msm::front::state<>
- {
- // optional entry/exit methods
- //template <class Event,class FSM>
- //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit5" << std::endl;}
- //template <class Event,class FSM>
- //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit5" << std::endl;}
- };
- struct Digit6 : public msm::front::state<>
- {
- // optional entry/exit methods
- //template <class Event,class FSM>
- //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit6" << std::endl;}
- //template <class Event,class FSM>
- //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit6" << std::endl;}
- };
- struct Digit7 : public msm::front::state<>
- {
- // optional entry/exit methods
- //template <class Event,class FSM>
- //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit7" << std::endl;}
- //template <class Event,class FSM>
- //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit7" << std::endl;}
- };
- struct Digit8 : public msm::front::state<>
- {
- // optional entry/exit methods
- //template <class Event,class FSM>
- //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit8" << std::endl;}
- //template <class Event,class FSM>
- //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit8" << std::endl;}
- };
- struct MinusChar2 : public msm::front::state<>
- {
- // optional entry/exit methods
- //template <class Event,class FSM>
- //void on_entry(Event const&,FSM& ) {std::cout << "entering: MinusChar2" << std::endl;}
- //template <class Event,class FSM>
- //void on_exit(Event const&,FSM& ) {std::cout << "leaving: MinusChar2" << std::endl;}
- };
- struct Digit9 : public msm::front::state<>
- {
- // optional entry/exit methods
- //template <class Event,class FSM>
- //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit9" << std::endl;}
- //template <class Event,class FSM>
- //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit9" << std::endl;}
- };
- struct Digit10 : public msm::front::state<>
- {
- // optional entry/exit methods
- //template <class Event,class FSM>
- //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit10" << std::endl;}
- //template <class Event,class FSM>
- //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit10" << std::endl;}
- };
- struct Digit11 : public msm::front::state<>
- {
- // optional entry/exit methods
- //template <class Event,class FSM>
- //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit11" << std::endl;}
- //template <class Event,class FSM>
- //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit11" << std::endl;}
- };
- struct Digit12 : public msm::front::state<>
- {
- // optional entry/exit methods
- //template <class Event,class FSM>
- //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit12" << std::endl;}
- //template <class Event,class FSM>
- //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit12" << std::endl;}
- };
- struct MinusChar3 : public msm::front::state<>
- {
- // optional entry/exit methods
- //template <class Event,class FSM>
- //void on_entry(Event const&,FSM& ) {std::cout << "entering: MinusChar3" << std::endl;}
- //template <class Event,class FSM>
- //void on_exit(Event const&,FSM& ) {std::cout << "leaving: MinusChar3" << std::endl;}
- };
- struct Digit13 : public msm::front::state<>
- {
- // optional entry/exit methods
- //template <class Event,class FSM>
- //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit13" << std::endl;}
- //template <class Event,class FSM>
- //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit13" << std::endl;}
- };
- struct Digit14 : public msm::front::state<>
- {
- // optional entry/exit methods
- //template <class Event,class FSM>
- //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit14" << std::endl;}
- //template <class Event,class FSM>
- //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit14" << std::endl;}
- };
- struct Digit15 : public msm::front::state<>
- {
- // optional entry/exit methods
- //template <class Event,class FSM>
- //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit15" << std::endl;}
- //template <class Event,class FSM>
- //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit15" << std::endl;}
- };
- //struct Start : public msm::front::state<> {};
- struct Parsed : public msm::front::state<> {};
- //struct Failed : public msm::front::state<> {};
- // the initial state of the player SM. Must be defined
- typedef Waiting initial_state;
- // transition actions
- struct test_fct
- {
- template <class FSM,class EVT,class SourceState,class TargetState>
- void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
- {
- std::cout << "Parsed!" << std::endl;
- }
- };
- // guard conditions
- // Transition table for parsing_
- struct transition_table : mpl::vector<
- // Start Event Next Action Guard
- // +-------------+-------------------+---------+---------------------+----------------------+
- Row < Waiting , digit , Digit1 >,
- Row < Digit1 , digit , Digit2 >,
- Row < Digit2 , digit , Digit3 >,
- Row < Digit3 , digit , Digit4 >,
- Row < Digit4 , event_char<'-'> , MinusChar1 >,
- Row < MinusChar1 , digit , Digit5 >,
- Row < Digit5 , digit , Digit6 >,
- Row < Digit6 , digit , Digit7 >,
- Row < Digit7 , digit , Digit8 >,
- Row < Digit8 , event_char<'-'> , MinusChar2 >,
- Row < MinusChar2 , digit , Digit9 >,
- Row < Digit9 , digit , Digit10 >,
- Row < Digit10 , digit , Digit11 >,
- Row < Digit11 , digit , Digit12 >,
- Row < Digit12 , event_char<'-'> , MinusChar3 >,
- Row < MinusChar3 , digit , Digit13 >,
- Row < Digit13 , digit , Digit14 >,
- Row < Digit14 , digit , Digit15 >,
- Row < Digit15 , eos , Parsed >,
- Row < Parsed , eos , Waiting >
- // +---------+-------------+---------+---------------------+----------------------+
- > {};
- // Replaces the default no-transition response.
- template <class FSM,class Event>
- void no_transition(Event const& e, FSM&,int state)
- {
- std::cout << "no transition from state " << state
- << " on event " << typeid(e).name() << std::endl;
- }
- };
- typedef msm::back::state_machine<parsing_> parsing;
- }
- #ifndef WIN32
- long mtime(struct timeval& tv1,struct timeval& tv2)
- {
- return (tv2.tv_sec-tv1.tv_sec) *1000000 + ((tv2.tv_usec-tv1.tv_usec));
- }
- #endif
- // This declares the statically-initialized char_event_dispatcher instance.
- template <class Fsm>
- const msm::back::char_event_dispatcher<Fsm>
- msm::back::char_event_dispatcher<Fsm>::instance;
- struct Parser
- {
- Parser():p(){p.start();}
- void new_char(char c)
- {
- typedef msm::back::char_event_dispatcher<test_fsm::parsing> table;
- table::instance.process_event(p,c);
- }
- void finish_string(){p.process_event(eos());}
- void reinit(){p.process_event(eos());}
- test_fsm::parsing p;
- };
- void msm_match(const char* input)
- {
- test_fsm::parsing p;
- p.start();
- int j=0;
- while(input[j])
- //for (size_t j=0;j<len;++j)
- {
- switch (input[j])
- {
- case '0':
- p.process_event(char_0());
- break;
- case '1':
- p.process_event(char_1());
- break;
- case '2':
- p.process_event(char_2());
- break;
- case '3':
- p.process_event(char_3());
- break;
- case '4':
- p.process_event(char_4());
- break;
- case '5':
- p.process_event(char_5());
- break;
- case '6':
- p.process_event(char_6());
- break;
- case '7':
- p.process_event(char_7());
- break;
- case '8':
- p.process_event(char_8());
- break;
- case '9':
- p.process_event(char_9());
- break;
- case '-':
- p.process_event(event_char<'-'>());
- break;
- default:
- p.process_event(default_char());
- break;
- }
- ++j;
- }
- p.process_event(eos());
- p.process_event(eos());
- }
- double time_match(const char* text)
- {
- boost::timer tim;
- int iter = 1;
- int counter, repeats;
- double result = 0;
- double run;
- do
- {
- tim.restart();
- for(counter = 0; counter < iter; ++counter)
- {
- msm_match( text);
- }
- result = tim.elapsed();
- iter *= 2;
- } while(result < 0.5);
- iter /= 2;
- // repeat test and report least value for consistency:
- for(repeats = 0; repeats < 10; ++repeats)
- {
- tim.restart();
- for(counter = 0; counter < iter; ++counter)
- {
- msm_match( text);
- }
- run = tim.elapsed();
- result = (std::min)(run, result);
- }
- return result / iter;
- }
- int main()
- {
- // for timing
- #ifdef WIN32
- LARGE_INTEGER res;
- ::QueryPerformanceFrequency(&res);
- LARGE_INTEGER li,li2;
- #else
- struct timeval tv1,tv2;
- gettimeofday(&tv1,NULL);
- #endif
- test_fsm::parsing p;
- p.start();
- const char* input = "1234-5678-1234-456";
- size_t len = strlen(input);
- // for timing
- #ifdef WIN32
- ::QueryPerformanceCounter(&li);
- #else
- gettimeofday(&tv1,NULL);
- #endif
- for (int i=0;i<1000;++i)
- {
- int j=0;
- while(input[j])
- //for (size_t j=0;j<len;++j)
- {
- switch (input[j])
- {
- case '0':
- p.process_event(char_0());
- break;
- case '1':
- p.process_event(char_1());
- break;
- case '2':
- p.process_event(char_2());
- break;
- case '3':
- p.process_event(char_3());
- break;
- case '4':
- p.process_event(char_4());
- break;
- case '5':
- p.process_event(char_5());
- break;
- case '6':
- p.process_event(char_6());
- break;
- case '7':
- p.process_event(char_7());
- break;
- case '8':
- p.process_event(char_8());
- break;
- case '9':
- p.process_event(char_9());
- break;
- case '-':
- p.process_event(event_char<'-'>());
- break;
- default:
- p.process_event(default_char());
- break;
- }
- ++j;
- }
- p.process_event(eos());
- p.process_event(eos());
- }
- #ifdef WIN32
- ::QueryPerformanceCounter(&li2);
- #else
- gettimeofday(&tv2,NULL);
- #endif
- #ifdef WIN32
- std::cout << "msm(1) took in s:" << (double)(li2.QuadPart-li.QuadPart)/res.QuadPart <<"\n" <<std::endl;
- #else
- std::cout << "msm(1) took in us:" << mtime(tv1,tv2) <<"\n" <<std::endl;
- #endif
- Parser parse;
- // for timing
- #ifdef WIN32
- ::QueryPerformanceCounter(&li);
- #else
- gettimeofday(&tv1,NULL);
- #endif
- for (int i=0;i<1000;++i)
- {
- for (size_t j=0;j<len;++j)
- {
- parse.new_char(input[j]);
- }
- parse.finish_string();
- parse.reinit();
- }
- #ifdef WIN32
- ::QueryPerformanceCounter(&li2);
- #else
- gettimeofday(&tv2,NULL);
- #endif
- #ifdef WIN32
- std::cout << "msm(2) took in s:" << (double)(li2.QuadPart-li.QuadPart)/res.QuadPart <<"\n" <<std::endl;
- #else
- std::cout << "msm(2) took in us:" << mtime(tv1,tv2) <<"\n" <<std::endl;
- #endif
- std::cout << "msm(3) took in s:" << time_match(input) <<"\n" <<std::endl;
- return 0;
- }
|