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
12 changes: 8 additions & 4 deletions doc/modules/ROOT/pages/tutorial/backmp11-back-end.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ 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_favor_compile_time | 3 | 193 | 43 | 6.0
| backmp11 | 3 | 211 | 29 | 0.7
| backmp11_favor_compile_time | 3 | 195 | 43 | 6.0
| sml | 5 | 234 | 57 | 0.3
|=======================================================================================================

Expand All @@ -28,8 +28,8 @@ 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 | 351 | 85 | 3.3
| backmp11_favor_compile_time | 5 | 256 | 100 | 20.4
| backmp11 | 8 | 354 | 85 | 3.4
| backmp11_favor_compile_time | 5 | 262 | 100 | 20.4
| backmp11_favor_compile_time_multi_cu | 5 | ~863 | 100 | 20.8
| sml | 18 | 543 | 422 | 5.4
|================================================================================================================
Expand Down Expand Up @@ -170,6 +170,10 @@ If the type of the state appears multiple times in a hierarchical state machine,
// - if `start()` is called for a running state machine, the call is ignored
// - if `stop()` is called on a stopped (not running) state machine, the call is ignored

=== Support for simplified functor signatures

Further described in xref:./functor-front-end.adoc#simplified_functor_signatures[the functor front-end documentation].


=== Simplified state machine signature

Expand Down
89 changes: 85 additions & 4 deletions doc/modules/ROOT/pages/tutorial/functor-front-end.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ Row < Paused , stop , Stopped , stop_playback , none
Row < Paused , open_close , Open , stop_and_open , none >
// +---------+------------+-----------+---------------------------+----------------------------+
> {};

----

Transitions are now of type "Row" with exactly 5 template arguments:
Expand All @@ -66,12 +65,12 @@ detected event, the state machine, source and target state:
----
struct store_cd_info
{
template <class Fsm,class Evt,class SourceState,class TargetState>
void operator()(Evt const&, Fsm& fsm, SourceState&,TargetState& )
template <class Event, class Fsm, class SourceState, class TargetState>
void operator()(Event const&, Fsm& fsm, SourceState&, TargetState&)
{
cout << "player::store_cd_info" << endl;
fsm.process_event(play());
}
}
};
----

Expand Down Expand Up @@ -119,6 +118,88 @@ It even starts looking like functional programming. MSM ships with
functors for operators, state machine usage, STL algorithms or container
methods.


== Using lambdas as functors ({cpp}20)

If {cpp}20 is available you can shorten the functor syntax by using lambdas as functors.
The `store_cd_info` functor can be rewritten with a lambda as follows:

[source,cpp]
----
using store_cd_info = msm::front::Lambda<
[](auto const& /*event*/, auto& fsm, auto& /*source*/, auto& /*target*/)
{
cout << "player::store_cd_info" << endl;
fsm.process_event(play());
}>;
----

[[simplified_functor_signatures]]
== Simplified functor signatures (`backmp11` only)

The `backmp11` back-end allows you to use shorter functor signatures, reducing the boilerplate of action and guard functor definitions. It automatically detects how many parameters your functors have and invokes them with the appropriate arguments.

The following three signatures are supported:

**Full signature**

[source,cpp]
----
struct store_cd_info
{
template <class Event, class Fsm, class SourceState, class TargetState>
void operator()(Event const&, Fsm& fsm, SourceState&, TargetState&)
{
cout << "player::store_cd_info" << endl;
fsm.process_event(play());
}
};
----

**Event and FSM only**

[source,cpp]
----
struct store_cd_info
{
template <class Event, class Fsm>
void operator()(Event const&, Fsm& fsm)
{
cout << "player::store_cd_info" << endl;
fsm.process_event(play());
}
};
----

**FSM only**

[source,cpp]
----
struct store_cd_info
{
template <class Fsm>
void operator()(Fsm& fsm)
{
cout << "player::store_cd_info" << endl;
fsm.process_event(play());
}
};
----

Simplified signatures are also supported with lambdas, providing a way to define
functors with minimal boilerplate:

[source,cpp]
----
using store_cd_info = msm::front::Lambda<
[](auto& fsm)
{
cout << "player::store_cd_info" << endl;
fsm.process_event(play());
}>;
----


[[defining-states-with-entryexit-actions]]

== Defining states with entry/exit actions
Expand Down
1 change: 1 addition & 0 deletions doc/modules/ROOT/pages/version-history.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
* 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])

== Boost 1.90

Expand Down
117 changes: 115 additions & 2 deletions include/boost/msm/backmp11/detail/transition_table.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,111 @@
#include <boost/msm/backmp11/detail/metafunctions.hpp>
#include "boost/msm/backmp11/state_machine_config.hpp"

namespace boost::msm::front
{
struct Defer;
};

