diff --git a/include/boost/sml.hpp b/include/boost/sml.hpp index 297929ef..3b5b6698 100644 --- a/include/boost/sml.hpp +++ b/include/boost/sml.hpp @@ -1062,31 +1062,57 @@ struct internal_event { struct anonymous : internal_event { constexpr static auto c_str() { return "anonymous"; } }; +template +struct default_internal_event { + static const T &get() { + static_assert(aux::is_constructible::value, "Default internal event requires a default-constructible payload type."); + return *static_cast(nullptr); + } +}; +template +struct default_internal_event::value>> { + constexpr static const T &get() { return value; } + static const T value; +}; +template +const T default_internal_event::value>>::value{}; template struct completion : internal_event { constexpr static auto c_str() { return "completion"; } + template ::value)> + constexpr completion() : event_(default_internal_event::get()) {} + constexpr explicit completion(const TEvent &event) : event_(event) {} + const TEvent &event_; }; template struct on_entry : internal_event, entry_exit { constexpr static auto c_str() { return "on_entry"; } - constexpr explicit on_entry(const TEvent &event = {}) : event_(event) {} + template ::value)> + constexpr on_entry() : event_(default_internal_event::get()) {} + constexpr explicit on_entry(const TEvent &event) : event_(event) {} const TEvent &event_; }; template struct on_exit : internal_event, entry_exit { constexpr static auto c_str() { return "on_exit"; } - constexpr explicit on_exit(const TEvent &event = {}) : event_(event) {} + template ::value)> + constexpr on_exit() : event_(default_internal_event::get()) {} + constexpr explicit on_exit(const TEvent &event) : event_(event) {} const TEvent &event_; }; template struct exception : internal_event { using type = TException; - constexpr explicit exception(const TException &exception = {}) : exception_(exception) {} + template ::value)> + constexpr exception() : exception_(default_internal_event::get()) {} + constexpr explicit exception(const TException &exception) : exception_(exception) {} const TException &exception_; }; template struct unexpected_event : internal_event, unexpected { - constexpr explicit unexpected_event(const TEvent &event = {}) : event_(event) {} + template ::value)> + constexpr unexpected_event() : event_(default_internal_event::get()) {} + constexpr explicit unexpected_event(const TEvent &event) : event_(event) {} const TEvent &event_; }; template @@ -1125,6 +1151,26 @@ template using get_generic_t = typename event_type::generic_t; template using get_mapped_t = typename event_type::mapped_t; +template +constexpr const TEvent &get_origin_event(const TEvent &event) { + return event; +} +template +constexpr const TEvent &get_origin_event(const unexpected_event &event) { + return event.event_; +} +template +constexpr const TEvent &get_origin_event(const on_entry &event) { + return event.event_; +} +template +constexpr const TEvent &get_origin_event(const on_exit &event) { + return event.event_; +} +template +constexpr const TException &get_origin_event(const exception &event) { + return event.exception_; +} template struct process : queue_handler { using queue_handler::queue_handler; @@ -1860,28 +1906,28 @@ struct sm_impl : aux::conditional_t - constexpr bool process_completion_event(TDeps &deps, TSubs &subs, aux::true_type) { - return process_internal_events(completion{}, deps, subs); + constexpr bool process_completion_event(const TOriginEvent &event, TDeps &deps, TSubs &subs, aux::true_type) { + return process_internal_events(completion{event}, deps, subs); } template - constexpr bool process_completion_event(TDeps &, TSubs &, aux::false_type) { + constexpr bool process_completion_event(const TOriginEvent &, TDeps &, TSubs &, aux::false_type) { return false; } template - constexpr bool process_post_event_step(TDeps &deps, TSubs &subs) { + constexpr bool process_post_event_step(const TOriginEvent &event, TDeps &deps, TSubs &subs) { return process_completion_event( - deps, subs, typename aux::is_base_of, events_ids_t>::type{}) || + event, deps, subs, typename aux::is_base_of, events_ids_t>::type{}) || process_internal_events(anonymous{}, deps, subs); } template - constexpr void process_post_events(TDeps &deps, TSubs &subs) { - while (process_post_event_step(deps, subs)) { + constexpr void process_post_events(const TOriginEvent &event, TDeps &deps, TSubs &subs) { + while (process_post_event_step(event, deps, subs)) { } } template constexpr bool process_event_and_post_events(const TEvent &event, TDeps &deps, TSubs &subs) { const bool handled = process_internal_events(event, deps, subs); - process_post_events(deps, subs); + process_post_events(get_origin_event(event), deps, subs); return handled; } constexpr void initialize(const aux::type_list<> &) {} @@ -2351,6 +2397,14 @@ template constexpr decltype(auto) get_arg(const aux::type_wrapper &, const back::on_exit &event, Tsm &, TDeps &) { return event.event_; } +template +constexpr decltype(auto) get_arg(const aux::type_wrapper &, const back::completion &event, Tsm &, TDeps &) { + return event.event_; +} +template +constexpr decltype(auto) get_arg(const aux::type_wrapper &, const back::completion &event, Tsm &, TDeps &) { + return event.event_; +} template constexpr decltype(auto) get_arg(const aux::type_wrapper &, const back::exception &event, Tsm &, TDeps &) { return event.exception_; @@ -2645,7 +2699,10 @@ struct event { constexpr auto operator/(const T &t) const { return transition_ea>{*this, aux::zero_wrapper{t}}; } - constexpr auto operator()() const { return TEvent{}; } + template ::value)> + constexpr auto operator()() const { + return U{}; + } }; } // namespace front namespace front { @@ -2756,6 +2813,18 @@ struct ignore> { }; using type = aux::join_t::type...>; }; +template +struct ignore, aux::type_list> { + template + struct non_events { + using arg_t = aux::remove_const_t>; + using type = aux::conditional_t::value || + aux::is_same, arg_t>::value || + aux::is_same::value, + aux::type_list<>, aux::type_list>; + }; + using type = aux::join_t::type...>; +}; template struct get_deps { using type = typename ignore>::type; diff --git a/test/ft/actions_process_n_defer.cpp b/test/ft/actions_process_n_defer.cpp index c3696ddd..70fd6ef1 100644 --- a/test/ft/actions_process_n_defer.cpp +++ b/test/ft/actions_process_n_defer.cpp @@ -120,7 +120,9 @@ test process_n_defer_again = [] { test process_queue_runs_completion_for_popped_event_type = [] { struct trigger {}; - struct queued1 {}; + struct queued1 { + int value{}; + }; struct queued2 {}; struct q0 {}; struct q1 {}; @@ -140,9 +142,9 @@ test process_queue_runs_completion_for_popped_event_type = [] { auto wrong_state = state; // clang-format off return make_transition_table( - *q0_state + event / (process(queued1{}), process(queued2{})) = q1_state + *q0_state + event / (process(queued1{42}), process(queued2{})) = q1_state , q1_state + event = q2_state - , q2_state + completion = q3_state + , q2_state + completion[([](const queued1& event) { return event.value == 42; })] = q3_state , q2_state + event = wrong_state , q3_state + event = done_state ); @@ -157,7 +159,9 @@ test process_queue_runs_completion_for_popped_event_type = [] { }; test defer_queue_runs_completion_for_popped_event_type = [] { - struct deferred {}; + struct deferred { + int value{}; + }; struct release {}; struct d0 {}; struct d1 {}; @@ -178,7 +182,7 @@ test defer_queue_runs_completion_for_popped_event_type = [] { *d0_state + event / defer , d0_state + event = d1_state , d1_state + event = d2_state - , d2_state + completion = done_state + , d2_state + completion[([](const deferred& event) { return event.value == 11; })] = done_state , d2_state + completion = wrong_state ); // clang-format on @@ -186,7 +190,7 @@ test defer_queue_runs_completion_for_popped_event_type = [] { }; sml::sm, sml::defer_queue> sm{}; - expect(sm.process_event(deferred{})); + expect(sm.process_event(deferred{11})); expect(sm.process_event(release{})); expect(sm.is(sml::state)); expect(!sm.is(sml::state)); diff --git a/test/ft/transitions.cpp b/test/ft/transitions.cpp index 9d0cc3ca..ff1df3df 100644 --- a/test/ft/transitions.cpp +++ b/test/ft/transitions.cpp @@ -89,13 +89,17 @@ test anonymous_transition = [] { }; test completion_transition_runs_before_anonymous = [] { + struct payload { + int value{}; + }; + struct c { auto operator()() noexcept { using namespace sml; // clang-format off return make_transition_table( - *idle + event = s1 - ,s1 + completion / [this] { calls += "completion|"; } = s2 + *idle + event = s1 + ,s1 + completion / [this](const payload& event) { calls += "completion(" + std::to_string(event.value) + ")|"; } = s2 ,s1 / [this] { calls += "anonymous_s1|"; } = s3 ,s2 / [this] { calls += "anonymous_s2|"; } = s4 ); @@ -106,10 +110,10 @@ test completion_transition_runs_before_anonymous = [] { }; sml::sm sm{}; - expect(sm.process_event(e1{})); + expect(sm.process_event(payload{42})); expect(sm.is(s4)); expect(!sm.is(s3)); - expect(static_cast(sm).calls == "completion|anonymous_s2|"); + expect(static_cast(sm).calls == "completion(42)|anonymous_s2|"); }; test subsequent_anonymous_transitions = [] {