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
36 changes: 35 additions & 1 deletion include/boost/sml.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2925,7 +2925,21 @@ constexpr void update_composite_states(TSubs &subs, aux::false_type, Ts &&...) {
using sm_impl_t = aux::apply_t<back::sm_impl, state_t>;
update_composite_states<sm_impl_t>(subs, aux::false_type{}, Ts{}...);
}
});
});
}
constexpr void clear_defer_queue(back::no_policy &) {}
template <class TQueue>
constexpr void clear_defer_queue(TQueue &queue) {
queue.erase(queue.begin(), queue.end());
}
template <class T, class TSubs>
constexpr void clear_sub_sm_defer_state(TSubs &subs) {
auto &sub_sm = back::sub_sm<back::sm_impl<T>>::get(&subs);
clear_defer_queue(sub_sm.defer_);
sub_sm.defer_processing_ = decltype(sub_sm.defer_processing_){};
sub_sm.defer_again_ = decltype(sub_sm.defer_again_){};
sub_sm.defer_it_ = {};
sub_sm.defer_end_ = {};
}
template <class SM, class TDeps, class TSubs, class TSrcState, class TDstState>
constexpr void update_current_state(SM &, TDeps &deps, TSubs &, typename SM::state_t &current_state,
Expand All @@ -2935,6 +2949,15 @@ constexpr void update_current_state(SM &, TDeps &deps, TSubs &, typename SM::sta
aux::string<typename TDstState::type>{});
current_state = new_state;
}
template <class SM, class TDeps, class TSubs, class T, class TDstState,
__BOOST_SML_REQUIRES(!detail::is_composite_state_v<typename TDstState::type>)>
constexpr void update_current_state(SM &, TDeps &deps, TSubs &subs, typename SM::state_t &current_state,
const typename SM::state_t &new_state, const state<back::sm<T>> &, const TDstState &) {
back::policies::log_state_change<typename SM::sm_t>(aux::type_wrapper<typename SM::logger_t>{}, deps, aux::string<T>{},
Comment thread
gabewillen marked this conversation as resolved.
aux::string<typename TDstState::type>{});
current_state = new_state;
clear_sub_sm_defer_state<T>(subs);
}
template <class SM, class TDeps, class TSubs, class TSrcState, class T>
constexpr void update_current_state(SM &, TDeps &deps, TSubs &subs, typename SM::state_t &current_state,
const typename SM::state_t &new_state, const TSrcState &, const state<back::sm<T>> &) {
Expand All @@ -2944,6 +2967,17 @@ constexpr void update_current_state(SM &, TDeps &deps, TSubs &subs, typename SM:
update_composite_states<back::sm_impl<T>>(subs, typename back::sm_impl<T>::has_history_states{},
typename back::sm_impl<T>::history_states_t{});
}
template <class SM, class TDeps, class TSubs, class TSrc, class TDst>
constexpr void update_current_state(SM &, TDeps &deps, TSubs &subs, typename SM::state_t &current_state,
const typename SM::state_t &new_state, const state<back::sm<TSrc>> &,
const state<back::sm<TDst>> &) {
back::policies::log_state_change<typename SM::sm_t>(aux::type_wrapper<typename SM::logger_t>{}, deps, aux::string<TSrc>{},
aux::string<TDst>{});
current_state = new_state;
clear_sub_sm_defer_state<TSrc>(subs);
update_composite_states<back::sm_impl<TDst>>(subs, typename back::sm_impl<TDst>::has_history_states{},
typename back::sm_impl<TDst>::history_states_t{});
}
template <class S1, class S2, class E, class G, class A>
struct transition<state<S1>, state<S2>, front::event<E>, G, A> {
static constexpr auto initial = state<S2>::initial;
Expand Down
3 changes: 3 additions & 0 deletions test/ft/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ add_test(test_fwd test_fwd)
add_executable(test_history history.cpp)
add_test(test_history test_history)

add_executable(test_issue_253 issue_253.cpp)
add_test(test_issue_253 test_issue_253)

add_executable(test_guards guards.cpp)
add_test(test_guards test_guards)

Expand Down
80 changes: 80 additions & 0 deletions test/ft/issue_253.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
//
// Copyright (c) 2016-2020 Kris Jusiak (kris at jusiak dot net)
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
#include <boost/sml.hpp>
#include <deque>
#include <queue>

Comment thread
gabewillen marked this conversation as resolved.
namespace sml = boost::sml;

test issue_253_nested_defer_queue_is_cleared_on_exit = [] {
struct issue_253_enter {};
struct issue_253_exit {};
struct issue_253_to_s2 {};
struct issue_253_to_s1 {};
struct issue_253_e1 {};
struct issue_253_outer_idle {};

struct issue_253_counters {
int nested_calls = 0;
int outer_calls = 0;
};

struct issue_253_nested {
auto operator()() const {
using namespace sml;
const auto issue_253_s1 = sml::state<class issue_253_s1>;
const auto issue_253_s2 = sml::state<class issue_253_s2>;
// clang-format off
return make_transition_table(
*issue_253_s1 + event<issue_253_to_s2> = issue_253_s2
, issue_253_s2 + event<issue_253_e1> / defer
, issue_253_s2 + event<issue_253_to_s1> = issue_253_s1
, issue_253_s1 + event<issue_253_e1> / [](issue_253_counters& counters) { ++counters.nested_calls; }
);
// clang-format on
}
};

struct issue_253_outer {
auto operator()() const {
using namespace sml;
const auto issue_253_idle = sml::state<issue_253_outer_idle>;
const auto issue_253_nested_state = sml::state<issue_253_nested>;
// clang-format off
return make_transition_table(
*issue_253_idle + event<issue_253_enter> = issue_253_nested_state
, issue_253_nested_state + event<issue_253_exit> = issue_253_idle
, issue_253_idle + event<issue_253_e1> / [](issue_253_counters& counters) { ++counters.outer_calls; }
);
// clang-format on
}
};

issue_253_counters counters{};
sml::sm<issue_253_outer, sml::defer_queue<std::deque>, sml::process_queue<std::queue>> sm{counters};

expect(sm.process_event(issue_253_enter{}));
expect(sm.process_event(issue_253_to_s2{}));
expect(sm.process_event(issue_253_e1{}));
expect(sm.process_event(issue_253_to_s1{}));
expect(sm.process_event(issue_253_exit{}));
expect(1 == counters.nested_calls);
expect(0 == counters.outer_calls);

expect(sm.process_event(issue_253_e1{}));
expect(1 == counters.outer_calls);

expect(sm.process_event(issue_253_enter{}));
expect(sm.process_event(issue_253_to_s2{}));
expect(sm.process_event(issue_253_to_s1{}));
expect(sm.process_event(issue_253_exit{}));
expect(1 == counters.nested_calls);

expect(sm.process_event(issue_253_e1{}));
expect(2 == counters.outer_calls);
};
Loading