Skip to content

Commit 102b028

Browse files
committed
Propagate origin event through completion transitions
1 parent 2437286 commit 102b028

3 files changed

Lines changed: 68 additions & 18 deletions

File tree

include/boost/sml.hpp

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1065,6 +1065,8 @@ struct anonymous : internal_event {
10651065
template <class TEvent>
10661066
struct completion : internal_event {
10671067
constexpr static auto c_str() { return "completion"; }
1068+
constexpr explicit completion(const TEvent &event) : event_(event) {}
1069+
const TEvent &event_;
10681070
};
10691071
template <class T, class TEvent = T>
10701072
struct on_entry : internal_event, entry_exit {
@@ -1125,6 +1127,26 @@ template <class TEvent>
11251127
using get_generic_t = typename event_type<TEvent>::generic_t;
11261128
template <class TEvent>
11271129
using get_mapped_t = typename event_type<TEvent>::mapped_t;
1130+
template <class TEvent>
1131+
constexpr const TEvent &get_origin_event(const TEvent &event) {
1132+
return event;
1133+
}
1134+
template <class T, class TEvent>
1135+
constexpr const TEvent &get_origin_event(const unexpected_event<T, TEvent> &event) {
1136+
return event.event_;
1137+
}
1138+
template <class T, class TEvent>
1139+
constexpr const TEvent &get_origin_event(const on_entry<T, TEvent> &event) {
1140+
return event.event_;
1141+
}
1142+
template <class T, class TEvent>
1143+
constexpr const TEvent &get_origin_event(const on_exit<T, TEvent> &event) {
1144+
return event.event_;
1145+
}
1146+
template <class T, class TException>
1147+
constexpr const TException &get_origin_event(const exception<T, TException> &event) {
1148+
return event.exception_;
1149+
}
11281150
template <class... TEvents>
11291151
struct process : queue_handler<TEvents...> {
11301152
using queue_handler<TEvents...>::queue_handler;
@@ -1860,28 +1882,28 @@ struct sm_impl : aux::conditional_t<aux::should_not_subclass_statemachine_class<
18601882
return handled && queued_handled;
18611883
}
18621884
template <class TOriginEvent, class TDeps, class TSubs>
1863-
constexpr bool process_completion_event(TDeps &deps, TSubs &subs, aux::true_type) {
1864-
return process_internal_events(completion<TOriginEvent>{}, deps, subs);
1885+
constexpr bool process_completion_event(const TOriginEvent &event, TDeps &deps, TSubs &subs, aux::true_type) {
1886+
return process_internal_events(completion<TOriginEvent>{event}, deps, subs);
18651887
}
18661888
template <class TOriginEvent, class TDeps, class TSubs>
1867-
constexpr bool process_completion_event(TDeps &, TSubs &, aux::false_type) {
1889+
constexpr bool process_completion_event(const TOriginEvent &, TDeps &, TSubs &, aux::false_type) {
18681890
return false;
18691891
}
18701892
template <class TOriginEvent, class TDeps, class TSubs>
1871-
constexpr bool process_post_event_step(TDeps &deps, TSubs &subs) {
1893+
constexpr bool process_post_event_step(const TOriginEvent &event, TDeps &deps, TSubs &subs) {
18721894
return process_completion_event<TOriginEvent>(
1873-
deps, subs, typename aux::is_base_of<completion<TOriginEvent>, events_ids_t>::type{}) ||
1895+
event, deps, subs, typename aux::is_base_of<completion<TOriginEvent>, events_ids_t>::type{}) ||
18741896
process_internal_events(anonymous{}, deps, subs);
18751897
}
18761898
template <class TOriginEvent, class TDeps, class TSubs>
1877-
constexpr void process_post_events(TDeps &deps, TSubs &subs) {
1878-
while (process_post_event_step<TOriginEvent>(deps, subs)) {
1899+
constexpr void process_post_events(const TOriginEvent &event, TDeps &deps, TSubs &subs) {
1900+
while (process_post_event_step<TOriginEvent>(event, deps, subs)) {
18791901
}
18801902
}
18811903
template <class TOriginEvent, class TEvent, class TDeps, class TSubs>
18821904
constexpr bool process_event_and_post_events(const TEvent &event, TDeps &deps, TSubs &subs) {
18831905
const bool handled = process_internal_events(event, deps, subs);
1884-
process_post_events<TOriginEvent>(deps, subs);
1906+
process_post_events<TOriginEvent>(get_origin_event(event), deps, subs);
18851907
return handled;
18861908
}
18871909
constexpr void initialize(const aux::type_list<> &) {}
@@ -2351,6 +2373,14 @@ template <class T, class TEvent, class Tsm, class TDeps>
23512373
constexpr decltype(auto) get_arg(const aux::type_wrapper<const TEvent &> &, const back::on_exit<T, TEvent> &event, Tsm &, TDeps &) {
23522374
return event.event_;
23532375
}
2376+
template <class TEvent, class Tsm, class TDeps>
2377+
constexpr decltype(auto) get_arg(const aux::type_wrapper<const TEvent &> &, const back::completion<TEvent> &event, Tsm &, TDeps &) {
2378+
return event.event_;
2379+
}
2380+
template <class TEvent, class Tsm, class TDeps>
2381+
constexpr decltype(auto) get_arg(const aux::type_wrapper<TEvent> &, const back::completion<TEvent> &event, Tsm &, TDeps &) {
2382+
return event.event_;
2383+
}
23542384
template <class T, class TEvent, class Tsm, class TDeps>
23552385
constexpr decltype(auto) get_arg(const aux::type_wrapper<const TEvent &> &, const back::exception<T, TEvent> &event, Tsm &, TDeps &) {
23562386
return event.exception_;
@@ -2756,6 +2786,18 @@ struct ignore<E, aux::type_list<Ts...>> {
27562786
};
27572787
using type = aux::join_t<typename non_events<Ts>::type...>;
27582788
};
2789+
template <class TEvent, class... Ts>
2790+
struct ignore<back::completion<TEvent>, aux::type_list<Ts...>> {
2791+
template <class T>
2792+
struct non_events {
2793+
using arg_t = aux::remove_const_t<aux::remove_reference_t<T>>;
2794+
using type = aux::conditional_t<aux::is_same<TEvent, arg_t>::value ||
2795+
aux::is_same<back::completion<TEvent>, arg_t>::value ||
2796+
aux::is_same<T, action_base>::value,
2797+
aux::type_list<>, aux::type_list<T>>;
2798+
};
2799+
using type = aux::join_t<typename non_events<Ts>::type...>;
2800+
};
27592801
template <class T, class E, class = void>
27602802
struct get_deps {
27612803
using type = typename ignore<E, args_t<T, E>>::type;

test/ft/actions_process_n_defer.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,9 @@ test process_n_defer_again = [] {
120120

121121
test process_queue_runs_completion_for_popped_event_type = [] {
122122
struct trigger {};
123-
struct queued1 {};
123+
struct queued1 {
124+
int value{};
125+
};
124126
struct queued2 {};
125127
struct q0 {};
126128
struct q1 {};
@@ -140,9 +142,9 @@ test process_queue_runs_completion_for_popped_event_type = [] {
140142
auto wrong_state = state<wrong>;
141143
// clang-format off
142144
return make_transition_table(
143-
*q0_state + event<trigger> / (process(queued1{}), process(queued2{})) = q1_state
145+
*q0_state + event<trigger> / (process(queued1{42}), process(queued2{})) = q1_state
144146
, q1_state + event<queued1> = q2_state
145-
, q2_state + completion<queued1> = q3_state
147+
, q2_state + completion<queued1>[([](const queued1& event) { return event.value == 42; })] = q3_state
146148
, q2_state + event<queued2> = wrong_state
147149
, q3_state + event<queued2> = done_state
148150
);
@@ -157,7 +159,9 @@ test process_queue_runs_completion_for_popped_event_type = [] {
157159
};
158160

159161
test defer_queue_runs_completion_for_popped_event_type = [] {
160-
struct deferred {};
162+
struct deferred {
163+
int value{};
164+
};
161165
struct release {};
162166
struct d0 {};
163167
struct d1 {};
@@ -178,15 +182,15 @@ test defer_queue_runs_completion_for_popped_event_type = [] {
178182
*d0_state + event<deferred> / defer
179183
, d0_state + event<release> = d1_state
180184
, d1_state + event<deferred> = d2_state
181-
, d2_state + completion<deferred> = done_state
185+
, d2_state + completion<deferred>[([](const deferred& event) { return event.value == 11; })] = done_state
182186
, d2_state + completion<release> = wrong_state
183187
);
184188
// clang-format on
185189
}
186190
};
187191

188192
sml::sm<c, sml::process_queue<std::queue>, sml::defer_queue<std::deque>> sm{};
189-
expect(sm.process_event(deferred{}));
193+
expect(sm.process_event(deferred{11}));
190194
expect(sm.process_event(release{}));
191195
expect(sm.is(sml::state<done>));
192196
expect(!sm.is(sml::state<wrong>));

test/ft/transitions.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,17 @@ test anonymous_transition = [] {
8989
};
9090

9191
test completion_transition_runs_before_anonymous = [] {
92+
struct payload {
93+
int value{};
94+
};
95+
9296
struct c {
9397
auto operator()() noexcept {
9498
using namespace sml;
9599
// clang-format off
96100
return make_transition_table(
97-
*idle + event<e1> = s1
98-
,s1 + completion<e1> / [this] { calls += "completion|"; } = s2
101+
*idle + event<payload> = s1
102+
,s1 + completion<payload> / [this](const payload& event) { calls += "completion(" + std::to_string(event.value) + ")|"; } = s2
99103
,s1 / [this] { calls += "anonymous_s1|"; } = s3
100104
,s2 / [this] { calls += "anonymous_s2|"; } = s4
101105
);
@@ -106,10 +110,10 @@ test completion_transition_runs_before_anonymous = [] {
106110
};
107111

108112
sml::sm<c> sm{};
109-
expect(sm.process_event(e1{}));
113+
expect(sm.process_event(payload{42}));
110114
expect(sm.is(s4));
111115
expect(!sm.is(s3));
112-
expect(static_cast<const c&>(sm).calls == "completion|anonymous_s2|");
116+
expect(static_cast<const c&>(sm).calls == "completion(42)|anonymous_s2|");
113117
};
114118

115119
test subsequent_anonymous_transitions = [] {

0 commit comments

Comments
 (0)