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: 3 additions & 9 deletions doc/local-playbook.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,26 +40,20 @@ site:

antora:
extensions:
- require: '@cppalliance/antora-playbook-macros-extension'
macros:
# Default values for macros
# These values can be overridden with environment variables,
# asciidoc.attributes, or --attribute command line option.
page-boost-branch: develop
page-boost-ui-branch: develop
page-commit-id: '000000'
- require: '@antora/lunr-extension'
index_latest_only: true
- require: '@cppalliance/antora-cpp-tagfiles-extension'
cpp-tagfiles:
using-namespaces:
- 'boost::'
- require: '@cppalliance/antora-downloads-extension'
- require: '@cppalliance/antora-cpp-reference-extension'
dependencies:
- name: 'boost'
repo: 'https://github.com/boostorg/boost.git'
tag: 'develop'
variable: 'BOOST_SRC_DIR'
system-env: 'BOOST_SRC_DIR'
- require: '@cppalliance/antora-downloads-extension'

asciidoc:
attributes:
Expand Down
2 changes: 2 additions & 0 deletions doc/modules/ROOT/pages/tutorial/backmp11-back-end.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,8 @@ It can be copied and adapted if needed, though this class is internal to the tes
To reduce the number of required header inclusions, `backmp11` uses `std::any` for defining Kleene events instead of `boost::any`.
You can opt in to use `boost::any` support by including `boost/msm/event_traits.h`.

Futhermore, the back-end forwards Kleene events without converting them to `std::any` or `boost:any`. Actions and guards receive the original event.


=== Removed features

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 @@ -9,6 +9,7 @@
** The APIs `process_queued_events()` and `process_single_queued_event()` are removed, use `process_event_pool(...)` instead
** The default active state switch policy is set to "after source exit" in compliance to the UML specification. The other options are not UML-compliant and will be removed in version 1.93 (https://github.com/boostorg/msm/issues/222[#222])
* New features (`backmp11`):
** Forward Kleene events to actions and guards without conversion (https://github.com/boostorg/msm/issues/229[#229])
** Ensure basic exception guarantee and propagate exceptions to the caller (https://github.com/boostorg/msm/issues/221[#221])
** Provide a reflection API and serialization support for Boost.Serialization, Boost.JSON and nlohmann/json (https://github.com/boostorg/msm/issues/197[#197])
* Bug fixes (`backmp11`):
Expand Down
96 changes: 9 additions & 87 deletions include/boost/msm/backmp11/detail/favor_runtime_speed.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,49 +112,13 @@ struct compile_policy_impl<
{
if (is_event_deferred(sm, event))
{
defer_event(sm, event, false);
sm.defer_event(event);
return true;
}
}
return false;
}

template <typename StateMachine, typename Event>
static void defer_event(StateMachine& sm, Event const& event,
bool next_rtc_seq)
{
if constexpr (is_kleene_event<Event>::value)
{
using event_set = generate_event_set<
typename StateMachine::front_end_t::transition_table>;
bool found =
mp_for_each_until<mp11::mp_transform<mp11::mp_identity, event_set>>(
[&sm, &event, next_rtc_seq](auto event_identity)
{
using KnownEvent = typename decltype(event_identity)::type;
if (event.type() == typeid(KnownEvent))
{
sm.do_defer_event(*any_cast<KnownEvent>(&event),
next_rtc_seq);
return true;
}
return false;
}
);
if (!found)
{
for (const auto state_id : sm.get_active_state_ids())
{
sm.no_transition(event, sm.get_fsm_argument(), state_id);
}
}
}
else
{
sm.do_defer_event(event, next_rtc_seq);
}
}

// Generates a singleton runtime lookup table that maps current state
// to a function that makes the SM take its transition on the given
// Event type.
Expand All @@ -181,7 +145,7 @@ struct compile_policy_impl<
{
if constexpr (has_internal_transitions::value)
{
return internal_dispatch_impl::transition::execute(sm, event);
return internal_dispatch_impl::transition::process(sm, event);
}
return process_result::HANDLED_FALSE;
}
Expand Down Expand Up @@ -301,7 +265,7 @@ struct compile_policy_impl<
using next_state_type = Submachine;
using transition_event = Event;

static process_result execute(StateMachine& sm,
static process_result process(StateMachine& sm,
uint8_t region_id,
Event const& event)
{
Expand Down Expand Up @@ -352,15 +316,6 @@ struct compile_policy_impl<
using merged_transitions =
mp11::mp_transform<merge_transitions,
filtered_transitions_by_state_map>;

template <typename Transition>
static process_result convert_event_and_execute(StateMachine& sm,
uint8_t region_id,
Event const& evt)
{
typename Transition::transition_event kleene_event{evt};
return Transition::execute(sm, region_id, kleene_event);
}
};

template <typename Strategy, typename NotExplicit = void>
Expand All @@ -381,29 +336,15 @@ struct compile_policy_impl<
[&sm, region_id, &event, state_id, &result](auto transition)
{
using Transition = decltype(transition);
using TransitionEvent =
typename Transition::transition_event;
using SourceState =
typename Transition::current_state_type;
constexpr auto source_state_id =
StateMachine::template get_state_id<SourceState>();
if (state_id == source_state_id)
{
if constexpr (!is_kleene_event<
TransitionEvent>::value)
{
result =
Transition::execute(sm, region_id, event);
}
else
{
result =
base::template convert_event_and_execute<
Transition>(sm, region_id, event);
}
result = Transition::process(sm, region_id, event);
}
}
);
});
return result;
}
};
Expand All @@ -417,7 +358,7 @@ struct compile_policy_impl<
Event const&);

