• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
11 #include <set>
12 #include <string>
13 #include <iostream>
14 #include <boost/msm/back/state_machine.hpp>
15 #include <boost/msm/front/state_machine_def.hpp>
16 
17 using namespace std;
18 namespace msm = boost::msm;
19 
20 namespace  // Concrete FSM implementation
21 {
22     // events
23     struct OneSong
24     {
OneSong__anon62ff73980111::OneSong25         OneSong(string const& asong):m_Song(asong){}
get_data__anon62ff73980111::OneSong26         const string& get_data() const {return m_Song;}
27     private:
28         string m_Song;
29     };
30     template <class DATA>
31     struct NotFound
32     {
get_data__anon62ff73980111::NotFound33         DATA get_data() const {return m_Data;}
34         DATA m_Data;
35     };
36     template <class DATA>
37     struct Found
38     {
get_data__anon62ff73980111::Found39         DATA get_data() const {return m_Data;}
40         DATA m_Data;
41     };
42     struct Done {};
43 
44     template <class Container,class BASE_TYPE,class FSMType>
45     struct Insert : public boost::msm::front::state<BASE_TYPE,boost::msm::front::sm_ptr>
46     {
47         template <class Event,class FSM>
on_entry__anon62ff73980111::Insert48         void on_entry(Event const& evt,FSM& )
49         {
50             //TODO other containers
51             if (m_Cont)
52             {
53                 m_Cont->insert(evt.get_data());
54             }
55             m_fsm->process_event(Done());
56         }
set_sm_ptr__anon62ff73980111::Insert57         void set_sm_ptr(FSMType* fsm){m_fsm=fsm;}
set_container__anon62ff73980111::Insert58         void set_container(Container* cont){m_Cont=cont;}
59         Container*  m_Cont;
60 
61     private:
62         FSMType*    m_fsm;
63     };
64     template <class BASE_TYPE,class FSMType>
65     struct StringFind : public boost::msm::front::state<BASE_TYPE,boost::msm::front::sm_ptr>
66     {
67         template <class Event,class FSM>
on_entry__anon62ff73980111::StringFind68         void on_entry(Event const& evt,FSM& )
69         {
70             //TODO other containers
71             // if the element in the event is found
72             if (evt.get_data().find(m_Cont) != std::string::npos )
73             {
74                 Found<std::string> res;
75                 res.m_Data = evt.get_data();
76                 m_fsm->process_event(res);
77             }
78             // data not found
79             else
80             {
81                 NotFound<std::string> res;
82                 res.m_Data = evt.get_data();
83                 m_fsm->process_event(res);
84             }
85         }
set_sm_ptr__anon62ff73980111::StringFind86         void set_sm_ptr(FSMType* fsm){m_fsm=fsm;}
set_container__anon62ff73980111::StringFind87         void set_container(const char* cont){m_Cont=cont;}
88     private:
89         std::string   m_Cont;
90         FSMType*      m_fsm;
91     };
92     template <class EventType,class Container,class BASE_TYPE,class FSMType>
93     struct Foreach : public boost::msm::front::state<BASE_TYPE,boost::msm::front::sm_ptr>
94     {
95         template <class Event,class FSM>
on_entry__anon62ff73980111::Foreach96         void on_entry(Event const& evt,FSM& )
97         {
98             //TODO other containers
99             if (!m_Cont.empty())
100             {
101                 typename Container::value_type next_event = *m_Cont.begin();
102                 m_Cont.erase(m_Cont.begin());
103                 m_fsm->process_event(EventType(next_event));
104             }
105         }
set_sm_ptr__anon62ff73980111::Foreach106         void set_sm_ptr(FSMType* fsm){m_fsm=fsm;}
set_container__anon62ff73980111::Foreach107         void set_container(Container* cont){m_Cont=*cont;}
108 
109     private:
110         Container   m_Cont;
111         FSMType*    m_fsm;
112     };
113 
114 
115     // Concrete FSM implementation
116     struct iPodSearch_ : public msm::front::state_machine_def<iPodSearch_>
117     {
118         typedef msm::back::state_machine<iPodSearch_> iPodSearch;
119         // The list of FSM states
120         typedef std::set<std::string> Songset;
121         typedef Insert<Songset,boost::msm::front::default_base_state,iPodSearch> MyInsert;
122         typedef StringFind<boost::msm::front::default_base_state,iPodSearch> MyFind;
123         typedef Foreach<OneSong,Songset,boost::msm::front::default_base_state,iPodSearch> MyForeach;
124 
125         // the initial state of the player SM. Must be defined
126         typedef MyForeach initial_state;
127 
128         // transition actions
129 
130         // guard conditions
131 
132         typedef iPodSearch_ fsm; // makes transition table cleaner
133 
134         // Transition table for player
135         struct transition_table : mpl::vector4<
136             //     Start       Event              Next         Action                Guard
137             //    +-----------+------------------+------------+---------------------+----------------------+
138             _row < MyForeach  , OneSong          , MyFind                                                  >,
139             _row < MyFind     , NotFound<string> , MyForeach                                               >,
140             _row < MyFind     , Found<string>    , MyInsert                                                >,
141             _row < MyInsert   , Done             , MyForeach                                               >
142             //    +-----------+------------------+------------+---------------------+----------------------+
143         > {};
iPodSearch___anon62ff73980111::iPodSearch_144         iPodSearch_():m_AllSongs(),m_ResultSearch()
145         {
146             // add a few songs for testing
147             m_AllSongs.insert("Let it be");
148             m_AllSongs.insert("Yellow submarine");
149             m_AllSongs.insert("Twist and Shout");
150             m_AllSongs.insert("She Loves You");
151         }
152         template <class Event,class FSM>
on_entry__anon62ff73980111::iPodSearch_153         void on_entry(Event const&,FSM& fsm)
154         {
155             fsm.template get_state<MyForeach&>().set_container(&m_AllSongs);
156             fsm.template get_state<MyInsert&>().set_container(&m_ResultSearch);
157         }
get_result__anon62ff73980111::iPodSearch_158         const Songset& get_result(){return m_ResultSearch;}
reset_search__anon62ff73980111::iPodSearch_159         void reset_search(){m_ResultSearch.clear();}
160 
161         // Replaces the default no-transition response.
162         template <class FSM,class Event>
no_transition__anon62ff73980111::iPodSearch_163         void no_transition(Event const& e, FSM&,int state)
164         {
165             std::cout << "no transition from state " << state
166                 << " on event " << typeid(e).name() << std::endl;
167         }
168 
169     private:
170         Songset m_AllSongs;
171         Songset m_ResultSearch;
172     };
173     typedef msm::back::state_machine<iPodSearch_> iPodSearch;
174 
175 
test()176     void test()
177     {
178         iPodSearch search;
179         // look for "She Loves You" using the first letters
180         search.get_state<iPodSearch::MyFind*>()->set_container("Sh");// will find 2 songs
181 
182         // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
183         search.start();
184         // display all the songs
185         const iPodSearch::Songset& res = search.get_result();
186         for (iPodSearch::Songset::const_iterator it = res.begin();it != res.end();++it)
187         {
188             cout << "candidate song:" << *it << endl;
189         }
190         cout << "search using more letters" << endl;
191         // look for "She Loves You" using more letters
192         search.reset_search();
193         search.get_state<iPodSearch::MyFind*>()->set_container("She");// will find 1 song
194         search.start();
195         const iPodSearch::Songset& res2 = search.get_result();
196         for (iPodSearch::Songset::const_iterator it = res2.begin();it != res2.end();++it)
197         {
198             cout << "candidate song:" << *it << endl;
199         }
200 
201     }
202 }
203 
main()204 int main()
205 {
206     test();
207     return 0;
208 }
209