libjmmcg  release_579_6_g8cffd
A C++ library containing an eclectic mix of useful, advanced components.
msm.cpp
Go to the documentation of this file.
1 /******************************************************************************
2 ** Copyright © 2015 by J.M.McGuiness, coder@hussar.me.uk
3 **
4 ** This library is free software; you can redistribute it and/or
5 ** modify it under the terms of the GNU Lesser General Public
6 ** License as published by the Free Software Foundation; either
7 ** version 2.1 of the License, or (at your option) any later version.
8 **
9 ** This library is distributed in the hope that it will be useful,
10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 ** Lesser General Public License for more details.
13 **
14 ** You should have received a copy of the GNU Lesser General Public
15 ** License along with this library; if not, write to the Free Software
16 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 
19 #include "stdafx.h"
20 
21 #define BOOST_TEST_MODULE libjmmcg_tests
22 #include <boost/test/included/unit_test.hpp>
23 
24 #include <boost/mpl/list.hpp>
25 
26 #include "core/msm.hpp"
27 
28 using namespace libjmmcg;
29 
30 enum class states {
31  start,
32  middle,
33  middle1,
34  end,
35  unknown
36 };
37 
38 std::ostream &
39 operator<<(std::ostream &os, states const s) noexcept(false) {
40  os<<static_cast<std::underlying_type<states>::type>(s);
41  return os;
42 }
43 
44 enum class end_states {
45  start=10,
46  middle,
47  middle1,
48  end,
49  unknown
50 };
51 
52 std::ostream &
53 operator<<(std::ostream &os, end_states const s) noexcept(false) {
54  os<<static_cast<std::underlying_type<end_states>::type>(s);
55  return os;
56 }
57 
58 struct data {
60 };
61 
64  unsigned j{68};
65 };
66 
67 using msm_types=boost::mpl::list<
68  msm::unroll,
69  msm::jump_table//,
70 // TODO msm::computed_goto,
71 // TODO msm::hash
72 >;
73 
74 template<class MSMT>
75 struct noop_driver {
76  struct fn_event {
77  using argument_type=std::function<void()>;
78 
79  template<auto state, auto next>
80  void operator()(argument_type &p) const noexcept(true) {
81  p();
82  }
83  template<auto state, auto next, class Params>
84  void operator()(Params &p) const noexcept(true) {
85  p();
86  }
87  };
88 
89  struct state_machine_t final : MSMT::template state_transition_table<state_machine_t> {
90  using base_t=typename MSMT::template state_transition_table<state_machine_t>;
91  using row_t=typename MSMT::template row_types<states, states>;
92  using transition_table=typename base_t::template rows<
93  typename row_t::template row<states::start, fn_event, states::end>
94  >;
95  };
96  using machine=typename MSMT::template machine<state_machine_t>;
97 
98  void process(states state) noexcept(false) {
99  auto fn=std::bind(&state_machine_t::no_op::noop);
100  msm.process(state, fn);
101  }
102 
103  machine msm{};
104 };
105 
106 template<class MSMT>
108  struct fn_event {
109  using argument_type=data_with_payload;
110 
111  explicit fn_event(unsigned &j)
112  : j_(j) {}
113 
114  template<auto state, end_states next>
115  void operator()(argument_type &p) const noexcept(true) {
116  p.state=next;
117  p.j+=j_;
118  }
119  template<auto state, auto next, class Params>
120  void operator()(Params &p) const noexcept(true) {
121  p.state=next;
122  p.j+=j_;
123  }
124 
125  private:
126  unsigned &j_;
127  };
128 
129  struct state_machine_t final : MSMT::template state_transition_table<state_machine_t> {
130  using base_t=typename MSMT::template state_transition_table<state_machine_t>;
131  using row_t=typename MSMT::template row_types<states, end_states>;
132  using transition_table=typename base_t::template rows<
133  typename row_t::template row<states::start, fn_event, end_states::middle>,
134  typename row_t::template row<states::middle, fn_event, end_states::middle1>,
135  typename row_t::template row<states::middle1, fn_event, end_states::end>
136  >;
137  };
138  using machine=typename MSMT::template machine<state_machine_t>;
139 
141  : j(42), msm(j, j, j) {
142  }
143 
144  template<class Arg>
145  void process(states state, Arg &p) noexcept(false) {
146  msm.process(state, p);
147  }
148 
149  unsigned j;
150  machine msm;
151 };
152 
153 template<class MSMT>
155  struct assign_event {
156  using argument_type=data;
157 
158  template<auto state, states next>
159  void operator()(argument_type &p) const noexcept(true) {
160  p.state=next;
161  }
162  template<auto state, auto next, class Params>
163  void operator()(Params &p) const noexcept(true) {
164  p.state=next;
165  }
166  };
167  struct is_true {
168  template<auto state, auto next, class Params>
169  bool operator()(Params &p) const noexcept(true) {
170  return p.check;
171  }
172  };
173 
174  struct state_machine_t final : MSMT::template state_transition_table<state_machine_t> {
175  using base_t=typename MSMT::template state_transition_table<state_machine_t>;
176  using row_t=typename MSMT::template row_types<states, states>;
177  using transition_table=typename base_t::template rows<
178  typename row_t::template row<states::start, assign_event, states::middle>,
179  typename row_t::template row<states::middle, assign_event, states::middle1>,
180  typename row_t::template row<states::middle1, assign_event, states::end>
181  >;
182  };
183  using machine=typename MSMT::template machine<state_machine_t>;
184 
185  template<class Arg>
186  void process(states state, Arg &p) noexcept(false) {
187  msm.process(state, p);
188  }
189 
190  machine msm{};
191 };
192 
193 BOOST_AUTO_TEST_SUITE(msm_tests)
194 
195 BOOST_AUTO_TEST_CASE_TEMPLATE(noop_driver_ctor, msm_type, msm_types) {
196  BOOST_CHECK_NO_THROW([[maybe_unused]] const noop_driver<msm_type> msm);
197 }
198 
199 BOOST_AUTO_TEST_CASE_TEMPLATE(start_state_noop_driver, msm_type, msm_types) {
200  noop_driver<msm_type> msm;
201  BOOST_CHECK_NO_THROW(msm.process(states::start));
202 }
203 
204 BOOST_AUTO_TEST_CASE_TEMPLATE(assign_driver_states_ctor, msm_type, msm_types) {
205  BOOST_CHECK_NO_THROW([[maybe_unused]] const assign_driver_states<msm_type> msm);
206 }
207 
208 BOOST_AUTO_TEST_CASE_TEMPLATE(start_state_assign_driver_states, msm_type, msm_types) {
209  assign_driver_states<msm_type> msm;
211  BOOST_CHECK_NO_THROW(msm.process(states::start, d));
212  BOOST_CHECK_EQUAL(d.state, end_states::middle);
213  BOOST_CHECK_EQUAL(d.j, 68+42);
214  BOOST_CHECK_NO_THROW(msm.process(states::middle, d));
215  BOOST_CHECK_EQUAL(d.state, end_states::middle1);
216  BOOST_CHECK_EQUAL(d.j, 68+42+42);
217 }
218 
219 BOOST_AUTO_TEST_CASE_TEMPLATE(assign_driver_ctor, msm_type, msm_types) {
220  BOOST_CHECK_NO_THROW([[maybe_unused]] const assign_driver<msm_type> msm);
221 }
222 
223 BOOST_AUTO_TEST_CASE_TEMPLATE(start_state_assign_event, msm_type, msm_types) {
224  assign_driver<msm_type> msm;
225  data d;
226  BOOST_CHECK_NO_THROW(msm.process(states::start, d));
227  BOOST_CHECK_EQUAL(d.state, states::middle);
228  BOOST_CHECK_NO_THROW(msm.process(states::middle, d));
229  BOOST_CHECK_EQUAL(d.state, states::middle1);
230  BOOST_CHECK_NO_THROW(msm.process(states::middle1, d));
231  BOOST_CHECK_EQUAL(d.state, states::end);
232 }
233 
234 BOOST_AUTO_TEST_SUITE_END()