namespace boost::msm::backmp11::detail
{

// Chain of priority tags for SFINAE handling:
// priority_tag_0
// ↓ (SFINAE fails?)
// priority_tag_1 (base of priority_tag_0)
// ↓ (SFINAE fails?)
// priority_tag_2 (base of priority_tag_1)
struct priority_tag_2 {};
struct priority_tag_1 : priority_tag_2 {};
struct priority_tag_0 : priority_tag_1 {};

template <typename Functor, typename Event, typename Fsm, typename Source,
typename Target>
auto invoke_functor(priority_tag_0, Functor&&, const Event& event, Fsm& fsm,
Source& source, Target& target)
-> decltype(Functor{}(event, fsm, source, target))
{
return Functor{}(event, fsm, source, target);
}
template <typename Functor, typename Event, typename Fsm, typename Source,
typename Target>
auto invoke_functor(priority_tag_1, Functor&&, const Event& event, Fsm& fsm, Source&,
Target&) -> decltype(Functor{}(event, fsm))
{
return Functor{}(event, fsm);
}
template <typename Functor, typename Event, typename Fsm, typename Source,
typename Target>
auto invoke_functor(priority_tag_2, Functor&&, const Event&, Fsm& fsm, Source&,
Target&) -> decltype(Functor{}(fsm))
{
return Functor{}(fsm);
}

template <typename Row>
using get_Guard = typename Row::Guard;
template <typename Row>
struct has_Guard : mp11::mp_valid<get_Guard, Row> {};

template <typename Functor>
struct invoke_guard_functor
{
template <typename Event, typename Fsm, typename Source, typename Target>
static bool execute(const Event& event, Fsm& fsm, Source& source,
Target& target)
{
return invoke_functor<Functor>(priority_tag_0{}, Functor{}, event, fsm,
source, target);
}
};
template <>
struct invoke_guard_functor<front::none>
{
template <typename Event, typename Fsm, typename Source, typename Target>
static bool execute(const Event&, Fsm&, Source&, Target&)
{
return true;
}
};

template <typename Row>
using get_Action = typename Row::Action;
template <typename Row>
struct has_Action : mp11::mp_valid<get_Action, Row> {};

template <typename Functor>
struct invoke_action_functor
{
template <typename Event, typename Fsm, typename Source, typename Target>
static process_result execute(const Event& event, Fsm& fsm, Source& source,
Target& target)
{
invoke_functor<Functor>(priority_tag_0{}, Functor{}, event, fsm, source,
target);
return process_result::HANDLED_TRUE;
}
};
template <>
struct invoke_action_functor<front::none>
{
template <typename Event, typename Fsm, typename Source, typename Target>
static process_result execute(const Event&, Fsm&, Source&, Target&)
{
return process_result::HANDLED_TRUE;
}
};
template <>
struct invoke_action_functor<front::Defer>
{
template <typename Event, typename Fsm, typename Source, typename Target>
static process_result execute(const Event& event, Fsm& fsm, Source&,
Target&)
{
fsm.defer_event(event);
return process_result::HANDLED_DEFERRED;
}
};

template <typename StateMachine>
struct transition_table_impl
{
Expand All @@ -39,7 +141,12 @@ struct transition_table_impl
static bool call_guard_or_true(StateMachine& sm, const Event& event,
Source& source, Target& target)
{
if constexpr (HasGuard)
if constexpr (has_Guard<Row>::value)
{
return invoke_guard_functor<typename Row::Guard>::execute(
event, sm.get_fsm_argument(), source, target);
}
else if constexpr (HasGuard)
{
return Row::guard_call(
sm.get_fsm_argument(), event, source, target, sm.m_states);
Expand All @@ -49,13 +156,19 @@ struct transition_table_impl
return true;
}
}

template <typename Row, bool HasAction, typename Event, typename Source,
typename Target>
static process_result call_action_or_true(StateMachine& sm,
const Event& event,
Source& source, Target& target)
{
if constexpr (HasAction)
if constexpr (has_Action<Row>::value)
{
return invoke_action_functor<typename Row::Action>::execute(
event, sm.get_fsm_argument(), source, target);
}
else if constexpr (HasAction)
{
return Row::action_call(
sm.get_fsm_argument(), event, source, target, sm.m_states);
Expand Down
7 changes: 7 additions & 0 deletions include/boost/msm/front/functor_row.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -361,5 +361,12 @@ namespace boost { namespace msm { namespace front
fsm.defer_event(evt);
}
};

#if __cplusplus >= 202002L
// Wrapper to make a functor from a lambda.
template <auto T>
struct Lambda : decltype(T) {};
#endif

}}}
#endif //BOOST_MSM_FRONT_FUNCTOR_ROW_H
Loading