Skip to content

Commit 4238d2e

Browse files
committed
Merge origin/main into codex/completion-event
2 parents c7527fb + cb75a87 commit 4238d2e

11 files changed

Lines changed: 5862 additions & 6 deletions

File tree

benchmark/simple/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ add_example(simple_sc benchmark_simple_sc sc.cpp)
1313

1414
if (NOT IS_MSVC_2015)
1515
add_example(simple_sml benchmark_simple_sml sml.cpp)
16+
add_example(simple_co_sm benchmark_simple_co_sm co_sm.cpp)
1617
endif()

benchmark/simple/co_sm.cpp

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
//
2+
// Copyright (c) 2016-2026 Kris Jusiak (kris at jusiak dot net)
3+
//
4+
// Distributed under the Boost Software License, Version 1.0.
5+
// (See accompanying file LICENSE_1_0.txt or copy at
6+
// http://www.boost.org/LICENSE_1_0.txt)
7+
//
8+
#include <boost/sml.hpp>
9+
#include <boost/sml/utility/co_sm.hpp>
10+
11+
#include "benchmark.hpp"
12+
13+
namespace sml = boost::sml;
14+
15+
struct play {};
16+
struct end_pause {};
17+
struct stop {};
18+
struct pause {};
19+
struct open_close {};
20+
struct cd_detected {};
21+
22+
auto start_playback = [] {};
23+
auto resume_playback = [] {};
24+
auto close_drawer = [] {};
25+
auto open_drawer = [] {};
26+
auto stop_and_open = [] {};
27+
auto stopped_again = [] {};
28+
auto store_cd_info = [] {};
29+
auto pause_playback = [] {};
30+
auto stop_playback = [] {};
31+
32+
struct player {
33+
auto operator()() const noexcept {
34+
using namespace sml;
35+
auto Empty = state<class Empty>;
36+
auto Open = state<class Open>;
37+
auto Stopped = state<class Stopped>;
38+
auto Playing = state<class Playing>;
39+
auto Pause = state<class Pause>;
40+
41+
// clang-format off
42+
return make_transition_table(
43+
Playing <= Stopped + event<play> / start_playback,
44+
Playing <= Pause + event<end_pause> / resume_playback,
45+
Empty <= Open + event<open_close> / close_drawer,
46+
Open <= *Empty + event<open_close> / open_drawer,
47+
Open <= Pause + event<open_close> / stop_and_open,
48+
Open <= Stopped + event<open_close> / open_drawer,
49+
Open <= Playing + event<open_close> / stop_and_open,
50+
Pause <= Playing + event<pause> / pause_playback,
51+
Stopped <= Playing + event<stop> / stop_playback,
52+
Stopped <= Pause + event<stop> / stop_playback,
53+
Stopped <= Empty + event<cd_detected> / store_cd_info,
54+
Stopped <= Stopped + event<stop> / stopped_again
55+
);
56+
// clang-format on
57+
}
58+
};
59+
60+
int main() {
61+
#if BOOST_SML_UTILITY_CO_SM_ENABLED
62+
using co_sm_t =
63+
sml::utility::co_sm<player, sml::utility::policy::coroutine_scheduler<sml::utility::policy::inline_scheduler>>;
64+
co_sm_t sm{};
65+
66+
benchmark_execution_speed([&] {
67+
for (auto i = 0; i < 1'000'000; ++i) {
68+
sm.process_event_async(open_close{}).result();
69+
sm.process_event_async(open_close{}).result();
70+
sm.process_event_async(cd_detected{}).result();
71+
sm.process_event_async(play{}).result();
72+
sm.process_event_async(pause{}).result();
73+
sm.process_event_async(end_pause{}).result();
74+
sm.process_event_async(pause{}).result();
75+
sm.process_event_async(stop{}).result();
76+
sm.process_event_async(stop{}).result();
77+
sm.process_event_async(open_close{}).result();
78+
sm.process_event_async(open_close{}).result();
79+
}
80+
});
81+
benchmark_memory_usage(sm);
82+
#else
83+
sml::sm<player> sm{};
84+
benchmark_execution_speed([&] {
85+
for (auto i = 0; i < 1'000'000; ++i) {
86+
sm.process_event(open_close{});
87+
sm.process_event(open_close{});
88+
sm.process_event(cd_detected{});
89+
sm.process_event(play{});
90+
sm.process_event(pause{});
91+
sm.process_event(end_pause{});
92+
sm.process_event(pause{});
93+
sm.process_event(stop{});
94+
sm.process_event(stop{});
95+
sm.process_event(open_close{});
96+
sm.process_event(open_close{});
97+
}
98+
});
99+
benchmark_memory_usage(sm);
100+
#endif
101+
}

