From 19092cef069aaf287f5a74d486f97ac505b30c6f Mon Sep 17 00:00:00 2001 From: Thomas Kemmer Date: Wed, 20 Feb 2019 21:42:12 +0100 Subject: [PATCH] Add fsm::row type (C++17 only). --- src/fsm.h | 35 +++++++++++++++- tests/Makefile.am | 1 + tests/test_basic_row.cpp | 7 +--- tests/test_row.cpp | 88 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 123 insertions(+), 8 deletions(-) create mode 100644 tests/test_row.cpp diff --git a/src/fsm.h b/src/fsm.h index dc98cc7..221adc1 100644 --- a/src/fsm.h +++ b/src/fsm.h @@ -258,7 +258,7 @@ namespace fsmlite { detail::invoke_as_binary_fn(action, self, event); } - // clang++-50: constexpr function's return type 'void' is not a literal type + // clang++-5.0: constexpr function's return type 'void' is not a literal type static /*constexpr*/ void process_event(std::nullptr_t, Derived& self, const Event& event) { } @@ -299,7 +299,6 @@ namespace fsmlite { * * @tparam guard a static `Guard` instance */ - template< State start, class Event, @@ -355,6 +354,38 @@ namespace fsmlite { } }; +#if __cplusplus >= 201703L + /** + * Generic transition class template (requires C++17). + * + * @tparam start the start state of the transition + * + * @tparam Event the event type triggering the transition + * + * @tparam target the target state of the transition + * + * @tparam action a static action function pointer, or `nullptr` + * + * @tparam guard a static guard function pointer, or `nullptr` + */ + template< + State start, + class Event, + State target, + auto action = nullptr, + auto guard = nullptr + > + struct row : public row_base { + static void process_event(Derived& self, const Event& event) { + row_base::process_event(action, self, event); + } + + static bool check_guard(const Derived& self, const Event& event) { + return row_base::check_guard(guard, self, event); + } + }; +#endif + private: template struct by_event_type; diff --git a/tests/Makefile.am b/tests/Makefile.am index 9c75a68..ed2c7cd 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -8,6 +8,7 @@ check_PROGRAMS = \ test_mem_fn_row \ test_notrans \ test_recursive \ + test_row \ test_scoped \ test_traits diff --git a/tests/test_basic_row.cpp b/tests/test_basic_row.cpp index 92db947..3770537 100644 --- a/tests/test_basic_row.cpp +++ b/tests/test_basic_row.cpp @@ -1,11 +1,7 @@ #include -#include -#include #include "fsm.h" -using namespace std::placeholders; - int value = 0; // global actions @@ -48,12 +44,11 @@ class state_machine: public fsmlite::fsm { basic_row< Running, event, Running, decltype(&m::store2), &m::store2, decltype(&m::is2), &m::is2 >, basic_row< Running, event, Running, decltype(&m::store3), &m::store3, decltype(&m::is3), &m::is3 >, basic_row< Running, event, Exit, decltype(&clear), &clear /* fallback */ >, - basic_row< Exit, event, Exit, decltype(nullptr), nullptr > + basic_row< Exit, event, Exit > // ----------+--------+------+--------+---------------------+-----------+------------------+-------+- >; }; - int main() { state_machine m; diff --git a/tests/test_row.cpp b/tests/test_row.cpp new file mode 100644 index 0000000..eb5cbb4 --- /dev/null +++ b/tests/test_row.cpp @@ -0,0 +1,88 @@ +#include + +#include "fsm.h" + +#if __cplusplus >= 201703L + +int value = 0; + +// global actions + +void store(int i) { value = i; } +void clear() { value = 0; } + +// global guards + +bool is1(int i) { return i == 1; } + +// fsm + +class state_machine: public fsmlite::fsm { + friend class fsm; // base class needs access to transition_table + +public: + enum states { Init, Running, Exit }; + + using event = int; + +public: + + static void store2() { value = 2; } + + static bool is2(int i) { return i == 2; } + + void store3() { value = 3; } + + bool is3(int i) const { return i == 3; } + +private: + using m = state_machine; + + using transition_table = table< +// Start Event Target Action Guard +// ----+--------+------+--------+-----------+-------+- + row< Init, event, Running, &store >, + row< Running, event, Running, &store, &is1 >, + row< Running, event, Running, &m::store2, &m::is2 >, + row< Running, event, Running, &m::store3, &m::is3 >, + row< Running, event, Exit, &clear >, + row< Exit, event, Exit > +// ----+--------+------+--------+-----------+-------+- + >; +}; + +#endif + +int main() +{ +#if __cplusplus >= 201703L + state_machine m; + assert(m.current_state() == state_machine::Init); + assert(value == 0); + + m.process_event(42); + assert(m.current_state() == state_machine::Running); + assert(value == 42); + + m.process_event(1); + assert(m.current_state() == state_machine::Running); + assert(value == 1); + + m.process_event(2); + assert(m.current_state() == state_machine::Running); + assert(value == 2); + + m.process_event(3); + assert(m.current_state() == state_machine::Running); + assert(value == 3); + + m.process_event(42); + assert(m.current_state() == state_machine::Exit); + assert(value == 0); + + m.process_event(42); + assert(m.current_state() == state_machine::Exit); + assert(value == 0); +#endif + return 0; +}