Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions doc/modules/ROOT/pages/tutorial/backmp11-back-end.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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
|=======================================================================================================
Expand All @@ -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
Expand Down
22 changes: 13 additions & 9 deletions doc/modules/ROOT/pages/version-history.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
3 changes: 0 additions & 3 deletions include/boost/msm/backmp11/common_types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
#ifndef BOOST_MSM_BACKMP11_COMMON_TYPES_HPP
#define BOOST_MSM_BACKMP11_COMMON_TYPES_HPP

#include <any>
#include <cstdint>
#include <optional>

Expand Down Expand Up @@ -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 {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -84,7 +84,9 @@ struct create_control_block<T, /*IsInline=*/false>
};

template <typename T, bool IsTriviallyCopyable>
struct inline_control_bock
struct inline_control_bock;
template <typename T>
struct inline_control_bock<T, /*IsTriviallyCopyable=*/false>
{
inline static const control_block instance = []() constexpr {
control_block self{};
Expand Down Expand Up @@ -126,8 +128,9 @@ const control_block& control_block_v =

struct inline_tag {};

template <size_t BufferSize, size_t BufferAlignment>
class basic_polymorphic_value_base
template <size_t BufferSize = 64 - sizeof(control_block*),
size_t BufferAlignment = alignof(void*)>
class basic_polymorphic_base
{
static_assert(BufferSize <= 255,
"BufferSize must not be bigger than 255 Bytes");
Expand All @@ -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<void*>(reinterpret_cast<const void*>(&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 <typename U>
using IsInline = std::bool_constant<
sizeof(U) <= BufferSize &&
alignof(U) <= BufferAlignment>;

template <typename U>
static constexpr bool is_nothrow_constructible_v =
std::is_trivially_copyable_v<U> && IsInline<U>::value;

basic_polymorphic_value_base(void* ptr, control_block& class_data)
: m_control_block(&class_data)
template <typename U>
explicit basic_polymorphic_base(const U& obj) noexcept(
is_nothrow_constructible_v<U>)
: m_control_block(&control_block_v<U, IsInline<U>::value>)
{
m_ptr = ptr;
if constexpr (IsInline<U>::value)
{
if constexpr (std::is_trivially_copyable_v<U>)
{
std::memcpy(&m_buffer, &obj, sizeof(U));
}
else
{
new (&m_buffer) U(obj);
}
}
else
{
m_ptr = new U(obj);
}
}

~basic_polymorphic_value_base()
template <typename U, typename... Args>
explicit basic_polymorphic_base(
std::in_place_type_t<U>,
Args&&... args) noexcept(is_nothrow_constructible_v<U>)
: m_control_block(&control_block_v<U, IsInline<U>::value>)
{
m_control_block->destroy(get());
if constexpr (IsInline<U>::value)
{
new (&m_buffer) U(std::forward<Args>(args)...);
}
else
{
m_ptr = new U(std::forward<Args>(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<void*>(reinterpret_cast<const void*>(&m_buffer));
}
else
destroy();
}

private:
void destroy()
{
m_control_block->destroy(get());;
if (!m_control_block->is_inline)
{
return m_ptr;
m_ptr = nullptr;
}
}

Expand All @@ -204,76 +248,41 @@ class basic_polymorphic_value_base
template <typename T,
size_t BufferSize = 64 - sizeof(control_block*),
size_t BufferAlignment = alignof(void*)>
class basic_polymorphic_value
: public basic_polymorphic_value_base<BufferSize, BufferAlignment>
class basic_polymorphic
: public basic_polymorphic_base<BufferSize, BufferAlignment>
{
private:
using destroy_fn_t = void(*)(T* ptr) noexcept;
using base = basic_polymorphic_value_base<BufferSize, BufferAlignment>;

template <typename U>
using IsInline = std::bool_constant<
sizeof(U) <= BufferSize &&
alignof(U) <= BufferAlignment>;
using base = basic_polymorphic_base<BufferSize, BufferAlignment>;

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 <typename U, bool IsInline = IsInline<U>::value>
struct make_impl;
template <typename U>
struct make_impl<U, /*IsInline=*/true>
template <typename U,
typename = std::enable_if_t<std::is_base_of_v<T, U>>>
explicit basic_polymorphic(const U& obj) noexcept(base::template is_nothrow_constructible_v<U>)
: base(obj)
{
static_assert(std::is_base_of_v<T, U>, "U must be derived from T");

static basic_polymorphic_value make(const U& obj)
{
if constexpr (std::is_trivially_copyable_v<U>)
{
return basic_polymorphic_value{&obj, control_block_v<U, true>,
inline_tag{}};
}
else
{
basic_polymorphic_value self{control_block_v<U, true>};
new (&self.m_buffer) U(obj);
return self;
}
}
}

template <typename... Args>
static basic_polymorphic_value make(Args&&... args)
{
basic_polymorphic_value self{control_block_v<U, true>};
new (&self.m_buffer) U(std::forward<Args>(args)...);
return self;
}
};
template <typename U>
struct make_impl<U, /*IsInline=*/false>
template <typename U, typename... Args,
typename = std::enable_if_t<std::is_base_of_v<T, U>>>
explicit basic_polymorphic(std::in_place_type_t<U> in_place,
Args&&... args) noexcept(base::template is_nothrow_constructible_v<U>)
: base(in_place, std::forward<Args>(args)...)
{
static_assert(std::is_base_of_v<T, U>, "U must be derived from T");

template <typename... Args>
static basic_polymorphic_value make(Args&&... args)
{
basic_polymorphic_value self{control_block_v<U, false>};
self.m_ptr = new U(std::forward<Args>(args)...);
return self;
}
};
}

template <typename U, typename... Args>
static basic_polymorphic_value make(Args&&... args)
static basic_polymorphic make(Args&&... args)
{
return make_impl<U>::make(std::forward<Args>(args)...);
return basic_polymorphic{std::in_place_type<U>,
std::forward<Args>(args)...};
};

template <typename U>
static constexpr basic_polymorphic_value make(const U& obj)
static basic_polymorphic make(const U& obj)
{
return make_impl<U>::make(obj);
return basic_polymorphic{obj};
};

T* get() const noexcept
Expand All @@ -290,9 +299,6 @@ class basic_polymorphic_value
{
return get();
}

protected:
using base::base;
};

} // namespace boost::msm::backmp11::detail
Expand Down
8 changes: 4 additions & 4 deletions include/boost/msm/backmp11/detail/state_machine_base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

#include <boost/msm/active_state_switching_policies.hpp>
#include <boost/msm/row_tags.hpp>
#include <boost/msm/backmp11/detail/basic_polymorphic_value.hpp>
#include <boost/msm/backmp11/detail/basic_polymorphic.hpp>
#include <boost/msm/backmp11/detail/favor_runtime_speed.hpp>
#include <boost/msm/backmp11/detail/history_impl.hpp>
#include <boost/msm/backmp11/detail/state_visitor.hpp>
Expand Down Expand Up @@ -148,7 +148,7 @@ class state_machine_base : public FrontEnd
using states_t = mp11::mp_rename<typename internal::state_set, std::tuple>;

protected:
using processable_event = basic_polymorphic_value<event_occurrence>;
using processable_event = basic_polymorphic<event_occurrence>;
template <typename T>
using event_container = typename config_t::template event_container<T>;
using event_container_t = event_container<processable_event>;
Expand Down Expand Up @@ -399,7 +399,7 @@ class state_machine_base : public FrontEnd
typename = std::enable_if_t<C>>
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;
}
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions include/boost/msm/backmp11/favor_compile_time.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ struct favor_compile_time
namespace detail
{

using any_event = std::any;

template <>
struct compile_policy_impl<favor_compile_time>
{
Expand Down
Loading