public:
static process_result dispatch(
static inline process_result dispatch(
StateMachine& sm, uint8_t region_id, const Event& event)
{
const auto state_id = sm.m_active_state_ids[region_id];
Expand All @@ -431,25 +372,6 @@ struct compile_policy_impl<
}

private:
// Convert a transition to its function pointer.
template <typename Transition,
bool IsKleeneEvent = is_kleene_event<
typename Transition::transition_event>::value>
struct get_cell;
template <typename Transition>
struct get_cell<Transition, /*IsKleeneEvent=*/false>
{
static constexpr cell_t value = &Transition::execute;
};
template <typename Transition>
struct get_cell<Transition, /*IsKleeneEvent=*/true>
{
static constexpr cell_t value =
&base::template convert_event_and_execute<Transition>;
};
template <typename Transition>
static constexpr cell_t cell_v = get_cell<Transition>::value;

struct cell_table
{
cell_t data[max_state]{};
Expand All @@ -466,7 +388,7 @@ struct compile_policy_impl<
((table.data[
StateMachine::template get_state_id<
typename Transitions::current_state_type>()] =
get_cell<Transitions>::value), ...);
&Transitions::process), ...);
return table;
}

Expand All @@ -487,14 +409,14 @@ struct compile_policy_impl<
{
using transition_event = Event;

static process_result execute(StateMachine& sm, Event const& evt)
static process_result process(StateMachine& sm, Event const& evt)
{
process_result result = process_result::HANDLED_FALSE;
mp_for_each_until<Transitions>(
[&result, &sm, &evt](auto transition)
{
using Transition = decltype(transition);
result |= Transition::execute(sm, evt);
result |= Transition::process(sm, evt);
if (result & handled_true_or_deferred)
{
// If a guard rejected previously,
Expand Down
44 changes: 30 additions & 14 deletions include/boost/msm/backmp11/detail/transition_table.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ namespace boost::msm::backmp11::detail
// ↓ (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_3 {};
struct priority_tag_2 : priority_tag_3 {};
struct priority_tag_1 : priority_tag_2 {};
struct priority_tag_0 : priority_tag_1 {};

Expand All @@ -60,6 +61,18 @@ auto invoke_functor(priority_tag_2, Functor&&, const Event&, Fsm& fsm, Source&,
{
return Functor{}(fsm);
}
template <typename...>
inline constexpr bool invokable = false;
template <typename Functor, typename Event, typename Fsm, typename Source,
typename Target>
auto invoke_functor(priority_tag_3, Functor&&, const Event&, Fsm&, Source&,
Target&)
{
static_assert(
invokable<Functor, Event, Fsm, Source, Target>,
"Action/Guard must be invokable with one of these signatures: "
"(event, fsm, source, target), (event, fsm), or (fsm)");
}

template <typename Row>
using get_Guard = typename Row::Guard;
Expand Down Expand Up @@ -230,10 +243,10 @@ struct transition_table_impl
using next_state_type =
convert_target_state<derived_t, typename Row::Target>;

// Take the transition action and return the next state.
static process_result execute(StateMachine& sm,
template <typename Event>
static process_result process(StateMachine& sm,
uint8_t region_id,
transition_event const& event)
const Event& event)
{
auto& state_id = sm.m_active_state_ids[region_id];
[[maybe_unused]] constexpr auto current_state_id =
Expand Down Expand Up @@ -298,10 +311,10 @@ struct transition_table_impl
using current_state_type = State;
using next_state_type = current_state_type;

// Take the transition action and return the next state.
static process_result execute(StateMachine& sm,
template <typename Event>
static process_result process(StateMachine& sm,
uint8_t region_id,
transition_event const& event)
const Event& event)
{
[[maybe_unused]] const auto state_id = sm.m_active_state_ids[region_id];
BOOST_ASSERT(
Expand All @@ -326,9 +339,9 @@ struct transition_table_impl
{
using transition_event = typename Row::Evt;

// Take the transition action and return the next state.
static process_result execute(StateMachine& sm,
transition_event const& event)
template <typename Event>
static process_result process(StateMachine& sm,
const Event& event)
{
auto& source = sm;
auto& target = source;
Expand Down Expand Up @@ -444,7 +457,8 @@ struct transition_table_impl

// Completion transitions are handled separately per state.
template <typename Transition>
using has_completion_event = has_completion_event<typename Transition::transition_event>;
using has_completion_event =
has_completion_event<typename Transition::transition_event>;
using completion_transition_table =
mp11::mp_copy_if<transition_table, has_completion_event>;
static_assert(mp11::mp_empty<completion_transition_table>::value ||
Expand Down Expand Up @@ -491,14 +505,16 @@ struct transition_chain
using current_state_type = State;
using transition_event = Event;

static process_result execute(StateMachine& sm, uint8_t region_id, Event const& evt)
static process_result process(StateMachine& sm,
uint8_t region_id,
const Event& evt)
{
process_result result = process_result::HANDLED_FALSE;
mp_for_each_until<Transitions>(
[&result, &sm, region_id, &evt](auto transition)
{
using Transition = decltype(transition);
result |= Transition::execute(sm, region_id, evt);
result |= Transition::process(sm, region_id, evt);
if (result & handled_true_or_deferred)
{
// If a guard rejected previously, ensure this bit is not present.
Expand Down
12 changes: 1 addition & 11 deletions include/boost/msm/backmp11/event_traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,6 @@ namespace boost::msm
template <>
struct is_kleene_event<std::any> : std::true_type {};

} // boost::msm

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

// Import std::any_cast for overload resolution:
// In case boost::any is used as Kleene event,
// overload resolution will pick boost::any_cast for us.
using std::any_cast;

} // boost::msm::backmp11
} // namespace boost::msm

#endif //BOOST_MSM_EVENT_TRAITS_HPP
Loading
Loading