libjmmcg  release_579_6_g8cffd
A C++ library containing an eclectic mix of useful, advanced components.
msm_impl.hpp
Go to the documentation of this file.
1 /******************************************************************************
2 ** Copyright © 2014 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 namespace jmmcg { namespace LIBJMMCG_VER_NAMESPACE { namespace msm {
20 
21 template<class States, class EndStates>
22 template<States Start, class Event, EndStates Next>
23 class unroll::row_types<States, EndStates>::row final {
24 public:
25  using states=States;
26  using end_states=EndStates;
27  using event_t=Event;
28  static constexpr const states start=Start;
29  static constexpr const end_states next=Next;
30 
31  constexpr row() noexcept(true)=default;
32  template<
33  class Arg,
34  class... Args,
35  class =typename std::enable_if<!std::is_convertible<Arg, row>::value>::type
36  > explicit constexpr
37  row(Arg &&arg, Args &&...args) noexcept(noexcept(event_t(std::forward<Arg>(arg), std::forward<Args>(args)...)))
38  : ev(std::forward<Arg>(arg), std::forward<Args>(args)...) {}
39  constexpr row(row const &r) noexcept(noexcept(event_t(std::declval<event_t>())))
40  : ev(r.ev) {}
41 
42  template<class... Params>
43  constexpr end_states
44  process(Params &&...p) noexcept(
45  noexcept(std::declval<event_t>().template operator()<start, next>(std::forward<Params>(p)...))
46  ) {
47  ev.template operator()<start, next>(std::forward<Params>(p)...);
48  return next;
49  }
50 
51  template<class... Params>
52  constexpr end_states
53  process(Params &&...p) const noexcept(
54  noexcept(std::declval<event_t>().template operator()<start, next>(std::forward<Params>(p)...))
55  ) {
56  ev.template operator()<start, next>(std::forward<Params>(p)...);
57  return next;
58  }
59 
60 private:
61  event_t ev;
62 };
63 
64 template<class States, class EndStates>
65 template<States Start, class Event, EndStates Next, class Guard>
66 class unroll::row_types<States, EndStates>::g_row final {
67 public:
68  using states=States;
69  using end_states=EndStates;
70  using event_t=Event;
71  using guard_t=Guard;
72  static constexpr const states start=Start;
73  static constexpr const end_states next=Next;
74 
75  constexpr g_row() noexcept(true)=default;
76  template<
77  class Arg,
78  class... Args,
79  class =typename std::enable_if<!std::is_convertible<Arg, g_row>::value>::type
80  > explicit constexpr
81  g_row(Arg &&arg, Args &&...args) noexcept(noexcept(event_t(std::forward<Arg>(arg), std::forward<Args>(args)...)))
82  : ev(std::forward<Arg>(arg), std::forward<Args>(args)...) {}
83  constexpr g_row(g_row const &r) noexcept(noexcept(event_t(std::declval<event_t>())))
84  : ev(r.ev) {}
85 
86  template<class... Params>
87  constexpr end_states
88  process(Params &&...p) noexcept(
89  noexcept(guard_t(std::forward<Params>(p)...))
90  || noexcept(std::declval<event_t>().template operator()<start, next>(std::forward<Params>(p)...))
91  ) {
92  if (guard_t(std::forward<Params>(p)...)) {
93  ev.template operator()<start, next>(std::forward<Params>(p)...);
94  return next;
95  } else {
96  return start;
97  }
98  }
99 
100  template<class... Params>
101  constexpr end_states
102  process(Params &&...p) const noexcept(
103  noexcept(guard_t(std::forward<Params>(p)...))
104  || noexcept(std::declval<event_t>().template operator()<start, next>(std::forward<Params>(p)...))
105  ) {
106  if (guard_t(std::forward<Params>(p)...)) {
107  ev.template operator()<start, next>(std::forward<Params>(p)...);
108  return next;
109  } else {
110  return start;
111  }
112  }
113 
114 private:
115  event_t ev;
116 };
117 
118 template<class Deriv>
119 template<class Row, class... Rows>
120 class unroll::state_transition_table<Deriv>::rows : public rows<Rows...> {
121 public:
122  enum : std::size_t {
123  size=sizeof...(Rows)+1
124  };
125  using a_transition=Row;
126  using states=typename a_transition::states;
127  using end_states=typename a_transition::end_states;
128 
129  constexpr rows() noexcept(true)=default;
130  template<
131  class Arg,
132  class... Args,
133  class =typename std::enable_if<!std::is_convertible<Arg, rows>::value>::type
134  > explicit constexpr
135  rows(Arg &&arg, Args &&...args) noexcept(
136  noexcept(rows<Rows...>(std::forward<Args>(args)...))
137  && noexcept(a_transition(std::forward<Arg>(arg)))
138  )
139  : rows<Rows...>(std::forward<Args>(args)...), transition(std::forward<Arg>(arg)) {
140  // If this fails, then insufficient ctor-arguments have been passed to the machine ctor.
141  BOOST_MPL_ASSERT_RELATION(sizeof...(Args)+1, ==, size);
142  }
143  constexpr rows(rows const &r) noexcept(noexcept(a_transition(std::declval<a_transition>())))
144  : rows<Rows...>(r), transition(r.transition) {
145  }
146 
147  template<class... Params>
148  constexpr end_states process(states s, Params &&...p) const noexcept(noexcept(std::declval<a_transition>().process(std::forward<Params>(p)...))) {
149  return s==a_transition::start ? transition.process(std::forward<Params>(p)...) : rows<Rows...>::process(s, std::forward<Params>(p)...);
150  }
151 
152  template<class... Params>
153  constexpr end_states process(states s, Params &&...p) noexcept(noexcept(std::declval<a_transition>().process(std::forward<Params>(p)...))) {
154  return s==a_transition::start ? transition.process(std::forward<Params>(p)...) : rows<Rows...>::process(s, std::forward<Params>(p)...);
155  }
156 
157 private:
158  a_transition transition;
159 };
160 
161 template<class Deriv>
162 template<class Row>
163 class unroll::state_transition_table<Deriv>::rows<Row> {
164 public:
165  enum : std::size_t {
166  size=1
167  };
168  using a_transition=Row;
169  using states=typename a_transition::states;
170  using end_states=typename a_transition::end_states;
171 
172  constexpr rows() noexcept(true)=default;
173  template<
174  class Arg,
175  class =typename std::enable_if<!std::is_convertible<Arg, rows>::value>::type
176  > explicit constexpr
177  rows(Arg &&arg) noexcept(noexcept(a_transition(std::forward<Arg>(arg))))
178  : transition(std::forward<Arg>(arg)) {}
179  constexpr rows(rows const &r) noexcept(noexcept(a_transition(std::declval<a_transition>())))
180  : transition(r.transition) {}
181 
182  template<class... Params>
183  constexpr end_states process([[maybe_unused]] states s, Params &&...p) const noexcept(noexcept(std::declval<a_transition>().process(std::forward<Params>(p)...))) {
184  return transition.process(std::forward<Params>(p)...);
185  }
186 
187  template<class... Params>
188  constexpr end_states process([[maybe_unused]] states s, Params &&...p) noexcept(noexcept(std::declval<a_transition>().process(std::forward<Params>(p)...))) {
189  return transition.process(std::forward<Params>(p)...);
190  }
191 
192 private:
193  a_transition transition;
194 };
195 
196 template<class STT>
197 template<class Arg, class... Args, class> inline constexpr
198 unroll::machine<STT>::machine(Arg &&arg, Args &&...args) noexcept(noexcept(rows_t(std::forward<Arg>(arg), std::forward<Args>(args)...)))
199 : rows_(std::forward<Arg>(arg), std::forward<Args>(args)...) {
200  // If this fails, then insufficient ctor-arguments have been passed to the machine ctor.
201  BOOST_MPL_ASSERT_RELATION(sizeof...(Args)+1, ==, rows_t::size);
202 }
203 
204 template<class STT>
205 inline constexpr
206 unroll::machine<STT>::machine(machine const &m) noexcept(noexcept(rows_t(std::declval<rows_t>())))
207 : rows_(m.rows_) {
208 }
209 
210 template<class STT>
211 template<class... Params> inline constexpr typename unroll::machine<STT>::end_states
212 unroll::machine<STT>::process(states s, Params &&...p) const noexcept(noexcept(std::declval<rows_t>().process(s, std::forward<Params>(p)...))) {
213  return rows_.process(s, std::forward<Params>(p)...);
214 }
215 
216 template<class STT>
217 template<class... Params> inline constexpr typename unroll::machine<STT>::end_states
218 unroll::machine<STT>::process(states s, Params &&...p) noexcept(noexcept(std::declval<rows_t>().process(s, std::forward<Params>(p)...))) {
219  return rows_.process(s, std::forward<Params>(p)...);
220 }
221 
222 template<class States, class EndStates>
223 template<States Start, class Event, EndStates Next>
224 class jump_table::row_types<States, EndStates>::row final {
225 public:
226  using states=States;
227  using end_states=EndStates;
228  using event_t=Event;
229  static constexpr const states start=Start;
230  static constexpr const end_states next=Next;
231 
232  constexpr row() noexcept(true)=default;
233  template<
234  class Arg,
235  class... Args,
236  class =typename std::enable_if<!std::is_convertible<Arg, row>::value>::type
237  > explicit constexpr
238  row(Arg &&arg, Args &&...args) noexcept(noexcept(event_t(std::forward<Arg>(arg), std::forward<Args>(args)...)))
239  : ev(std::forward<Arg>(arg), std::forward<Args>(args)...) {}
240  constexpr row(row const &r) noexcept(noexcept(event_t(std::declval<event_t>())))
241  : ev(r.ev) {}
242 
243  template<class... Params>
244  constexpr end_states
245  process(Params &&...p) noexcept(
246  noexcept(std::declval<event_t>().template operator()<start, next>(std::forward<Params>(p)...))
247  ) {
248  ev.template operator()<start, next>(std::forward<Params>(p)...);
249  return next;
250  }
251 
252  template<class... Params>
253  constexpr end_states
254  process(Params &&...p) const noexcept(
255  noexcept(std::declval<event_t>().template operator()<start, next>(std::forward<Params>(p)...))
256  ) {
257  ev.template operator()<start, next>(std::forward<Params>(p)...);
258  return next;
259  }
260 
261 private:
262  event_t ev;
263 };
264 
265 template<class States, class EndStates>
266 template<States Start, class Event, EndStates Next, class Guard>
267 class jump_table::row_types<States, EndStates>::g_row final {
268 public:
269  using states=States;
270  using end_states=EndStates;
271  using event_t=Event;
272  using guard_t=Guard;
273  static constexpr const states start=Start;
274  static constexpr const end_states next=Next;
275 
276  constexpr g_row() noexcept(true)=default;
277  template<
278  class Arg,
279  class... Args,
280  class =typename std::enable_if<!std::is_convertible<Arg, g_row>::value>::type
281  > explicit constexpr
282  g_row(Arg &&arg, Args &&...args) noexcept(noexcept(event_t(std::forward<Arg>(arg), std::forward<Args>(args)...)))
283  : ev(std::forward<Arg>(arg), std::forward<Args>(args)...) {}
284  constexpr g_row(g_row const &r) noexcept(noexcept(event_t(std::declval<event_t>())))
285  : ev(r.ev) {}
286 
287  template<class... Params>
288  constexpr end_states
289  process(Params &&...p) noexcept(
290  noexcept(guard_t(std::forward<Params>(p)...))
291  || noexcept(std::declval<event_t>().template operator()<start, next>(std::forward<Params>(p)...))
292  ) {
293  if (guard_t(std::forward<Params>(p)...)) {
294  ev.template operator()<start, next>(std::forward<Params>(p)...);
295  return next;
296  } else {
297  return start;
298  }
299  }
300 
301  template<class... Params>
302  constexpr end_states
303  process(Params &&...p) const noexcept(
304  noexcept(guard_t(std::forward<Params>(p)...))
305  || noexcept(std::declval<event_t>().template operator()<start, next>(std::forward<Params>(p)...))
306  ) {
307  if (guard_t(std::forward<Params>(p)...)) {
308  ev.template operator()<start, next>(std::forward<Params>(p)...);
309  return next;
310  } else {
311  return start;
312  }
313  }
314 
315 private:
316  event_t ev;
317 };
318 
319 template<class Deriv>
320 template<class Row>
321 class jump_table::state_transition_table<Deriv>::rows_details<Row> {
322 public:
323  enum : std::size_t {
324  stride=0
325  };
326 };
327 
328 template<class Deriv>
329 template<class Row1, class Row2>
330 class jump_table::state_transition_table<Deriv>::rows_details<Row1, Row2> {
331 public:
332  BOOST_MPL_ASSERT_RELATION((static_cast<std::size_t>(Row2::start)-static_cast<std::size_t>(Row1::start)), >, 0);
333  enum : std::size_t {
334  stride=static_cast<std::size_t>(Row2::start)-static_cast<std::size_t>(Row1::start)
335  };
336 };
337 
338 template<class Deriv>
339 template<class Row1, class Row2, class... Rows>
340 class jump_table::state_transition_table<Deriv>::rows_details<Row1, Row2, Rows...> {
341  enum : std::size_t {
342  stride_before=rows_details<Row1, Row2>::stride,
343  stride_after=rows_details<Row2, Rows...>::stride
344  };
345  BOOST_MPL_ASSERT_RELATION(stride_before, ==, stride_after);
346 
347 public:
348  enum : std::size_t {
349  stride=stride_before
350  };
351 };
352 
353 template<class Deriv>
354 struct jump_table::state_transition_table<Deriv>::rows_base {
355 };
356 
357 template<class Deriv>
358 template<class Row>
359 class jump_table::state_transition_table<Deriv>::rows<Row> : public rows_base {
360 public:
361  enum : std::size_t {
362  size=1,
363  stride=1
364  };
365  using a_transition=Row;
366  using states=typename a_transition::states;
367  using end_states=typename a_transition::end_states;
368 
369  constexpr rows() noexcept(true)=default;
370  template<
371  class Arg,
372  class =typename std::enable_if<!std::is_convertible<Arg, rows>::value>::type
373  > explicit constexpr
374  rows(Arg &&arg) noexcept(noexcept(a_transition(std::forward<Arg>(arg))))
375  : transition(std::forward<Arg>(arg)) {
376  }
377  constexpr rows(rows const &r) noexcept(noexcept(a_transition(std::declval<a_transition>())))
378  : transition(r.transition) {
379  }
380 
381  template<class... Params>
382  static constexpr end_states process(rows_base &row, [[maybe_unused]] states s, Params &&...p) noexcept(noexcept(std::declval<a_transition>().process(std::forward<Params>(p)...))) {
383  assert(s==rows::a_transition::start);
384  return static_cast<rows &>(row).transition.process(std::forward<Params>(p)...);
385  }
386 
387  template<class... Params>
388  struct fn_table_t final : private non_newable {
389  using process_fn_ptr_t=end_states (*)(rows_base &, states, Params &&...);
390  using element_type=std::array<process_fn_ptr_t, size>;
391 
392  ALIGN_TO_L1_CACHE static inline constexpr element_type fn_table{
393  &rows::process<Params...>
394  };
395  };
396 
397 private:
398  a_transition transition;
399 };
400 
401 template<class Deriv>
402 template<class Row, class... Rows>
403 class jump_table::state_transition_table<Deriv>::rows : public rows<Rows...> {
404 public:
405  enum : std::size_t {
406  size=sizeof...(Rows)+1,
407  stride=rows_details<Row, Rows...>::stride
408  };
409  using a_transition=Row;
410  using states=typename a_transition::states;
411  using end_states=typename a_transition::end_states;
412 
413  constexpr rows() noexcept(true)=default;
414  template<
415  class Arg,
416  class... Args,
417  class =typename std::enable_if<!std::is_convertible<Arg, rows>::value>::type
418  > explicit constexpr
419  rows(Arg &&arg, Args &&...args) noexcept(
420  noexcept(rows<Rows...>(std::forward<Args>(args)...))
421  && noexcept(a_transition(std::forward<Arg>(arg)))
422  )
423  : rows<Rows...>(std::forward<Args>(args)...), transition(std::forward<Arg>(arg)) {
424  // If this fails, then insufficient ctor-arguments have been passed to the machine ctor.
425  BOOST_MPL_ASSERT_RELATION(sizeof...(Args)+1, ==, size);
426  }
427  constexpr rows(rows const &r) noexcept(noexcept(a_transition(std::declval<a_transition>())))
428  : rows<Rows...>(r), transition(r.transition) {
429  }
430 
431  template<class... Params>
432  static constexpr end_states process(rows_base &row, [[maybe_unused]] states s, Params &&...p) noexcept(noexcept(std::declval<a_transition>().process(std::forward<Params>(p)...))) {
433  assert(s==static_cast<rows &>(row).a_transition::start);
434  return static_cast<rows &>(row).transition.process(std::forward<Params>(p)...);
435  }
436 
437  template<class... Params>
438  struct fn_table_t final : private non_newable {
439  using process_fn_ptr_t=end_states (*)(rows_base &, states, Params &&...);
440  using element_type=std::array<process_fn_ptr_t, size>;
441 
442  /**
443  * This is very sad: the table may be constexpr, but is not really... So it must be loaded at initialisation-time, thus is in the data-cache, not instruction-cache.
444  * Thus significant performance has been lost. Hence why I do not like constexpr & prefer enums (where one can): it leads one into thinking it is compile-time, when it is not.
445  */
446  ALIGN_TO_L1_CACHE static inline constexpr element_type fn_table{
447  &rows<Row>::template process<Params...>,
448  &rows<Rows>::template process<Params...>...
449  };
450  };
451 
452 private:
453  a_transition transition;
454 };
455 
456 template<class STT>
457 template<class Arg, class... Args, class> inline constexpr
458 jump_table::machine<STT>::machine(Arg &&arg, Args &&...args) noexcept(noexcept(rows_t(std::forward<Arg>(arg), std::forward<Args>(args)...)))
459 : rows_(std::forward<Arg>(arg), std::forward<Args>(args)...) {
460  // If this fails, then insufficient ctor-arguments have been passed to the machine ctor.
461  BOOST_MPL_ASSERT_RELATION(sizeof...(Args)+1, ==, rows_t::size);
462 }
463 
464 template<class STT>
465 inline constexpr
466 jump_table::machine<STT>::machine(machine const &m) noexcept(noexcept(rows_t(std::declval<rows_t>())))
467 : rows_(m.rows_) {
468 }
469 
470 template<class STT>
471 template<class... Params> inline constexpr typename jump_table::machine<STT>::end_states
472 jump_table::machine<STT>::process(states s, Params &&...p) const noexcept(false) {
473  using fn_table_t=typename rows_t::template fn_table_t<Params...>;
474  constexpr auto offset=static_cast<typename std::underlying_type<states>::type>(element_type::transition_table::rows::a_transition::start);
475  const auto index=static_cast<typename std::underlying_type<states>::type>(s)/element_type::transition_table::rows::stride-offset;
476  assert(index>=0);
477  return (*fn_table_t::fn_table[index])(rows_, s, std::forward<Params>(p)...);
478 }
479 
480 template<class STT>
481 template<class... Params> inline constexpr typename jump_table::machine<STT>::end_states
482 jump_table::machine<STT>::process(states s, Params &&...p) noexcept(false) {
483  using fn_table_t=typename rows_t::template fn_table_t<Params...>;
484  constexpr auto offset=static_cast<typename std::underlying_type<states>::type>(element_type::transition_table::rows::a_transition::start);
485  const auto index=static_cast<typename std::underlying_type<states>::type>(s)/element_type::transition_table::rows::stride-offset;
486  assert(index>=0);
487  return (*fn_table_t::fn_table[index])(rows_, s, std::forward<Params>(p)...);
488 }
489 
490 template<class States, class EndStates>
491 template<States Start, class Event, EndStates Next>
492 class computed_goto::row_types<States, EndStates>::row final {
493 public:
494  using states=States;
495  using end_states=EndStates;
496  using event_t=Event;
497  static constexpr const states start=Start;
498  static constexpr const end_states next=Next;
499 
500  constexpr row() noexcept(true)=default;
501  template<
502  class Arg,
503  class... Args,
504  class =typename std::enable_if<!std::is_convertible<Arg, row>::value>::type
505  > explicit constexpr
506  row(Arg &&arg, Args &&...args) noexcept(noexcept(event_t(std::forward<Arg>(arg), std::forward<Args>(args)...)))
507  : ev(std::forward<Arg>(arg), std::forward<Args>(args)...) {}
508  constexpr row(row const &r) noexcept(noexcept(event_t(std::declval<event_t>())))
509  : ev(r.ev) {}
510 
511  template<class... Params>
512  constexpr end_states
513  process(Params &&...p) noexcept(
514  noexcept(std::declval<event_t>().template operator()<start, next>(std::forward<Params>(p)...))
515  ) {
516  ev.template operator()<start, next>(std::forward<Params>(p)...);
517  return next;
518  }
519 
520  template<class... Params>
521  constexpr end_states
522  process(Params &&...p) const noexcept(
523  noexcept(std::declval<event_t>().template operator()<start, next>(std::forward<Params>(p)...))
524  ) {
525  ev.template operator()<start, next>(std::forward<Params>(p)...);
526  return next;
527  }
528 
529 private:
530  event_t ev;
531 };
532 
533 template<class States, class EndStates>
534 template<States Start, class Event, EndStates Next, class Guard>
535 class computed_goto::row_types<States, EndStates>::g_row final {
536 public:
537  using states=States;
538  using end_states=EndStates;
539  using event_t=Event;
540  using guard_t=Guard;
541  static constexpr const states start=Start;
542  static constexpr const end_states next=Next;
543 
544  constexpr g_row() noexcept(true)=default;
545  template<
546  class Arg,
547  class... Args,
548  class =typename std::enable_if<!std::is_convertible<Arg, g_row>::value>::type
549  > explicit constexpr
550  g_row(Arg &&arg, Args &&...args) noexcept(noexcept(event_t(std::forward<Arg>(arg), std::forward<Args>(args)...)))
551  : ev(std::forward<Arg>(arg), std::forward<Args>(args)...) {}
552  constexpr g_row(g_row const &r) noexcept(noexcept(event_t(std::declval<event_t>())))
553  : ev(r.ev) {}
554 
555  template<class... Params>
556  constexpr end_states
557  process(Params &&...p) noexcept(
558  noexcept(guard_t(std::forward<Params>(p)...))
559  || noexcept(std::declval<event_t>().template operator()<start, next>(std::forward<Params>(p)...))
560  ) {
561  if (guard_t(std::forward<Params>(p)...)) {
562  ev.template operator()<start, next>(std::forward<Params>(p)...);
563  return next;
564  } else {
565  return start;
566  }
567  }
568 
569  template<class... Params>
570  constexpr end_states
571  process(Params &&...p) const noexcept(
572  noexcept(guard_t(std::forward<Params>(p)...))
573  || noexcept(std::declval<event_t>().template operator()<start, next>(std::forward<Params>(p)...))
574  ) {
575  if (guard_t(std::forward<Params>(p)...)) {
576  ev.template operator()<start, next>(std::forward<Params>(p)...);
577  return next;
578  } else {
579  return start;
580  }
581  }
582 
583 private:
584  event_t ev;
585 };
586 
587 template<class Deriv>
588 template<class Row>
589 class computed_goto::state_transition_table<Deriv>::rows_details<Row> {
590 public:
591  enum : std::size_t {
592  stride=0
593  };
594 };
595 
596 template<class Deriv>
597 template<class Row1, class Row2>
598 class computed_goto::state_transition_table<Deriv>::rows_details<Row1, Row2> {
599 public:
600  BOOST_MPL_ASSERT_RELATION((static_cast<std::size_t>(Row2::start)-static_cast<std::size_t>(Row1::start)), >, 0);
601  enum : std::size_t {
602  stride=static_cast<std::size_t>(Row2::start)-static_cast<std::size_t>(Row1::start)
603  };
604 };
605 
606 template<class Deriv>
607 template<class Row1, class Row2, class... Rows>
608 class computed_goto::state_transition_table<Deriv>::rows_details<Row1, Row2, Rows...> {
609  enum : std::size_t {
610  stride_before=rows_details<Row1, Row2>::stride,
611  stride_after=rows_details<Row2, Rows...>::stride
612  };
613  BOOST_MPL_ASSERT_RELATION(stride_before, ==, stride_after);
614 
615 public:
616  enum : std::size_t {
617  stride=stride_before
618  };
619 };
620 
621 template<class Deriv>
622 template<class Row>
623 class computed_goto::state_transition_table<Deriv>::rows<Row> {
624 public:
625  enum : std::size_t {
626  size=1,
627  stride=1
628  };
629  using a_transition=Row;
630  using states=typename a_transition::states;
631  using end_states=typename a_transition::end_states;
632 
633  constexpr rows() noexcept(true)=default;
634  template<
635  class Arg,
636  class =typename std::enable_if<!std::is_convertible<Arg, rows>::value>::type
637  > explicit constexpr
638  rows(Arg &&arg) noexcept(noexcept(a_transition(std::forward<Arg>(arg))))
639  : transition(std::forward<Arg>(arg)) {}
640  constexpr rows(rows const &r) noexcept(noexcept(a_transition(std::declval<a_transition>())))
641  : transition(r.transition) {}
642 
643  template<class... Params>
644  static constexpr end_states process(rows &row, [[maybe_unused]] states s, Params &&...p) noexcept(noexcept(std::declval<a_transition>().process(std::forward<Params>(p)...))) {
645  assert(s==rows::a_transition::start);
646  return row.transition.process(std::forward<Params>(p)...);
647  }
648 
649  template<class... Params>
650  struct fn_details_t {
651  using process_fn_ptr_t=end_states (*)(rows &, states, Params &&...);
652 
653  static inline constexpr process_fn_ptr_t base_fn_ptr=&rows::process<Params...>;
654  static inline constexpr std::size_t stride=0;
655  };
656 
657 private:
658  a_transition transition;
659 };
660 
661 template<class Deriv>
662 template<class Row, class... Rows>
663 class computed_goto::state_transition_table<Deriv>::rows : public rows<Rows...> {
664 public:
665  enum : std::size_t {
666  size=sizeof...(Rows)+1,
667  stride=rows_details<Row, Rows...>::stride
668  };
669  using a_transition=Row;
670  using states=typename a_transition::states;
671  using end_states=typename a_transition::end_states;
672 
673  constexpr rows() noexcept(true)=default;
674  template<
675  class Arg,
676  class... Args,
677  class =typename std::enable_if<!std::is_convertible<Arg, rows>::value>::type
678  > explicit constexpr
679  rows(Arg &&arg, Args &&...args) noexcept(
680  noexcept(rows<Rows...>(std::forward<Args>(args)...))
681  && noexcept(a_transition(std::forward<Arg>(arg)))
682  )
683  : rows<Rows...>(std::forward<Args>(args)...), transition(std::forward<Arg>(arg)) {
684  // If this fails, then insufficient ctor-arguments have been passed to the machine ctor.
685  BOOST_MPL_ASSERT_RELATION(sizeof...(Args)+1, ==, size);
686  }
687  constexpr rows(rows const &r) noexcept(noexcept(a_transition(std::declval<a_transition>())))
688  : rows<Rows...>(r), transition(r.transition) {
689  }
690 
691  template<class... Params>
692  static constexpr end_states process(rows &row, [[maybe_unused]] states s, Params &&...p) noexcept(noexcept(std::declval<a_transition>().process(std::forward<Params>(p)...))) {
693  assert(s==rows::a_transition::start);
694  return row.transition.process(std::forward<Params>(p)...);
695  }
696 
697  template<class... Params>
698  struct fn_details_t {
699  using process_fn_ptr_t=end_states (*)(rows &, states, Params &&...);
700 
701  static inline constexpr process_fn_ptr_t base_fn_ptr=&rows::process<Params...>;
702  static inline constexpr auto next_fn_ptr=&rows<Rows...>::template process<Params...>;
703  static inline const std::size_t stride=reinterpret_cast<std::size_t>(next_fn_ptr)-reinterpret_cast<std::size_t>(base_fn_ptr);
704  };
705 
706 private:
707  a_transition transition;
708 };
709 
710 template<class STT>
711 template<class Arg, class... Args, class> inline constexpr
712 computed_goto::machine<STT>::machine(Arg &&arg, Args &&...args) noexcept(noexcept(rows_t(std::forward<Arg>(arg), std::forward<Args>(args)...)))
713 : rows_(std::forward<Arg>(arg), std::forward<Args>(args)...) {
714  // If this fails, then insufficient ctor-arguments have been passed to the machine ctor.
715  BOOST_MPL_ASSERT_RELATION(sizeof...(Args)+1, ==, rows_t::size);
716 }
717 
718 template<class STT>
719 inline constexpr
720 computed_goto::machine<STT>::machine(machine const &m) noexcept(noexcept(rows_t(std::declval<rows_t>())))
721 : rows_(m.rows_) {
722 }
723 
724 template<class STT>
725 template<class... Params> inline constexpr typename computed_goto::machine<STT>::end_states
726 computed_goto::machine<STT>::process(states s, Params &&...p) const noexcept(false) {
727  using fn_details_t=typename rows_t::template fn_details_t<Params...>;
728  constexpr auto offset=static_cast<typename std::underlying_type<states>::type>(element_type::transition_table::rows::a_transition::start);
729  const auto index=static_cast<typename std::underlying_type<states>::type>(s)/element_type::transition_table::rows::stride-offset;
730  assert(index>=0);
731  const std::size_t ptr_offset=index*fn_details_t::stride;
732  assert(ptr_offset>=0);
733  const typename fn_details_t::process_fn_ptr_t process_fn_ptr=fn_details_t::base_fn_ptr+ptr_offset;
734  return (*process_fn_ptr)(rows_, s, std::forward<Params>(p)...);
735 }
736 
737 template<class STT>
738 template<class... Params> inline constexpr typename computed_goto::machine<STT>::end_states
739 computed_goto::machine<STT>::process(states s, Params &&...p) noexcept(false) {
740  using fn_details_t=typename rows_t::template fn_details_t<Params...>;
741  constexpr auto offset=static_cast<typename std::underlying_type<states>::type>(element_type::transition_table::rows::a_transition::start);
742  const auto index=static_cast<typename std::underlying_type<states>::type>(s)/element_type::transition_table::rows::stride-offset;
743  assert(index>=0);
744  const std::size_t ptr_offset=index*fn_details_t::stride;
745  assert(ptr_offset>=0);
746  const typename fn_details_t::process_fn_ptr_t process_fn_ptr=fn_details_t::base_fn_ptr+ptr_offset;
747  return (*process_fn_ptr)(rows_, s, std::forward<Params>(p)...);
748 }
749 
750 template<class States, class EndStates>
751 struct hash::row_types<States, EndStates>::compat_row_base {
752  /**
753  * \param p Measurements revealed that passing via void * and reinterpret_cast'ing had no effect on performance.
754  */
755  virtual EndStates process(void *p) const noexcept(false)=0;
756  /**
757  * \param p Measurements revealed that passing via void * and reinterpret_cast'ing had no effect on performance.
758  */
759  virtual EndStates process(void *p) noexcept(false)=0;
760 };
761 
762 template<class States, class EndStates>
763 template<States Start, class Event, EndStates Next>
764 class hash::row_types<States, EndStates>::row final : public compat_row_base {
765 public:
766  using states=States;
767  using end_states=EndStates;
768  using event_t=Event;
769  static constexpr const states start=Start;
770  static constexpr const end_states next=Next;
771 
772  constexpr row() noexcept(true)=default;
773  template<
774  class Arg,
775  class... Args,
776  class =typename std::enable_if<!std::is_convertible<Arg, row>::value>::type
777  > explicit constexpr
778  row(Arg &&arg, Args &&...args) noexcept(false) // TODO noexcept(noexcept(event_t(std::forward<Arg>(arg), std::forward<Args>(args)...)))
779  : ev(std::forward<Arg>(arg), std::forward<Args>(args)...) {}
780  constexpr row(row const &r) noexcept(noexcept(event_t(std::declval<event_t>())))
781  : ev(r.ev) {}
782 
783  end_states process(void *p) const noexcept(
784  false// TODO noexcept(std::declval<event_t>().template operator()<start, next>(*reinterpret_cast<typename event_t::argument_type *>(p)))
785  ) override final {
786  assert(p);
787  assert(dynamic_cast<typename event_t::argument_type *>(reinterpret_cast<typename event_t::argument_type *>(p)));
788  ev.template operator()<start, next>(*reinterpret_cast<typename event_t::argument_type *>(p));
789  return next;
790  }
791 
792  end_states process(void *p) noexcept(
793  false// TODO noexcept(std::declval<event_t>().template operator()<start, next>(*reinterpret_cast<typename event_t::argument_type *>(p)))
794  ) override final {
795  assert(p);
796  assert(dynamic_cast<typename event_t::argument_type *>(reinterpret_cast<typename event_t::argument_type *>(p)));
797  ev.template operator()<start, next>(*reinterpret_cast<typename event_t::argument_type *>(p));
798  return next;
799  }
800 
801 private:
802  event_t ev;
803 };
804 
805 template<class States, class EndStates>
806 template<States Start, class Event, EndStates Next, class Guard>
807 class hash::row_types<States, EndStates>::g_row final : public compat_row_base {
808 public:
809  using states=States;
810  using end_states=EndStates;
811  using event_t=Event;
812  using guard_t=Guard;
813  static constexpr const states start=Start;
814  static constexpr const end_states next=Next;
815 
816  constexpr g_row() noexcept(true)=default;
817  template<
818  class Arg,
819  class... Args,
820  class =typename std::enable_if<!std::is_convertible<Arg, g_row>::value>::type
821  > explicit constexpr
822  g_row(Arg &&arg, Args &&...args) noexcept(noexcept(event_t(std::forward<Arg>(arg), std::forward<Args>(args)...)))
823  : ev(std::forward<Arg>(arg), std::forward<Args>(args)...) {}
824  constexpr g_row(g_row const &r) noexcept(noexcept(event_t(std::declval<event_t>())))
825  : ev(r.ev) {}
826 
827  end_states process(void *p) const noexcept(
828  noexcept(guard_t(p))
829  || noexcept(
830  std::declval<event_t>().template operator()<start, next>(*reinterpret_cast<typename event_t::argument_type *>(nullptr))
831  )
832  ) override final {
833  assert(p);
834  auto arg=reinterpret_cast<typename event_t::argument_type *>(p);
835  assert(dynamic_cast<typename event_t::argument_type *>(arg));
836  if (guard_t(p)) {
837  ev.template operator()<start, next>(*arg);
838  return next;
839  } else {
840  return start;
841  }
842  }
843 
844  end_states process(void *p) noexcept(
845  noexcept(guard_t(p))
846  || noexcept(
847  std::declval<event_t>().template operator()<start, next>(*reinterpret_cast<typename event_t::argument_type *>(nullptr))
848  )
849  ) override final {
850  assert(p);
851  auto arg=reinterpret_cast<typename event_t::argument_type *>(p);
852  assert(dynamic_cast<typename event_t::argument_type *>(arg));
853  if (guard_t(p)) {
854  ev.template operator()<start, next>(*arg);
855  return next;
856  } else {
857  return start;
858  }
859  }
860 
861 private:
862  event_t ev;
863 };
864 
865 /// How to get the state out of the specified row.
866 template<class Deriv>
867 template<class Row>
868 struct hash::state_transition_table<Deriv>::get_state_as_hash final {
869  static constexpr const typename Row::states value=Row::start;
870 };
871 
872 template<class Deriv>
873 template<class Row, class... Rows>
874 struct hash::state_transition_table<Deriv>::rows {
875  enum : std::size_t {
876  size=sizeof...(Rows)+1
877  };
878  using a_transition=Row;
879  using states=typename a_transition::states;
880  using end_states=typename a_transition::end_states;
881  struct hasher final {
882  private:
883  /**
884  Hack to avoid using std::is_enum on types that are not enums in non-dependant circumstances.
885  */
886  template<class T, bool=std::is_enum<T>::value>
887  struct is_enum
888  {
889  using type=T;
890  };
891  template<class T>
892  struct is_enum<T, true>
893  {
894  using type=typename std::underlying_type<T>::type;
895  };
896 
897  public:
898  using element_type=typename is_enum<states>::type;
899 
900  constexpr element_type operator()(states const v) const noexcept(true) {
901  return static_cast<element_type>(v);
902  }
903  constexpr element_type operator()(states const v, std::size_t const &) const noexcept(true) {
904  return static_cast<element_type>(v);
905  }
906  };
907  using states_to_actions_table_t=unordered_tuple<
908  states,
909  typename hash::row_types<states, end_states>::compat_row_base,
910  hasher,
911  get_state_as_hash,
912  Row, Rows...
913  >;
914 };
915 
916 template<class STT>
917 template<class Arg, class... Args, class> constexpr inline
918 hash::machine<STT>::machine(Arg &&arg, Args &&...args) noexcept(noexcept(states_to_actions_table_t(std::forward<Arg>(arg), std::forward<Args>(args)...)))
919 : tbl(std::forward<Arg>(arg), std::forward<Args>(args)...) {
920 }
921 
922 template<class STT>
923 inline constexpr
925 : tbl(m.tbl) {
926 }
927 
928 template<class STT>
929 template<class Params> inline typename hash::machine<STT>::end_states
930 hash::machine<STT>::process(states s, Params &p) const noexcept(
931  noexcept(
932  std::declval<states_to_actions_table_t>()[s].process(reinterpret_cast<void *>(&p))
933  )
934 ) {
935  return static_cast<typename machine<STT>::end_states>(tbl[s].process(reinterpret_cast<void *>(&p)));
936 }
937 
938 template<class STT>
939 template<class Params> inline typename hash::machine<STT>::end_states
940 hash::machine<STT>::process(states s, Params &p) noexcept(
941  noexcept(
942  std::declval<states_to_actions_table_t>()[s].process(reinterpret_cast<void *>(&p))
943  )
944 ) {
945  return static_cast<typename machine<STT>::end_states>(tbl[s].process(reinterpret_cast<void *>(&p)));
946 }
947 
948 } } }