include/boost/sml.hpp

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -763,6 +763,10 @@ template <class R, class T, int N>
763763
constexpr R get_id(type_id_type<N, T> *) {
764764
return static_cast<R>(N);
765765
}
766+
template <class T, int N>
767+
constexpr true_type has_type_id(type_id_type<N, T> *);
768+
template <class T>
769+
constexpr false_type has_type_id(...);
766770
template <template <class...> class, class T>
767771
struct is : false_type {};
768772
template <template <class...> class T, class... Ts>
@@ -1303,6 +1307,15 @@ struct transitions<aux::false_type> {
13031307
return false;
13041308
}
13051309
};
1310+
template <class TEvent, class...>
1311+
struct has_terminate_parent_transition : aux::false_type {};
1312+
template <class TEvent, class TTransition, class... TRest>
1313+
struct has_terminate_parent_transition<TEvent, TTransition, TRest...>
1314+
: aux::conditional<
1315+
aux::is_same<terminate_state, typename TTransition::dst_state>::value &&
1316+
aux::is_same<TEvent, typename TTransition::event>::value,
1317+
aux::true_type,
1318+
has_terminate_parent_transition<TEvent, TRest...>>::type {};
13061319
template <class Tsm, class T, class... Ts>
13071320
struct transitions_sub<sm<Tsm>, T, Ts...> {
13081321
template <class TEvent, class SM, class TDeps, class TSubs>
@@ -1318,7 +1331,14 @@ struct transitions_sub<sm<Tsm>, T, Ts...> {
13181331
}
13191332
template <class TEvent, class SM, class TDeps, class TSubs>
13201333
constexpr static bool execute_impl(const TEvent &event, SM &sm, TDeps &deps, TSubs &subs, typename SM::state_t &current_state) {
1321-
const auto handled = sub_sm<sm_impl<Tsm>>::get(&subs).process_event(event, deps, subs);
1334+
auto &sub = sub_sm<sm_impl<Tsm>>::get(&subs);
1335+
const auto handled = sub.process_event(event, deps, subs);
1336+
1337+
if (handled && sub.is_terminated() && has_terminate_parent_transition<TEvent, T, Ts...>::value) {
1338+
const auto propagated = transitions<T, Ts...>::execute(event, sm, deps, subs, current_state);
1339+
return propagated ? propagated : handled;
1340+
}
1341+
13221342
return handled ? handled : transitions<T, Ts...>::execute(event, sm, deps, subs, current_state);
13231343
}
13241344
template <class _, class TEvent, class SM, class TDeps, class TSubs>
@@ -2114,12 +2134,17 @@ struct sm_impl : aux::conditional_t<aux::should_not_subclass_statemachine_class<
21142134
constexpr static void visit_state(const TVisitor &visitor) {
21152135
visitor(aux::string<TState>{});
21162136
}
2117-
constexpr bool is_terminated() const { return is_terminated_impl(aux::make_index_sequence<regions>{}); }
2118-
constexpr bool is_terminated_impl(aux::index_sequence<0>) const {
2119-
return current_state_[0] == aux::get_id<state_t, terminate_state>((states_ids_t *)0);
2137+
constexpr bool is_terminated() const {
2138+
return is_terminated_impl(aux::make_index_sequence<regions>{},
2139+
decltype(aux::has_type_id<terminate_state>((states_ids_t *)0)){});
2140+
}
2141+
template <int... Ns>
2142+
constexpr bool is_terminated_impl(aux::index_sequence<Ns...>, aux::false_type) const {
2143+
(void)sizeof...(Ns);
2144+
return false;
21202145
}
21212146
template <int... Ns>
2122-
constexpr bool is_terminated_impl(aux::index_sequence<Ns...>) const {
2147+
constexpr bool is_terminated_impl(aux::index_sequence<Ns...>, aux::true_type) const {
21232148
#if defined(__cpp_fold_expressions)
21242149
return ((current_state_[Ns] == aux::get_id<state_t, terminate_state>((states_ids_t *)0)) && ...);
21252150
#else

0 commit comments

Comments
 (0)