diff --git a/include/boost/sml.hpp b/include/boost/sml.hpp index a0cdc30f..0e4c6b0f 100644 --- a/include/boost/sml.hpp +++ b/include/boost/sml.hpp @@ -216,7 +216,7 @@ struct remove_reference { }; template using remove_reference_t = typename remove_reference::type; -} +} // namespace aux namespace aux { using swallow = int[]; template @@ -480,7 +480,7 @@ auto get_type_name(const char *ptr, index_sequence) { static const char str[] = {ptr[N + Ns]..., 0}; return str; } -} +} // namespace detail template const char *get_type_name() { #if defined(_MSC_VER) && !defined(__clang__) @@ -525,7 +525,7 @@ struct string { } static auto c_str_impl(...) { return get_type_name(); } }; -} +} // namespace aux namespace back { namespace policies { struct defer_queue_policy__ {}; @@ -535,8 +535,8 @@ struct defer_queue : aux::pair; using flag = bool; }; -} -} +} // namespace policies +} // namespace back namespace back { template class queue_event { @@ -627,7 +627,7 @@ struct deque_handler : queue_event_call... { } void *deque_{}; }; -} +} // namespace back namespace back { struct _ {}; struct initial {}; @@ -709,7 +709,7 @@ template struct defer : deque_handler { using deque_handler::deque_handler; }; -} +} // namespace back namespace back { template class sm; @@ -832,7 +832,7 @@ template struct convert_to_sm> { using type = aux::type_list, sm_impl>...>; }; -} +} // namespace back namespace back { template class sm; @@ -919,7 +919,7 @@ struct transitions_sub> { return false; } }; -} +} // namespace back namespace back { template class sm; @@ -1011,33 +1011,38 @@ struct get_state_mapping, TMappings, TUnexpected> { }; template using get_state_mapping_t = typename get_state_mapping::type; -template +template transitions get_event_mapping_impl(...); template TMappings get_event_mapping_impl(event_mappings *); -template -unique_mappings_t get_event_mapping_impl(event_mappings> *, - event_mappings<_, aux::inherit> *); +template +unique_mappings_t get_event_mapping_impl(event_mappings> *, + event_mappings> *); +template +using with_default_event_mapping_t = typename aux::conditional< + aux::is_same, decltype(get_event_mapping_impl<_>((TMappings *)0))>::value, + decltype(get_event_mapping_impl((TMappings *)0)), + typename aux::conditional< + aux::is_same, decltype(get_event_mapping_impl((TMappings *)0))>::value, + decltype(get_event_mapping_impl<_>((TMappings *)0)), + decltype(get_event_mapping_impl((TMappings *)0, (TMappings *)0))>::type>::type; template -struct get_event_mapping_impl_helper - : aux::conditional, decltype(get_event_mapping_impl<_>((TMappings *)0))>::value, - decltype(get_event_mapping_impl((TMappings *)0)), - decltype(get_event_mapping_impl((TMappings *)0, (TMappings *)0))>::type {}; +struct get_event_mapping_impl_helper : with_default_event_mapping_t {}; template struct get_event_mapping_impl_helper, TMappings> : decltype(get_event_mapping_impl>((TMappings *)0)) { }; -template -struct get_event_mapping_impl_helper, TMappings> - : decltype(get_event_mapping_impl>((TMappings *)0)) {}; -template -struct get_event_mapping_impl_helper, TMappings> - : decltype(get_event_mapping_impl>((TMappings *)0)) {}; -template -struct get_event_mapping_impl_helper, TMappings> - : decltype(get_event_mapping_impl>((TMappings *)0)) {}; +template +struct get_event_mapping_impl_helper, TMappings> + : with_default_event_mapping_t, unexpected_event<_, _>, TMappings> {}; +template +struct get_event_mapping_impl_helper, TMappings> + : with_default_event_mapping_t, on_entry<_, _>, TMappings> {}; +template +struct get_event_mapping_impl_helper, TMappings> + : with_default_event_mapping_t, on_exit<_, _>, TMappings> {}; template using get_event_mapping_t = get_event_mapping_impl_helper; -} +} // namespace back namespace back { namespace policies { struct dispatch_policy__ {}; @@ -1112,8 +1117,8 @@ struct fold_expr { } }; #endif -} -} +} // namespace policies +} // namespace back namespace back { template class sm; @@ -1180,8 +1185,8 @@ void log_guard(const aux::type &, TDeps &deps, const aux::zero_wrapper< bool result) { return static_cast &>(deps).value.template log_guard(guard.get(), event, result); } -} -} +} // namespace policies +} // namespace back namespace back { namespace policies { struct process_queue_policy__ {}; @@ -1190,14 +1195,14 @@ struct process_queue : aux::pair using rebind = T; }; -} -} +} // namespace policies +} // namespace back namespace back { namespace policies { struct testing_policy__ {}; struct testing : aux::pair {}; -} -} +} // namespace policies +} // namespace back namespace back { namespace policies { struct thread_safety_policy__ { @@ -1217,8 +1222,8 @@ struct thread_safe : aux::pair> { } TLock lock; }; -} -} +} // namespace policies +} // namespace back namespace back { struct no_policy : policies::thread_safety_policy__ { using type = no_policy; @@ -1257,7 +1262,7 @@ struct sm_policy { template using rebind = typename rebind_impl::type; }; -} +} // namespace back namespace concepts { struct callable_fallback { void operator()(); @@ -1273,7 +1278,7 @@ template struct callable : aux::true_type {}; template struct callable : aux::true_type {}; -} +} // namespace concepts namespace concepts { template decltype(aux::declval().operator()()) composable_impl(int); @@ -1281,7 +1286,7 @@ template void composable_impl(...); template struct composable : aux::is(0))> {}; -} +} // namespace concepts #if !defined(BOOST_SML_DISABLE_EXCEPTIONS) #if !(defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) #define BOOST_SML_DISABLE_EXCEPTIONS true @@ -1427,12 +1432,12 @@ struct sm_impl : aux::conditional_t::value, aux: bool process_internal_event(const TEvent &event, TDeps &deps, TSubs &subs, state_t ¤t_state) { policies::log_process_event(aux::type{}, deps, event); #if BOOST_SML_DISABLE_EXCEPTIONS - return process_event_impl, mappings>>(event, deps, subs, states_t{}, current_state) + return process_event_impl, mappings>>(event, deps, subs, states_t{}, + current_state); #else return process_event_noexcept, mappings>>(event, deps, subs, current_state, - has_exceptions{}) + has_exceptions{}); #endif - || process_internal_generic_event(event, deps, subs, current_state); } template bool process_event_impl(const TEvent &event, TDeps &deps, TSubs &subs, const aux::type_list &states, @@ -1738,7 +1743,7 @@ class sm { deps_t deps_; sub_sms_t sub_sms_; }; -} +} // namespace back namespace front { struct operator_base {}; struct action_base {}; @@ -1970,7 +1975,7 @@ class not_ : operator_base { private: T g; }; -} +} // namespace front template ::value)> auto operator!(const T &t) { return front::not_>(aux::zero_wrapper{t}); @@ -1999,8 +2004,8 @@ struct defer : action_base { } } }; -} -} +} // namespace actions +} // namespace front using testing = back::policies::testing; template using logger = back::policies::logger; @@ -2026,7 +2031,7 @@ auto transitional_impl(T &&t) -> aux::always; template struct transitional : decltype(transitional_impl(aux::declval())) {}; -} +} // namespace concepts namespace front { namespace actions { struct process { @@ -2047,8 +2052,8 @@ struct process { return process_impl{event}; } }; -} -} +} // namespace actions +} // namespace front namespace front { template struct transition_eg; @@ -2066,7 +2071,7 @@ struct event { } auto operator()() const { return TEvent{}; } }; -} +} // namespace front namespace front { struct initial_state {}; struct history_state {}; @@ -2159,7 +2164,7 @@ struct state_sm::value>> { using type = state>>; }; #endif -} +} // namespace front namespace front { struct internal {}; template @@ -2593,7 +2598,7 @@ struct transition, state, front::event, always, none> { } __BOOST_SML_ZERO_SIZE_ARRAY(aux::byte); }; -} +} // namespace front using _ = back::_; #if !(defined(_MSC_VER) && !defined(__clang__)) template @@ -2641,7 +2646,7 @@ constexpr auto operator""_e() { return event>; } #endif -} +} // namespace literals __BOOST_SML_UNUSED static front::state X; __BOOST_SML_UNUSED static front::history_state H; __BOOST_SML_UNUSED static front::actions::defer defer; diff --git a/include/boost/sml/back/mappings.hpp b/include/boost/sml/back/mappings.hpp index 2cf598a9..adcb03c2 100644 --- a/include/boost/sml/back/mappings.hpp +++ b/include/boost/sml/back/mappings.hpp @@ -135,37 +135,43 @@ struct get_state_mapping, TMappings, TUnexpected> { template using get_state_mapping_t = typename get_state_mapping::type; -template +template transitions get_event_mapping_impl(...); template TMappings get_event_mapping_impl(event_mappings *); -template -unique_mappings_t get_event_mapping_impl(event_mappings> *, - event_mappings<_, aux::inherit> *); +template +unique_mappings_t get_event_mapping_impl(event_mappings> *, + event_mappings> *); + +template +using with_default_event_mapping_t = typename aux::conditional< + aux::is_same, decltype(get_event_mapping_impl<_>((TMappings *)0))>::value, + decltype(get_event_mapping_impl((TMappings *)0)), + typename aux::conditional< + aux::is_same, decltype(get_event_mapping_impl((TMappings *)0))>::value, + decltype(get_event_mapping_impl<_>((TMappings *)0)), + decltype(get_event_mapping_impl((TMappings *)0, (TMappings *)0))>::type>::type; template -struct get_event_mapping_impl_helper - : aux::conditional, decltype(get_event_mapping_impl<_>((TMappings *)0))>::value, - decltype(get_event_mapping_impl((TMappings *)0)), - decltype(get_event_mapping_impl((TMappings *)0, (TMappings *)0))>::type {}; +struct get_event_mapping_impl_helper : with_default_event_mapping_t {}; template struct get_event_mapping_impl_helper, TMappings> : decltype(get_event_mapping_impl>((TMappings *)0)) { }; -template -struct get_event_mapping_impl_helper, TMappings> - : decltype(get_event_mapping_impl>((TMappings *)0)) {}; +template +struct get_event_mapping_impl_helper, TMappings> + : with_default_event_mapping_t, unexpected_event<_, _>, TMappings> {}; -template -struct get_event_mapping_impl_helper, TMappings> - : decltype(get_event_mapping_impl>((TMappings *)0)) {}; +template +struct get_event_mapping_impl_helper, TMappings> + : with_default_event_mapping_t, on_entry<_, _>, TMappings> {}; -template -struct get_event_mapping_impl_helper, TMappings> - : decltype(get_event_mapping_impl>((TMappings *)0)) {}; +template +struct get_event_mapping_impl_helper, TMappings> + : with_default_event_mapping_t, on_exit<_, _>, TMappings> {}; template using get_event_mapping_t = get_event_mapping_impl_helper; diff --git a/include/boost/sml/back/state_machine.hpp b/include/boost/sml/back/state_machine.hpp index ed9db1a1..6749d494 100644 --- a/include/boost/sml/back/state_machine.hpp +++ b/include/boost/sml/back/state_machine.hpp @@ -182,12 +182,12 @@ struct sm_impl : aux::conditional_t::value, aux: bool process_internal_event(const TEvent &event, TDeps &deps, TSubs &subs, state_t ¤t_state) { policies::log_process_event(aux::type{}, deps, event); #if BOOST_SML_DISABLE_EXCEPTIONS // __pph__ - return process_event_impl, mappings>>(event, deps, subs, states_t{}, current_state) + return process_event_impl, mappings>>(event, deps, subs, states_t{}, + current_state); #else // __pph__ return process_event_noexcept, mappings>>(event, deps, subs, current_state, - has_exceptions{}) + has_exceptions{}); #endif // __pph__ - || process_internal_generic_event(event, deps, subs, current_state); } template diff --git a/test/ft/transitions.cpp b/test/ft/transitions.cpp index 42243811..6116ad3c 100644 --- a/test/ft/transitions.cpp +++ b/test/ft/transitions.cpp @@ -678,6 +678,107 @@ test initial_nontrivial_exit = [] { } }; +template +struct tstate { + auto operator()() noexcept { + using namespace sml; + // clang-format off + return make_transition_table( + *idle + sml::on_entry<_> / [](std::string& s) { s+="ts" + std::to_string(N) + "_en|"; } + ,idle + sml::on_entry / [](std::string& s) { s+="ts"+std::to_string(N)+"e1en|"; } + ,idle + sml::on_exit<_> / [](std::string& s) { s+="ts"+std::to_string(N)+"_ex|"; } + ,idle + sml::on_exit / [](std::string& s) { s+="ts"+std::to_string(N)+"e1ex|"; } + ); + // clang-format on + } +}; +auto t1 = sml::state>; +auto t2 = sml::state>; +auto t3 = sml::state>; +auto t4 = sml::state>; + +test composite_nontrivial_entry = [] { + struct c { + auto operator()() noexcept { + using namespace sml; + // clang-format off + return make_transition_table( + *t1 + sml::on_entry<_> / [](std::string& calls) { calls+="t1_en|"; } + ,t1 + sml::on_entry / [](std::string& calls) { calls+="t1e2en|"; } + ); + // clang-format on + } + }; + + struct d { + auto operator()() noexcept { + using namespace sml; + // clang-format off + return make_transition_table( + *idle + event = state + , idle + event = state + , state + event = idle + ); + // clang-format on + } + }; + { + // Test with a composite sm + std::string s; + sml::sm sm{s}; + sm.process_event(e1{}); + expect("t1_en|ts1e1en|" == s); + s = ""; + sm.process_event(e2{}); + expect("ts1_ex|" == s); + s = ""; + sm.process_event(e2{}); + expect("t1e2en|ts1_en|" == s); + } +}; + +test composite_nontrivial_exit = [] { + struct c { + auto operator()() noexcept { + using namespace sml; + // clang-format off + return make_transition_table( + *t1 + sml::on_exit<_> / [](std::string& calls) { calls+="t1_ex|"; } + ,t1 + sml::on_exit / [](std::string& calls) { calls+="t1e2ex|"; } + ,t1 + event = t2 + ,t1 + event = t2 + ,t2 + sml::on_exit<_> / [](std::string& calls) { calls+="t2_ex|"; } + ,t2 + sml::on_exit / [](std::string& calls) { calls+="t2e4ex|"; } + ); + // clang-format on + } + }; + + struct d { + auto operator()() noexcept { + using namespace sml; + // clang-format off + return make_transition_table( + *state + event = idle + ,state + sml::on_exit<_> / [](std::string& calls) { calls+="c_ex|"; } + ); + // clang-format on + } + }; + { + // Test with a composite sm + std::string s; + sml::sm sm{s}; + expect("ts1_en|" == s); + s = ""; + sm.process_event(e1{}); + expect("ts1e1ex|t1_ex|ts2e1en|" == s); + s = ""; + sm.process_event(e4{}); + expect("ts2_ex|t2e4ex|c_ex|" == s); + } +}; + #if !defined(_MSC_VER) test general_transition_overload = [] { struct c {