From 7ca4d03178a7f1b301975ae398a45e3f55cbb580 Mon Sep 17 00:00:00 2001 From: Marco Bergamin Date: Tue, 2 Jun 2020 05:21:23 -0700 Subject: [PATCH 1/2] Fix bug in dep resolution when requesting a "const T*" after providing a "T*" Before this fix, if a T* was injected as depedency, requesting a const T* will result in a invalid nullptr. Four unit tests added. --- include/boost/sml.hpp | 28 +++++++++++++- test/ft/dependencies.cpp | 84 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+), 1 deletion(-) diff --git a/include/boost/sml.hpp b/include/boost/sml.hpp index b0f6174c..cce98e3b 100644 --- a/include/boost/sml.hpp +++ b/include/boost/sml.hpp @@ -207,6 +207,16 @@ struct remove_reference { }; template using remove_reference_t = typename remove_reference::type; +template +struct remove_pointer { + using type = T; +}; +template +struct remove_pointer { + using type = T; +}; +template +using remove_pointer_t = typename remove_pointer::type; } namespace aux { using swallow = int[]; @@ -363,6 +373,14 @@ template T &try_get(const pool_type *object) { return object->value; } +template +const T *try_get(const pool_type *object) { + return object->value; +} +template +T *try_get(const pool_type *object) { + return object->value; +} template T &get(TPool &p) { return static_cast &>(p).value; @@ -371,13 +389,21 @@ template const T &cget(const TPool &p) { return static_cast &>(p).value; } +template +T *get(TPool *p) { + return static_cast &>(p).value; +} +template +const T *cget(const TPool *p) { + return static_cast &>(p).value; +} template struct pool : pool_type... { using boost_di_inject__ = type_list; pool() = default; explicit pool(Ts... ts) : pool_type(ts)... {} template - pool(init, const pool &p) : pool_type(try_get>>(&p))... {} + pool(init, const pool &p) : pool_type(try_get>>>(&p))... {} template pool(const pool &p) : pool_type(init{}, p)... {} }; diff --git a/test/ft/dependencies.cpp b/test/ft/dependencies.cpp index 7346ba26..8c66e55d 100644 --- a/test/ft/dependencies.cpp +++ b/test/ft/dependencies.cpp @@ -142,6 +142,90 @@ test dependencies_smart_ptrs = [] { expect(sm.is(sml::X)); }; +test dependencies_with_reference = [] { + struct Data { + int m_member { 42 }; + }; + + struct c { + auto operator()() noexcept { + const auto action = [](Data& data) { expect(data.m_member == 42); }; + + using namespace sml; + return make_transition_table(*idle + event / action = X); + } + }; + + Data data; + sml::sm sm{data}; + sm.process_event(e1{}); + expect(sm.is(sml::X)); +}; + +test dependencies_with_const_reference = [] { + struct Data { + int m_member { 42 }; + }; + + struct c { + auto operator()() noexcept { + const auto action = [](const Data& data) { + expect(data.m_member == 42); + }; + + using namespace sml; + return make_transition_table(*idle + event / action = X); + } + }; + + Data data; + sml::sm sm{data}; + sm.process_event(e1{}); + expect(sm.is(sml::X)); +}; + +test dependencies_with_pointer = [] { + struct Data { + int m_member { 42 }; + }; + + struct c { + auto operator()() noexcept { + const auto action = [](Data* data) { expect(data->m_member == 42); }; + + using namespace sml; + return make_transition_table(*idle + event / action = X); + } + }; + + Data data; + sml::sm sm{&data}; + sm.process_event(e1{}); + expect(sm.is(sml::X)); +}; + +test dependencies_with_const_pointer = [] { + struct Data { + int m_member { 42 }; + }; + + struct c { + auto operator()() noexcept { + const auto action = [](const Data* data) { + expect(data->m_member == 42); + }; + + using namespace sml; + return make_transition_table(*idle + event / action = X); + } + }; + + Data data; + sml::sm sm{&data}; + sm.process_event(e1{}); + expect(sm.is(sml::X)); +}; + #if (_MSC_VER >= 1910) // MSVC 2017 test dependencies_multiple_subs = [] { struct update { From 3c0e2ee7133d174efc84dd54cc62a48373b4734c Mon Sep 17 00:00:00 2001 From: Marco Bergamin Date: Tue, 2 Jun 2020 07:23:51 -0700 Subject: [PATCH 2/2] Fixes moved type_traits.hpp and utility.hpp. Generated sml.hpp using pph.sh --- include/boost/sml.hpp | 71 +++++++++++++------------- include/boost/sml/aux_/type_traits.hpp | 10 ++++ include/boost/sml/aux_/utility.hpp | 20 +++++++- 3 files changed, 65 insertions(+), 36 deletions(-) diff --git a/include/boost/sml.hpp b/include/boost/sml.hpp index cce98e3b..17b6aa8d 100644 --- a/include/boost/sml.hpp +++ b/include/boost/sml.hpp @@ -217,7 +217,7 @@ struct remove_pointer { }; template using remove_pointer_t = typename remove_pointer::type; -} +} // namespace aux namespace aux { using swallow = int[]; template @@ -403,7 +403,8 @@ struct pool : pool_type... { pool() = default; explicit pool(Ts... ts) : pool_type(ts)... {} template - pool(init, const pool &p) : pool_type(try_get>>>(&p))... {} + pool(init, const pool &p) + : pool_type(try_get>>>(&p))... {} template pool(const pool &p) : pool_type(init{}, p)... {} }; @@ -481,7 +482,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__) @@ -526,7 +527,7 @@ struct string { } static auto c_str_impl(...) { return get_type_name(); } }; -} +} // namespace aux namespace back { namespace policies { struct defer_queue_policy__ {}; @@ -536,8 +537,8 @@ struct defer_queue : aux::pair; using flag = bool; }; -} -} +} // namespace policies +} // namespace back namespace back { template class queue_event { @@ -628,7 +629,7 @@ struct deque_handler : queue_event_call... { } void *deque_{}; }; -} +} // namespace back namespace back { struct _ {}; struct initial {}; @@ -710,7 +711,7 @@ template struct defer : deque_handler { using deque_handler::deque_handler; }; -} +} // namespace back namespace back { template class sm; @@ -833,7 +834,7 @@ template struct convert_to_sm> { using type = aux::type_list, sm_impl>...>; }; -} +} // namespace back namespace back { template class sm; @@ -919,7 +920,7 @@ struct transitions_sub> { return sub_sm>::get(&subs).template process_event(event, deps, subs); } }; -} +} // namespace back namespace back { template class sm; @@ -1037,7 +1038,7 @@ struct get_event_mapping_impl_helper, TMappings> : decltype(get_event_mapping_impl>((TMappings *)0)) {}; template using get_event_mapping_t = get_event_mapping_impl_helper; -} +} // namespace back namespace back { namespace policies { struct dispatch_policy__ {}; @@ -1112,8 +1113,8 @@ struct fold_expr { } }; #endif -} -} +} // namespace policies +} // namespace back namespace back { template class sm; @@ -1180,8 +1181,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 +1191,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 +1218,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 +1258,7 @@ struct sm_policy { template using rebind = typename rebind_impl::type; }; -} +} // namespace back namespace concepts { struct callable_fallback { void operator()(); @@ -1269,7 +1270,7 @@ aux::true_type test_callable(...); template struct callable : decltype(test_callable, callable_fallback>>(0)) {}; -} +} // namespace concepts namespace concepts { template decltype(aux::declval().operator()()) composable_impl(int); @@ -1277,7 +1278,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 @@ -1754,7 +1755,7 @@ class sm { deps_t deps_; sub_sms_t sub_sms_; }; -} +} // namespace back namespace front { struct operator_base {}; struct action_base {}; @@ -1988,7 +1989,7 @@ class not_ : operator_base { private: T g; }; -} +} // namespace front template ::value)> auto operator!(const T &t) { return front::not_>(aux::zero_wrapper{t}); @@ -2017,8 +2018,8 @@ struct defer : action_base { } } }; -} -} +} // namespace actions +} // namespace front using testing = back::policies::testing; template using logger = back::policies::logger; @@ -2044,7 +2045,7 @@ auto transitional_impl(T &&t) -> aux::always; template struct transitional : decltype(transitional_impl(aux::declval())) {}; -} +} // namespace concepts namespace front { namespace actions { struct process { @@ -2065,8 +2066,8 @@ struct process { return process_impl{event}; } }; -} -} +} // namespace actions +} // namespace front namespace front { template struct transition_eg; @@ -2084,7 +2085,7 @@ struct event { } auto operator()() const { return TEvent{}; } }; -} +} // namespace front namespace front { struct initial_state {}; struct history_state {}; @@ -2177,7 +2178,7 @@ struct state_sm::value>> { using type = state>>; }; #endif -} +} // namespace front namespace front { struct internal {}; template @@ -2627,7 +2628,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 @@ -2675,7 +2676,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/aux_/type_traits.hpp b/include/boost/sml/aux_/type_traits.hpp index fe9fc653..a79fe50a 100644 --- a/include/boost/sml/aux_/type_traits.hpp +++ b/include/boost/sml/aux_/type_traits.hpp @@ -175,6 +175,16 @@ struct remove_reference { template using remove_reference_t = typename remove_reference::type; +template +struct remove_pointer { + using type = T; +}; +template +struct remove_pointer { + using type = T; +}; +template +using remove_pointer_t = typename remove_pointer::type; } // namespace aux #endif diff --git a/include/boost/sml/aux_/utility.hpp b/include/boost/sml/aux_/utility.hpp index ce55e044..67d40bc6 100644 --- a/include/boost/sml/aux_/utility.hpp +++ b/include/boost/sml/aux_/utility.hpp @@ -190,6 +190,15 @@ T &try_get(const pool_type *object) { return object->value; } +template +const T *try_get(const pool_type *object) { + return object->value; +} +template +T *try_get(const pool_type *object) { + return object->value; +} + template T &get(TPool &p) { return static_cast &>(p).value; @@ -200,6 +209,15 @@ const T &cget(const TPool &p) { return static_cast &>(p).value; } +template +T *get(TPool *p) { + return static_cast &>(p).value; +} +template +const T *cget(const TPool *p) { + return static_cast &>(p).value; +} + template struct pool : pool_type... { using boost_di_inject__ = type_list; @@ -209,7 +227,7 @@ struct pool : pool_type... { explicit pool(Ts... ts) : pool_type(ts)... {} template - pool(init, const pool &p) : pool_type(try_get>>(&p))... {} + pool(init, const pool &p) : pool_type(try_get>>>(&p))... {} template pool(const pool &p) : pool_type(init{}, p)... {}