From ab105a9a63cd55527f8397e9e47f021cb2fccca0 Mon Sep 17 00:00:00 2001 From: Christian Granzin Date: Tue, 24 Feb 2026 19:51:31 -0500 Subject: [PATCH] refactor(backmp11): basic_polymorphic, version history Cleaned up basic_polymorphic and aligned version history with the Boost relase notes. --- .../pages/tutorial/backmp11-back-end.adoc | 4 +- doc/modules/ROOT/pages/version-history.adoc | 22 ++- include/boost/msm/backmp11/common_types.hpp | 3 - ...orphic_value.hpp => basic_polymorphic.hpp} | 186 +++++++++--------- .../backmp11/detail/state_machine_base.hpp | 8 +- .../boost/msm/backmp11/favor_compile_time.hpp | 2 + ...Value.cpp => Backmp11BasicPolymorphic.cpp} | 16 +- test/CMakeLists.txt | 6 +- test/Jamfile.v2 | 2 +- 9 files changed, 131 insertions(+), 118 deletions(-) rename include/boost/msm/backmp11/detail/{basic_polymorphic_value.hpp => basic_polymorphic.hpp} (63%) rename test/{Backmp11BasicPolymorphicValue.cpp => Backmp11BasicPolymorphic.cpp} (91%) diff --git a/doc/modules/ROOT/pages/tutorial/backmp11-back-end.adoc b/doc/modules/ROOT/pages/tutorial/backmp11-back-end.adoc index 7e229f83..007193eb 100644 --- a/doc/modules/ROOT/pages/tutorial/backmp11-back-end.adoc +++ b/doc/modules/ROOT/pages/tutorial/backmp11-back-end.adoc @@ -15,7 +15,7 @@ It offers a significant improvement in runtime and memory usage, as can be seen | back | 14 | 815 | 68 | 2.8 | back_favor_compile_time | 17 | 775 | 226 | 3.5 | back11 | 37 | 2682 | 84 | 2.8 -| backmp11 | 3 | 209 | 29 | 0.7 +| backmp11 | 3 | 209 | 28 | 0.7 | backmp11_favor_compile_time | 3 | 195 | 43 | 6.0 | sml | 5 | 234 | 57 | 0.3 |======================================================================================================= @@ -28,7 +28,7 @@ It offers a significant improvement in runtime and memory usage, as can be seen | | Compile time / sec | Compile RAM / MB | Binary size / kB | Runtime / sec | back | 49 | 2165 | 230 | 13.2 | back_favor_compile_time | 55 | 1704 | 911 | > 300 -| backmp11 | 8 | 348 | 83 | 3.4 +| backmp11 | 8 | 348 | 79 | 3.3 | backmp11_favor_compile_time | 5 | 261 | 97 | 20.6 | backmp11_favor_compile_time_multi_cu | 4 | ~863 | 97 | 21.4 | sml | 18 | 543 | 422 | 5.4 diff --git a/doc/modules/ROOT/pages/version-history.adoc b/doc/modules/ROOT/pages/version-history.adoc index 093eeca9..e32339ef 100644 --- a/doc/modules/ROOT/pages/version-history.adoc +++ b/doc/modules/ROOT/pages/version-history.adoc @@ -4,15 +4,19 @@ == Boost 1.91 -* feat(backmp11): Further optimized compilation, with up to 25% faster compile times and less RAM consumption than the 1.90 version -* fix(backmp11): Incorrect FSM type in call on_entry() & on_exit() (https://github.com/boostorg/msm/issues/167[#167]) -* feat(backmp11): Merge queued & deferred events into a single event pool (https://github.com/boostorg/msm/issues/168[#168]) -* feat(backmp11): Support conditional deferral with the `deferred_events` property (https://github.com/boostorg/msm/issues/155[#155]) -* fix(backmp11): Completion events fire too often (https://github.com/boostorg/msm/issues/166[#166]) -* feat(backmp11): Small Object Optimization for events in the event pool (https://github.com/boostorg/msm/issues/172[#172]) -* feat(backmp11): Improve support for the `deferred_events` property in hierarchical state machines (https://github.com/boostorg/msm/issues/173[#173]) -* feat(backmp11): Improve runtime performance with a `flat_fold` dispatch strategy (https://github.com/boostorg/msm/issues/180[#180]) -* feat(backmp11): Simplified functor signatures (https://github.com/boostorg/msm/issues/175[#175]) +* New features (`backmp11`): +** Improve support for the `deferred_events` property in hierarchical state machines (https://github.com/boostorg/msm/issues/173[#173]) +** Support conditional deferral with the `deferred_events` property (https://github.com/boostorg/msm/issues/155[#155]) +** Simplified functor signatures (https://github.com/boostorg/msm/issues/175[#175]) +** Merge queued and deferred events into a single event pool (https://github.com/boostorg/msm/issues/168[#168]) +** Small object optimization for events in the event pool (https://github.com/boostorg/msm/issues/172[#172]) +** Improve runtime performance with a `flat_fold` dispatch strategy (https://github.com/boostorg/msm/issues/180[#180]) +** Further optimize compilation, with up to 25% faster compile times and lower RAM consumption compared to version 1.90 +* Bug fixes (`backmp11`): +** Incorrect `FSM` type in calls to `on_entry(...)` and `on_exit(...)` (https://github.com/boostorg/msm/issues/167[#167]) +** Completion events fire too often (https://github.com/boostorg/msm/issues/166[#166]) +* **Breaking change (`backmp11`)**: Direct access to the event pool is changed from `public` to `protected`, +because manipulating it outside of the library code can lead to undefined behavior. == Boost 1.90 diff --git a/include/boost/msm/backmp11/common_types.hpp b/include/boost/msm/backmp11/common_types.hpp index a52e034d..f95cb1f0 100644 --- a/include/boost/msm/backmp11/common_types.hpp +++ b/include/boost/msm/backmp11/common_types.hpp @@ -12,7 +12,6 @@ #ifndef BOOST_MSM_BACKMP11_COMMON_TYPES_HPP #define BOOST_MSM_BACKMP11_COMMON_TYPES_HPP -#include #include #include @@ -61,8 +60,6 @@ namespace boost::msm::backmp11 using process_result = back::HandledEnum; -using any_event = std::any; - // flag handling struct flag_or {}; struct flag_and {}; diff --git a/include/boost/msm/backmp11/detail/basic_polymorphic_value.hpp b/include/boost/msm/backmp11/detail/basic_polymorphic.hpp similarity index 63% rename from include/boost/msm/backmp11/detail/basic_polymorphic_value.hpp rename to include/boost/msm/backmp11/detail/basic_polymorphic.hpp index 215e256e..7bf156d1 100644 --- a/include/boost/msm/backmp11/detail/basic_polymorphic_value.hpp +++ b/include/boost/msm/backmp11/detail/basic_polymorphic.hpp @@ -21,8 +21,8 @@ namespace boost::msm::backmp11::detail { -// Basic polymorphic value with small buffer optimization. -// Similar to standard proposal P0201 (polymorphic_value). +// Basic polymorphic value with small object optimization. +// Similar to std::polymorphic (C++26). struct control_block { @@ -84,7 +84,9 @@ struct create_control_block }; template -struct inline_control_bock +struct inline_control_bock; +template +struct inline_control_bock { inline static const control_block instance = []() constexpr { control_block self{}; @@ -126,8 +128,9 @@ const control_block& control_block_v = struct inline_tag {}; -template -class basic_polymorphic_value_base +template +class basic_polymorphic_base { static_assert(BufferSize <= 255, "BufferSize must not be bigger than 255 Bytes"); @@ -138,59 +141,100 @@ class basic_polymorphic_value_base return m_control_block->is_inline; } - protected: - explicit basic_polymorphic_value_base(const control_block& class_data) - : m_control_block(&class_data) + void* get() const noexcept { + if (m_control_block->is_inline) + { + return const_cast(reinterpret_cast(&m_buffer)); + } + else + { + return m_ptr; + } } - basic_polymorphic_value_base(const void* src, const control_block& class_data, - inline_tag) - : m_control_block(&class_data) - { - std::memcpy(&this->m_buffer, src, m_control_block->size); - } + protected: + template + using IsInline = std::bool_constant< + sizeof(U) <= BufferSize && + alignof(U) <= BufferAlignment>; + + template + static constexpr bool is_nothrow_constructible_v = + std::is_trivially_copyable_v && IsInline::value; - basic_polymorphic_value_base(void* ptr, control_block& class_data) - : m_control_block(&class_data) + template + explicit basic_polymorphic_base(const U& obj) noexcept( + is_nothrow_constructible_v) + : m_control_block(&control_block_v::value>) { - m_ptr = ptr; + if constexpr (IsInline::value) + { + if constexpr (std::is_trivially_copyable_v) + { + std::memcpy(&m_buffer, &obj, sizeof(U)); + } + else + { + new (&m_buffer) U(obj); + } + } + else + { + m_ptr = new U(obj); + } } - ~basic_polymorphic_value_base() + template + explicit basic_polymorphic_base( + std::in_place_type_t, + Args&&... args) noexcept(is_nothrow_constructible_v) + : m_control_block(&control_block_v::value>) { - m_control_block->destroy(get()); + if constexpr (IsInline::value) + { + new (&m_buffer) U(std::forward(args)...); + } + else + { + m_ptr = new U(std::forward(args)...); + } } - basic_polymorphic_value_base(const basic_polymorphic_value_base&) = delete; - basic_polymorphic_value_base& operator=(const basic_polymorphic_value_base&) = delete; + // Moveable is enough for our needs. + // Removing the copy operators ensures we do not accidentally copy the value. + basic_polymorphic_base(const basic_polymorphic_base& rhs) = delete; + basic_polymorphic_base& operator=(const basic_polymorphic_base& rhs) = delete; - basic_polymorphic_value_base(basic_polymorphic_value_base&& other) noexcept + basic_polymorphic_base(basic_polymorphic_base&& other) noexcept : m_control_block(other.m_control_block) { m_control_block->move(m_ptr, other.m_ptr); } - basic_polymorphic_value_base& operator=(basic_polymorphic_value_base&& other) noexcept + basic_polymorphic_base& operator=(basic_polymorphic_base&& other) noexcept { if (this != &other) { - m_control_block->destroy(get()); + destroy(); m_control_block = other.m_control_block; m_control_block->move(m_ptr, other.m_ptr); } return *this; } - void* get() const noexcept + ~basic_polymorphic_base() { - if (m_control_block->is_inline) - { - return const_cast(reinterpret_cast(&m_buffer)); - } - else + destroy(); + } + + private: + void destroy() + { + m_control_block->destroy(get());; + if (!m_control_block->is_inline) { - return m_ptr; + m_ptr = nullptr; } } @@ -204,76 +248,41 @@ class basic_polymorphic_value_base template -class basic_polymorphic_value - : public basic_polymorphic_value_base +class basic_polymorphic + : public basic_polymorphic_base { - private: - using destroy_fn_t = void(*)(T* ptr) noexcept; - using base = basic_polymorphic_value_base; - - template - using IsInline = std::bool_constant< - sizeof(U) <= BufferSize && - alignof(U) <= BufferAlignment>; + using base = basic_polymorphic_base; public: - basic_polymorphic_value(basic_polymorphic_value&& other) noexcept = default; - basic_polymorphic_value& operator=(basic_polymorphic_value&& other) noexcept = default; + basic_polymorphic(basic_polymorphic&& other) noexcept = default; + basic_polymorphic& operator=(basic_polymorphic&& other) noexcept = default; - template ::value> - struct make_impl; - template - struct make_impl + template >> + explicit basic_polymorphic(const U& obj) noexcept(base::template is_nothrow_constructible_v) + : base(obj) { - static_assert(std::is_base_of_v, "U must be derived from T"); - - static basic_polymorphic_value make(const U& obj) - { - if constexpr (std::is_trivially_copyable_v) - { - return basic_polymorphic_value{&obj, control_block_v, - inline_tag{}}; - } - else - { - basic_polymorphic_value self{control_block_v}; - new (&self.m_buffer) U(obj); - return self; - } - } + } - template - static basic_polymorphic_value make(Args&&... args) - { - basic_polymorphic_value self{control_block_v}; - new (&self.m_buffer) U(std::forward(args)...); - return self; - } - }; - template - struct make_impl + template >> + explicit basic_polymorphic(std::in_place_type_t in_place, + Args&&... args) noexcept(base::template is_nothrow_constructible_v) + : base(in_place, std::forward(args)...) { - static_assert(std::is_base_of_v, "U must be derived from T"); - - template - static basic_polymorphic_value make(Args&&... args) - { - basic_polymorphic_value self{control_block_v}; - self.m_ptr = new U(std::forward(args)...); - return self; - } - }; + } template - static basic_polymorphic_value make(Args&&... args) + static basic_polymorphic make(Args&&... args) { - return make_impl::make(std::forward(args)...); + return basic_polymorphic{std::in_place_type, + std::forward(args)...}; }; template - static constexpr basic_polymorphic_value make(const U& obj) + static basic_polymorphic make(const U& obj) { - return make_impl::make(obj); + return basic_polymorphic{obj}; }; T* get() const noexcept @@ -290,9 +299,6 @@ class basic_polymorphic_value { return get(); } - - protected: - using base::base; }; } // namespace boost::msm::backmp11::detail diff --git a/include/boost/msm/backmp11/detail/state_machine_base.hpp b/include/boost/msm/backmp11/detail/state_machine_base.hpp index 9f8631c4..452d8884 100644 --- a/include/boost/msm/backmp11/detail/state_machine_base.hpp +++ b/include/boost/msm/backmp11/detail/state_machine_base.hpp @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include #include @@ -148,7 +148,7 @@ class state_machine_base : public FrontEnd using states_t = mp11::mp_rename; protected: - using processable_event = basic_polymorphic_value; + using processable_event = basic_polymorphic; template using event_container = typename config_t::template event_container; using event_container_t = event_container; @@ -399,7 +399,7 @@ class state_machine_base : public FrontEnd typename = std::enable_if_t> inline size_t process_event_pool(size_t max_events = SIZE_MAX) { - if (get_event_pool().events.empty()) + if (get_event_pool().events.empty() || m_event_processing) { return 0; } @@ -869,7 +869,7 @@ class state_machine_base : public FrontEnd } } #else - result = Transition::execute(self(), state_id, event); + result = Transition::execute(self(), region_id, event); #endif m_event_processing = false; return result; diff --git a/include/boost/msm/backmp11/favor_compile_time.hpp b/include/boost/msm/backmp11/favor_compile_time.hpp index 342ad35c..82b6d6ef 100644 --- a/include/boost/msm/backmp11/favor_compile_time.hpp +++ b/include/boost/msm/backmp11/favor_compile_time.hpp @@ -49,6 +49,8 @@ struct favor_compile_time namespace detail { +using any_event = std::any; + template <> struct compile_policy_impl { diff --git a/test/Backmp11BasicPolymorphicValue.cpp b/test/Backmp11BasicPolymorphic.cpp similarity index 91% rename from test/Backmp11BasicPolymorphicValue.cpp rename to test/Backmp11BasicPolymorphic.cpp index 1fd19fd2..319f4c66 100644 --- a/test/Backmp11BasicPolymorphicValue.cpp +++ b/test/Backmp11BasicPolymorphic.cpp @@ -10,14 +10,14 @@ // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_MSM_NONSTANDALONE_TEST -#define BOOST_TEST_MODULE backmp11_basic_polymorphic_value +#define BOOST_TEST_MODULE backmp11_basic_polymorphic #endif #include -#include +#include #include "Utils.hpp" -using boost::msm::backmp11::detail::basic_polymorphic_value; +using boost::msm::backmp11::detail::basic_polymorphic; namespace { @@ -29,7 +29,7 @@ struct trivial_class BOOST_AUTO_TEST_CASE(trivial_class_test) { - using ptr_t = basic_polymorphic_value; + using ptr_t = basic_polymorphic; static_assert(sizeof(ptr_t) == 64); ptr_t ptr = ptr_t::make(trivial_class{42}); @@ -52,7 +52,7 @@ struct class_with_destructor size_t class_with_destructor::destructor_calls{}; BOOST_AUTO_TEST_CASE(class_with_destructor_test) { - using ptr_t = basic_polymorphic_value; + using ptr_t = basic_polymorphic; [[maybe_unused]] size_t& destructor_calls = class_with_destructor::destructor_calls; @@ -104,7 +104,7 @@ struct big_class_with_destructor size_t big_class_with_destructor::destructor_calls{}; BOOST_AUTO_TEST_CASE(big_class_with_destructor_test) { - using ptr_t = basic_polymorphic_value; + using ptr_t = basic_polymorphic; { ptr_t ptr = ptr_t::make(42); BOOST_REQUIRE(!ptr.is_inline()); @@ -133,7 +133,7 @@ struct sub_class__with_destructor : class_with_destructor size_t sub_class__with_destructor::destructor_calls{}; BOOST_AUTO_TEST_CASE(two_destructors_test) { - using ptr_t = basic_polymorphic_value; + using ptr_t = basic_polymorphic; [[maybe_unused]] size_t& destructor_calls_0 = class_with_destructor::destructor_calls; [[maybe_unused]] size_t& destructor_calls_1 = sub_class__with_destructor::destructor_calls; @@ -191,7 +191,7 @@ struct other_virtual_class : virtual_class size_t other_virtual_class::method_calls{}; BOOST_AUTO_TEST_CASE(virtual_class_test) { - using ptr_t = basic_polymorphic_value; + using ptr_t = basic_polymorphic; ptr_t ptr = ptr_t::make(); BOOST_REQUIRE(ptr.is_inline()); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 2bb7f32e..2f385d60 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -14,6 +14,10 @@ endif() if(BOOST_MSM_TEST_STRICT) add_compile_options(-Wall -Wextra -Werror -Wno-language-extension-token) endif() +if(BOOST_MSM_TEST_ENABLE_SANITIZERS) + add_compile_options(-fsanitize=address -fno-omit-frame-pointer) + add_link_options(-fsanitize=address -fno-omit-frame-pointer) +endif() add_executable(boost_msm_tests @@ -72,7 +76,7 @@ add_dependencies(tests boost_msm_euml_tests) add_executable(boost_msm_cxx17_tests EXCLUDE_FROM_ALL - Backmp11BasicPolymorphicValue.cpp + Backmp11BasicPolymorphic.cpp Backmp11Completion.cpp Backmp11Constructor.cpp Backmp11Context.cpp diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index d45363f5..dc938ded 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -76,7 +76,7 @@ test-suite msm-unit-tests test-suite msm-unit-tests-cxxstd17 : - [ run Backmp11BasicPolymorphicValue.cpp ] + [ run Backmp11BasicPolymorphic.cpp ] [ run Backmp11Completion.cpp ] [ run Backmp11Constructor.cpp ] [ run Backmp11Context.cpp ]