ParsingDigits.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  1. // Copyright 2010 Christophe Henry
  2. // henry UNDERSCORE christophe AT hotmail DOT com
  3. // This is an extended version of the state machine available in the boost::mpl library
  4. // Distributed under the same license as the original.
  5. // Copyright for the original version:
  6. // Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
  7. // under the Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at
  9. // http://www.boost.org/LICENSE_1_0.txt)
  10. #define FUSION_MAX_VECTOR_SIZE 20
  11. #include <boost/msm/back/state_machine.hpp>
  12. #include "char_event_dispatcher.hpp"
  13. #include <boost/msm/front/state_machine_def.hpp>
  14. #include <boost/msm/front/functor_row.hpp>
  15. #include <boost/timer.hpp>
  16. namespace msm = boost::msm;
  17. namespace mpl = boost::mpl;
  18. using namespace msm::front;
  19. #include <iostream>
  20. #ifdef WIN32
  21. #include "windows.h"
  22. #else
  23. #include <sys/time.h>
  24. #endif
  25. // events
  26. struct end_sub {template <class Event> end_sub(Event const&){}};
  27. struct other_char {};
  28. struct default_char {};
  29. struct eos {};
  30. namespace test_fsm // Concrete FSM implementation
  31. {
  32. // Concrete FSM implementation
  33. struct parsing_ : public msm::front::state_machine_def<parsing_>
  34. {
  35. // no need for exception handling or message queue
  36. typedef int no_exception_thrown;
  37. typedef int no_message_queue;
  38. struct Waiting : public msm::front::state<>
  39. {
  40. // optional entry/exit methods
  41. //template <class Event,class FSM>
  42. //void on_entry(Event const&,FSM& ) {std::cout << "entering: Waiting" << std::endl;}
  43. //template <class Event,class FSM>
  44. //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Waiting" << std::endl;}
  45. };
  46. struct Digit1 : public msm::front::state<>
  47. {
  48. // optional entry/exit methods
  49. //template <class Event,class FSM>
  50. //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit1" << std::endl;}
  51. //template <class Event,class FSM>
  52. //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit1" << std::endl;}
  53. };
  54. struct Digit2 : public msm::front::state<>
  55. {
  56. // optional entry/exit methods
  57. //template <class Event,class FSM>
  58. //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit2" << std::endl;}
  59. //template <class Event,class FSM>
  60. //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit2" << std::endl;}
  61. };
  62. struct Digit3 : public msm::front::state<>
  63. {
  64. // optional entry/exit methods
  65. //template <class Event,class FSM>
  66. //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit3" << std::endl;}
  67. //template <class Event,class FSM>
  68. //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit3" << std::endl;}
  69. };
  70. struct Digit4 : public msm::front::state<>
  71. {
  72. // optional entry/exit methods
  73. //template <class Event,class FSM>
  74. //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit4" << std::endl;}
  75. //template <class Event,class FSM>
  76. //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit4" << std::endl;}
  77. };
  78. struct MinusChar1 : public msm::front::state<>
  79. {
  80. // optional entry/exit methods
  81. //template <class Event,class FSM>
  82. //void on_entry(Event const&,FSM& ) {std::cout << "entering: MinusChar1" << std::endl;}
  83. //template <class Event,class FSM>
  84. //void on_exit(Event const&,FSM& ) {std::cout << "leaving: MinusChar1" << std::endl;}
  85. };
  86. struct Digit5 : public msm::front::state<>
  87. {
  88. // optional entry/exit methods
  89. //template <class Event,class FSM>
  90. //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit5" << std::endl;}
  91. //template <class Event,class FSM>
  92. //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit5" << std::endl;}
  93. };
  94. struct Digit6 : public msm::front::state<>
  95. {
  96. // optional entry/exit methods
  97. //template <class Event,class FSM>
  98. //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit6" << std::endl;}
  99. //template <class Event,class FSM>
  100. //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit6" << std::endl;}
  101. };
  102. struct Digit7 : public msm::front::state<>
  103. {
  104. // optional entry/exit methods
  105. //template <class Event,class FSM>
  106. //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit7" << std::endl;}
  107. //template <class Event,class FSM>
  108. //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit7" << std::endl;}
  109. };
  110. struct Digit8 : public msm::front::state<>
  111. {
  112. // optional entry/exit methods
  113. //template <class Event,class FSM>
  114. //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit8" << std::endl;}
  115. //template <class Event,class FSM>
  116. //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit8" << std::endl;}
  117. };
  118. struct MinusChar2 : public msm::front::state<>
  119. {
  120. // optional entry/exit methods
  121. //template <class Event,class FSM>
  122. //void on_entry(Event const&,FSM& ) {std::cout << "entering: MinusChar2" << std::endl;}
  123. //template <class Event,class FSM>
  124. //void on_exit(Event const&,FSM& ) {std::cout << "leaving: MinusChar2" << std::endl;}
  125. };
  126. struct Digit9 : public msm::front::state<>
  127. {
  128. // optional entry/exit methods
  129. //template <class Event,class FSM>
  130. //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit9" << std::endl;}
  131. //template <class Event,class FSM>
  132. //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit9" << std::endl;}
  133. };
  134. struct Digit10 : public msm::front::state<>
  135. {
  136. // optional entry/exit methods
  137. //template <class Event,class FSM>
  138. //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit10" << std::endl;}
  139. //template <class Event,class FSM>
  140. //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit10" << std::endl;}
  141. };
  142. struct Digit11 : public msm::front::state<>
  143. {
  144. // optional entry/exit methods
  145. //template <class Event,class FSM>
  146. //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit11" << std::endl;}
  147. //template <class Event,class FSM>
  148. //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit11" << std::endl;}
  149. };
  150. struct Digit12 : public msm::front::state<>
  151. {
  152. // optional entry/exit methods
  153. //template <class Event,class FSM>
  154. //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit12" << std::endl;}
  155. //template <class Event,class FSM>
  156. //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit12" << std::endl;}
  157. };
  158. struct MinusChar3 : public msm::front::state<>
  159. {
  160. // optional entry/exit methods
  161. //template <class Event,class FSM>
  162. //void on_entry(Event const&,FSM& ) {std::cout << "entering: MinusChar3" << std::endl;}
  163. //template <class Event,class FSM>
  164. //void on_exit(Event const&,FSM& ) {std::cout << "leaving: MinusChar3" << std::endl;}
  165. };
  166. struct Digit13 : public msm::front::state<>
  167. {
  168. // optional entry/exit methods
  169. //template <class Event,class FSM>
  170. //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit13" << std::endl;}
  171. //template <class Event,class FSM>
  172. //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit13" << std::endl;}
  173. };
  174. struct Digit14 : public msm::front::state<>
  175. {
  176. // optional entry/exit methods
  177. //template <class Event,class FSM>
  178. //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit14" << std::endl;}
  179. //template <class Event,class FSM>
  180. //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit14" << std::endl;}
  181. };
  182. struct Digit15 : public msm::front::state<>
  183. {
  184. // optional entry/exit methods
  185. //template <class Event,class FSM>
  186. //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit15" << std::endl;}
  187. //template <class Event,class FSM>
  188. //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit15" << std::endl;}
  189. };
  190. //struct Start : public msm::front::state<> {};
  191. struct Parsed : public msm::front::state<> {};
  192. //struct Failed : public msm::front::state<> {};
  193. // the initial state of the player SM. Must be defined
  194. typedef Waiting initial_state;
  195. // transition actions
  196. struct test_fct
  197. {
  198. template <class FSM,class EVT,class SourceState,class TargetState>
  199. void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
  200. {
  201. std::cout << "Parsed!" << std::endl;
  202. }
  203. };
  204. // guard conditions
  205. // Transition table for parsing_
  206. struct transition_table : mpl::vector<
  207. // Start Event Next Action Guard
  208. // +-------------+-------------------+---------+---------------------+----------------------+
  209. Row < Waiting , digit , Digit1 >,
  210. Row < Digit1 , digit , Digit2 >,
  211. Row < Digit2 , digit , Digit3 >,
  212. Row < Digit3 , digit , Digit4 >,
  213. Row < Digit4 , event_char<'-'> , MinusChar1 >,
  214. Row < MinusChar1 , digit , Digit5 >,
  215. Row < Digit5 , digit , Digit6 >,
  216. Row < Digit6 , digit , Digit7 >,
  217. Row < Digit7 , digit , Digit8 >,
  218. Row < Digit8 , event_char<'-'> , MinusChar2 >,
  219. Row < MinusChar2 , digit , Digit9 >,
  220. Row < Digit9 , digit , Digit10 >,
  221. Row < Digit10 , digit , Digit11 >,
  222. Row < Digit11 , digit , Digit12 >,
  223. Row < Digit12 , event_char<'-'> , MinusChar3 >,
  224. Row < MinusChar3 , digit , Digit13 >,
  225. Row < Digit13 , digit , Digit14 >,
  226. Row < Digit14 , digit , Digit15 >,
  227. Row < Digit15 , eos , Parsed >,
  228. Row < Parsed , eos , Waiting >
  229. // +---------+-------------+---------+---------------------+----------------------+
  230. > {};
  231. // Replaces the default no-transition response.
  232. template <class FSM,class Event>
  233. void no_transition(Event const& e, FSM&,int state)
  234. {
  235. std::cout << "no transition from state " << state
  236. << " on event " << typeid(e).name() << std::endl;
  237. }
  238. };
  239. typedef msm::back::state_machine<parsing_> parsing;
  240. }
  241. #ifndef WIN32
  242. long mtime(struct timeval& tv1,struct timeval& tv2)
  243. {
  244. return (tv2.tv_sec-tv1.tv_sec) *1000000 + ((tv2.tv_usec-tv1.tv_usec));
  245. }
  246. #endif
  247. // This declares the statically-initialized char_event_dispatcher instance.
  248. template <class Fsm>
  249. const msm::back::char_event_dispatcher<Fsm>
  250. msm::back::char_event_dispatcher<Fsm>::instance;
  251. struct Parser
  252. {
  253. Parser():p(){p.start();}
  254. void new_char(char c)
  255. {
  256. typedef msm::back::char_event_dispatcher<test_fsm::parsing> table;
  257. table::instance.process_event(p,c);
  258. }
  259. void finish_string(){p.process_event(eos());}
  260. void reinit(){p.process_event(eos());}
  261. test_fsm::parsing p;
  262. };
  263. void msm_match(const char* input)
  264. {
  265. test_fsm::parsing p;
  266. p.start();
  267. int j=0;
  268. while(input[j])
  269. //for (size_t j=0;j<len;++j)
  270. {
  271. switch (input[j])
  272. {
  273. case '0':
  274. p.process_event(char_0());
  275. break;
  276. case '1':
  277. p.process_event(char_1());
  278. break;
  279. case '2':
  280. p.process_event(char_2());
  281. break;
  282. case '3':
  283. p.process_event(char_3());
  284. break;
  285. case '4':
  286. p.process_event(char_4());
  287. break;
  288. case '5':
  289. p.process_event(char_5());
  290. break;
  291. case '6':
  292. p.process_event(char_6());
  293. break;
  294. case '7':
  295. p.process_event(char_7());
  296. break;
  297. case '8':
  298. p.process_event(char_8());
  299. break;
  300. case '9':
  301. p.process_event(char_9());
  302. break;
  303. case '-':
  304. p.process_event(event_char<'-'>());
  305. break;
  306. default:
  307. p.process_event(default_char());
  308. break;
  309. }
  310. ++j;
  311. }
  312. p.process_event(eos());
  313. p.process_event(eos());
  314. }
  315. double time_match(const char* text)
  316. {
  317. boost::timer tim;
  318. int iter = 1;
  319. int counter, repeats;
  320. double result = 0;
  321. double run;
  322. do
  323. {
  324. tim.restart();
  325. for(counter = 0; counter < iter; ++counter)
  326. {
  327. msm_match( text);
  328. }
  329. result = tim.elapsed();
  330. iter *= 2;
  331. } while(result < 0.5);
  332. iter /= 2;
  333. // repeat test and report least value for consistency:
  334. for(repeats = 0; repeats < 10; ++repeats)
  335. {
  336. tim.restart();
  337. for(counter = 0; counter < iter; ++counter)
  338. {
  339. msm_match( text);
  340. }
  341. run = tim.elapsed();
  342. result = (std::min)(run, result);
  343. }
  344. return result / iter;
  345. }
  346. int main()
  347. {
  348. // for timing
  349. #ifdef WIN32
  350. LARGE_INTEGER res;
  351. ::QueryPerformanceFrequency(&res);
  352. LARGE_INTEGER li,li2;
  353. #else
  354. struct timeval tv1,tv2;
  355. gettimeofday(&tv1,NULL);
  356. #endif
  357. test_fsm::parsing p;
  358. p.start();
  359. const char* input = "1234-5678-1234-456";
  360. size_t len = strlen(input);
  361. // for timing
  362. #ifdef WIN32
  363. ::QueryPerformanceCounter(&li);
  364. #else
  365. gettimeofday(&tv1,NULL);
  366. #endif
  367. for (int i=0;i<1000;++i)
  368. {
  369. int j=0;
  370. while(input[j])
  371. //for (size_t j=0;j<len;++j)
  372. {
  373. switch (input[j])
  374. {
  375. case '0':
  376. p.process_event(char_0());
  377. break;
  378. case '1':
  379. p.process_event(char_1());
  380. break;
  381. case '2':
  382. p.process_event(char_2());
  383. break;
  384. case '3':
  385. p.process_event(char_3());
  386. break;
  387. case '4':
  388. p.process_event(char_4());
  389. break;
  390. case '5':
  391. p.process_event(char_5());
  392. break;
  393. case '6':
  394. p.process_event(char_6());
  395. break;
  396. case '7':
  397. p.process_event(char_7());
  398. break;
  399. case '8':
  400. p.process_event(char_8());
  401. break;
  402. case '9':
  403. p.process_event(char_9());
  404. break;
  405. case '-':
  406. p.process_event(event_char<'-'>());
  407. break;
  408. default:
  409. p.process_event(default_char());
  410. break;
  411. }
  412. ++j;
  413. }
  414. p.process_event(eos());
  415. p.process_event(eos());
  416. }
  417. #ifdef WIN32
  418. ::QueryPerformanceCounter(&li2);
  419. #else
  420. gettimeofday(&tv2,NULL);
  421. #endif
  422. #ifdef WIN32
  423. std::cout << "msm(1) took in s:" << (double)(li2.QuadPart-li.QuadPart)/res.QuadPart <<"\n" <<std::endl;
  424. #else
  425. std::cout << "msm(1) took in us:" << mtime(tv1,tv2) <<"\n" <<std::endl;
  426. #endif
  427. Parser parse;
  428. // for timing
  429. #ifdef WIN32
  430. ::QueryPerformanceCounter(&li);
  431. #else
  432. gettimeofday(&tv1,NULL);
  433. #endif
  434. for (int i=0;i<1000;++i)
  435. {
  436. for (size_t j=0;j<len;++j)
  437. {
  438. parse.new_char(input[j]);
  439. }
  440. parse.finish_string();
  441. parse.reinit();
  442. }
  443. #ifdef WIN32
  444. ::QueryPerformanceCounter(&li2);
  445. #else
  446. gettimeofday(&tv2,NULL);
  447. #endif
  448. #ifdef WIN32
  449. std::cout << "msm(2) took in s:" << (double)(li2.QuadPart-li.QuadPart)/res.QuadPart <<"\n" <<std::endl;
  450. #else
  451. std::cout << "msm(2) took in us:" << mtime(tv1,tv2) <<"\n" <<std::endl;
  452. #endif
  453. std::cout << "msm(3) took in s:" << time_match(input) <<"\n" <<std::endl;
  454. return 0;
  455. }