16 #include "../../lib/type_pack/include/type_pack.hpp"
18 #include <type_traits>
29 template <
class Source,
class Event,
class Target,
class Action,
33 using source_t = Source;
34 using event_t = Event;
35 using target_t = Target;
36 using action_t = Action;
37 using guard_t = Guard;
44 template <
class Source,
class Event,
class Target,
class Action,
class Guard>
45 using tr =
transition<Source, Event, Target, Action, Guard>;
49 template <
class Gd,
class Target>
52 template <
class Guard,
class Target>
53 inline constexpr bool match_v = match<Guard, Target>::value;
55 template <
class Guard>
56 struct is_logical_guard;
61 template <
typename T,
typename... Ts>
62 struct unpack<tp::type_pack<T, Ts...>> {
63 using type = std::variant<T, Ts...>;
66 template <
class GuardPack>
69 template <
class Source,
class Event,
class GuardPack>
72 template <
class TrPack>
74 using type = tp::empty_pack;
77 template <
class Tr,
class... Trs>
78 struct unpack_trs<tp::type_pack<Tr, Trs...>> {
79 using source_t =
typename Tr::source_t;
80 using event_t =
typename Tr::event_t;
81 using guard_t =
typename Tr::guard_t;
82 using tr_t = tr_cond<source_t, event_t, guard_t>;
85 tp::concatenate_t<tp::just_type<tr_t>,
86 typename unpack_trs<tp::type_pack<Trs...>>::type>;
90 template <
typename... Ts>
93 using transitions = tp::type_pack<Ts...>;
95 using sources = tp::type_pack<
typename Ts::source_t...>;
96 using events = tp::type_pack<
typename Ts::event_t...>;
97 using targets = tp::type_pack<
typename Ts::target_t...>;
98 using guards_raw = tp::concatenate_t<tp::type_pack<
typename Ts::guard_t...>,
100 using guards =
typename __details::unpack_guards<guards_raw>::type;
102 using states = tp::concatenate_t<sources, targets>;
104 using state_collection = tp::unique_t<states>;
105 using event_collection = tp::unique_t<events>;
106 using guard_collection = tp::unique_t<guards>;
108 using state_v =
typename __details::unpack<state_collection>::type;
109 using event_v =
typename __details::unpack<event_collection>::type;
110 using guard_v =
typename __details::unpack<guard_collection>::type;
114 using tr_conds =
typename __details::unpack_trs<transitions>::type;
115 using test_t = tp::unique_t<tr_conds>;
117 static_assert(tp::is_equal<tr_conds, test_t>::value,
118 "Duplicated transitions");
121 namespace __details {
123 template <
class T,
class Pack>
124 constexpr bool static_check_contains() {
125 constexpr bool contains = tp::contains<T, Pack>::value;
126 static_assert(contains);
130 template <
class FSMLogger,
class F,
typename... Args>
131 inline void invoke(FSMLogger& logger, F&& f, Args&&... args)
noexcept(
132 std::is_nothrow_invocable_v<F, Args...>) {
133 if constexpr (std::is_invocable<F, Args...>::value) {
134 logger.write(
"Calling an action...");
135 f(std::forward<Args>(args)...);
146 template <
typename T>
147 inline void write(
const char*)
noexcept {}
152 inline void write(
const char*)
noexcept {}
158 using state_v =
typename Table::state_v;
159 using event_v =
typename Table::event_v;
160 using guard_v =
typename Table::guard_v;
161 using transition_pack =
typename Table::transitions;
162 using guard_collection =
typename Table::guard_collection;
164 static constexpr std::size_t m_tr_count = transition_pack::size();
169 using logger_t = Logger;
172 template <
class State,
class Event,
class Guard,
class Pack,
175 template <
typename... Args>
176 inline void operator()(state_v&, Args&&...)
noexcept {}
179 template <
class State,
class Event,
class Guard, std::size_t Idx,
180 typename T,
typename... Ts>
181 struct event_impl<State, Event, Guard, tp::type_pack<T, Ts...>, Idx> {
182 template <
typename... Args>
183 inline void operator()(state_v& state, logger_t& log, Args&&... args) {
184 using state_t =
typename T::source_t;
185 using event_t =
typename T::event_t;
186 using guard_t =
typename T::guard_t;
187 using target_t =
typename T::target_t;
188 using action_t =
typename T::action_t;
190 if constexpr (std::is_same_v<State, state_t> &&
191 std::is_same_v<Event, event_t> &&
192 __details::match_v<Guard, guard_t>) {
193 log.
template write<target_t>(
"Change state to ");
195 __details::invoke(log, action_t {}, std::forward<Args>(args)...);
197 event_impl<State, Event, Guard, tp::type_pack<Ts...>, Idx + 1> {}(
198 state, log, std::forward<Args>(args)...);
203 inline state_machine()
204 : m_state(tp::at_t<0,
typename Table::sources> {}), m_guard(
none {}) {}
214 : m_state(tp::at_t<0,
typename Table::sources> {}), m_guard(
none {}),
215 logger(std::move(custom_logger)) {}
230 template <
typename Event,
typename... Args>
232 logger.
template write<Event>(
"New event: ");
233 state_v& ref_state = m_state;
234 guard_v& ref_guard = m_guard;
235 auto l = [&](
const auto& arg) {
236 auto gl = [&](
const auto& arg2) {
237 using event_t = Event;
238 using state_t = std::decay_t<
decltype(arg)>;
239 using guard_t = std::decay_t<
decltype(arg2)>;
240 event_impl<state_t, event_t, guard_t, transition_pack, 0> {}(
241 ref_state, logger, std::forward<Args>(args)...);
243 std::visit(gl, ref_guard);
245 std::visit(l, m_state);
256 template <
typename... Args>
258 logger_t& ref_log = logger;
259 auto l = [&](
const auto& arg) {
260 using state_t = std::decay_t<
decltype(arg)>;
261 ref_log.
template write<state_t>(
"Attempt to call an action for: ");
262 __details::invoke(ref_log, state_t {}, std::forward<Args>(args)...);
264 std::visit(l, m_state);
272 template <
class Guard>
274 if constexpr (__details::static_check_contains<Guard,
275 guard_collection>()) {
276 logger.
template write<Guard>(
"New guard: ");
284 namespace __details {
286 enum class guard_class { noneof, anyof };
288 struct logic_guard_base {};
292 template <
class Guard,
class... Guards>
295 static constexpr __details::guard_class type =
296 __details::guard_class::anyof;
297 using guard_pack = tp::type_pack<Guard, Guards...>;
298 using pack = guard_pack;
302 template <
class Guard,
class... Guards>
305 static constexpr __details::guard_class type =
306 __details::guard_class::noneof;
307 using guard_pack = tp::type_pack<Guard, Guards...>;
308 using pack = guard_pack;
313 template <
class Guard>
317 template <
class... Guards>
321 template <
class... Guards>
324 namespace __details {
326 template <
class Guard,
class Target,
typename AlwaysVoid>
328 static const bool value =
false;
331 template <
class Guard>
332 struct is_none_guard {
333 static constexpr bool value =
false;
337 struct is_none_guard<
none> {
338 static constexpr bool value =
true;
341 template <
class Guard,
class Target>
342 struct match_impl<Guard, Target,
343 std::enable_if_t<std::is_same_v<Guard, Target> &&
344 !is_none_guard<Target>::value>> {
345 static constexpr bool value =
true;
348 template <
class Guard,
class Target>
352 Target::type == guard_class::anyof &&
353 tp::contains<Guard,
typename Target::guard_pack>::value>> {
354 static constexpr bool value =
true;
357 template <
class Guard,
class Target>
361 Target::type == guard_class::noneof &&
362 !tp::contains<Guard,
typename Target::guard_pack>::value>> {
363 static constexpr bool value =
true;
366 template <
class Guard,
class Target>
367 struct match_impl<Guard, Target,
368 std::enable_if_t<is_none_guard<Target>::value>> {
369 static constexpr bool value =
true;
381 template <
class Gd,
class Target>
382 struct match : __details::match_impl<Gd, Target,
void> {};
384 template <
class Guard>
385 struct is_logical_guard {
386 static constexpr bool value = std::is_base_of_v<logic_guard_base, Guard>;
389 template <
class Guard,
typename AlwaysVoid>
390 struct unpack_guard_impl {
391 using type = tp::just_type<Guard>;
394 template <
class Guard>
395 struct unpack_guard_impl<Guard,
396 std::enable_if_t<is_logical_guard<Guard>::value>> {
397 using type =
typename Guard::pack;
400 template <
class Guard>
401 struct unpack_guard : unpack_guard_impl<Guard,
void> {};
403 template <
class GuardPack>
404 struct unpack_guards {};
406 template <
typename T,
typename... Ts>
407 struct unpack_guards<tp::type_pack<T, Ts...>> {
408 using pack =
typename unpack_guard<T>::type;
409 using next =
typename unpack_guards<tp::type_pack<Ts...>>::type;
410 using type = tp::concatenate_t<pack, next>;
414 struct unpack_guards<tp::empty_pack> {
415 using type = tp::empty_pack;