Skip to content

Commit fd81ea9

Browse files
committed
Implement support for multiple entry and exit functions
1 parent 07c9d36 commit fd81ea9

2 files changed

Lines changed: 90 additions & 30 deletions

File tree

include/cpp_event_framework/Statemachine.hxx

Lines changed: 51 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -264,27 +264,41 @@ public:
264264
StatePtr const initial_ = nullptr;
265265

266266
/**
267-
* @brief Optional entry action
268-
*
267+
* @brief Optional list of entry actions
269268
*/
270-
EntryExitType const on_entry_ = nullptr;
269+
std::span<const EntryExitType> const on_entry_;
271270
/**
272-
* @brief Optional exit action
273-
*
271+
* @brief Optional single entry action
272+
*/
273+
EntryExitType const on_single_entry_ = nullptr;
274+
/**
275+
* @brief Optional list of exit actions
274276
*/
275-
EntryExitType const on_exit_ = nullptr;
277+
std::span<const EntryExitType> const on_exit_;
278+
/**
279+
* @brief Optional single exit action
280+
*/
281+
EntryExitType const on_single_exit_ = nullptr;
276282
/**
277283
* @brief Statemachine handler, must be assigned
278284
*/
279285
HandlerType const handler_ = nullptr;
280286

281287
/**
282288
* @brief Construct a new Statemachine State object
283-
*
284289
*/
285290
constexpr State(const char* name, HandlerType handler, StatePtr parent = nullptr, StatePtr initial = nullptr,
286291
EntryExitType on_entry = nullptr, EntryExitType on_exit = nullptr) noexcept
287-
: State(name, handler, parent, initial, on_entry, on_exit, EFlags::kNone)
292+
: State(name, handler, parent, initial, on_entry, {}, on_exit, {}, EFlags::kNone)
293+
{
294+
}
295+
296+
/**
297+
* @brief Construct a new Statemachine State object
298+
*/
299+
constexpr State(const char* name, HandlerType handler, StatePtr parent, StatePtr initial,
300+
std::span<const EntryExitType> on_entry, std::span<const EntryExitType> on_exit) noexcept
301+
: State(name, handler, parent, initial, nullptr, on_entry, nullptr, on_exit, EFlags::kNone)
288302
{
289303
}
290304

@@ -301,33 +315,31 @@ public:
301315
/**
302316
* @brief Stream operator for logging
303317
*/
304-
friend inline std::ostream& operator<<(std::ostream& os, StateRef state)
318+
friend std::ostream& operator<<(std::ostream& os, StateRef state)
305319
{
306320
return os << state.Name();
307321
}
308322

309323
protected:
310324
/**
311325
* @brief Construct a new Statemachine State object
312-
*
313326
*/
314327
constexpr State(const char* name, HandlerType handler, StatePtr parent, StatePtr initial,
315-
EntryExitType on_entry, EntryExitType on_exit, EFlags flags) noexcept
328+
EntryExitType on_single_entry, std::span<const EntryExitType> on_entry,
329+
EntryExitType on_single_exit, std::span<const EntryExitType> on_exit, EFlags flags) noexcept
316330
: flags_(flags)
317331
, parent_(parent)
318332
, initial_(initial)
319333
, on_entry_(on_entry)
334+
, on_single_entry_(on_single_entry)
320335
, on_exit_(on_exit)
336+
, on_single_exit_(on_single_exit)
321337
, handler_(handler)
322338
, name_(name)
323339
{
324340
}
325341

326342
private:
327-
/**
328-
* @brief Statename, optional, useful for logging
329-
*
330-
*/
331343
const char* name_ = nullptr;
332344
};
333345

@@ -339,13 +351,22 @@ public:
339351
{
340352
public:
341353
/**
342-
* @brief Construct a new Statemachine State object
343-
*
354+
* @brief Construct a new History State
344355
*/
345356
constexpr HistoryState(const char* name, typename State::HandlerType handler, StatePtr parent = nullptr,
346357
StatePtr initial = nullptr, typename State::EntryExitType on_entry = nullptr,
347358
typename State::EntryExitType on_exit = nullptr) noexcept
348-
: State(name, handler, parent, initial, on_entry, on_exit, EFlags::kHistory)
359+
: State(name, handler, parent, initial, on_entry, {}, on_exit, {}, EFlags::kHistory)
360+
{
361+
}
362+
363+
/**
364+
* @brief Construct a new History State
365+
*/
366+
constexpr HistoryState(const char* name, typename State::HandlerType handler, StatePtr parent, StatePtr initial,
367+
std::span<typename State::EntryExitType> on_entry,
368+
std::span<typename State::EntryExitType> on_exit) noexcept
369+
: State(name, handler, parent, initial, nullptr, on_entry, nullptr, on_exit, EFlags::kNone)
349370
{
350371
}
351372
};
@@ -721,9 +742,13 @@ private:
721742
on_state_exit_(*this, *state);
722743
}
723744

724-
if (state->on_exit_ != nullptr)
745+
if (state->on_single_exit_ != nullptr)
725746
{
726-
(impl_->*state->on_exit_)();
747+
(impl_->*state->on_single_exit_)();
748+
}
749+
for (const auto& on_ex : state->on_exit_)
750+
{
751+
(impl_->*on_ex)();
727752
}
728753
}
729754

@@ -762,9 +787,13 @@ private:
762787
on_state_entry_(*this, state);
763788
}
764789

765-
if (state.on_entry_ != nullptr)
790+
if (state.on_single_entry_ != nullptr)
791+
{
792+
(impl_->*state.on_single_entry_)();
793+
}
794+
for (const auto& on_en : state.on_entry_)
766795
{
767-
(impl_->*state.on_entry_)();
796+
(impl_->*on_en)();
768797
}
769798
}
770799

test/Statemachine_unittest.cxx

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ class Fsm : public cpp_event_framework::Statemachine<StatemachineImpl, const cpp
4141
static const State kRedYellow;
4242

4343
private:
44+
static const std::array<State::EntryExitType, 2> FsmOffEntryActions;
45+
static const std::array<State::EntryExitType, 2> FsmOffExitActions;
46+
4447
static Transition FsmOffHandler(ImplPtr /*impl*/, Event event);
4548

4649
static Transition FsmOnHandler(ImplPtr /*impl*/, Event event);
@@ -93,7 +96,9 @@ class StatemachineImpl
9396
}
9497

9598
bool off_entry_called_ = false;
99+
bool off_entry2_called_ = false;
96100
bool off_exit_called_ = false;
101+
bool off_exit2_called_ = false;
97102
bool on_entry_called_ = false;
98103
bool on_exit_called_ = false;
99104
bool yellow_red_transition1_called_ = false;
@@ -112,7 +117,9 @@ class StatemachineImpl
112117
void CheckAllFalse() const
113118
{
114119
assert(off_entry_called_ == false);
120+
assert(off_entry2_called_ == false);
115121
assert(off_exit_called_ == false);
122+
assert(off_exit2_called_ == false);
116123
assert(on_entry_called_ == false);
117124
assert(on_exit_called_ == false);
118125
assert(yellow_red_transition1_called_ == false);
@@ -127,13 +134,23 @@ class StatemachineImpl
127134
off_entry_called_ = true;
128135
std::cout << "Off entry\n";
129136
}
137+
void FsmOffEntry2()
138+
{
139+
off_entry2_called_ = true;
140+
std::cout << "Off entry2\n";
141+
}
130142

131143
void FsmOffExit()
132144
{
133145
off_exit_called_ = true;
134146
fsm_.RecallEvents();
135147
std::cout << "Off exit\n";
136148
}
149+
void FsmOffExit2()
150+
{
151+
off_exit2_called_ = true;
152+
std::cout << "Off exit2\n";
153+
}
137154

138155
void FsmOnEntry()
139156
{
@@ -179,26 +196,34 @@ class StatemachineImpl
179196
assert(fsm_.CurrentState() == &Fsm::kOff);
180197
assert(off_entry_called_ == true);
181198
off_entry_called_ = false;
199+
assert(off_entry2_called_ == true);
200+
off_entry2_called_ = false;
182201
CheckAllFalse();
183202

184203
fsm_.React(EvtSelfTransition::MakeShared());
185204
assert(fsm_.CurrentState() == &Fsm::kOff);
186205
assert(off_entry_called_ == true);
187206
off_entry_called_ = false;
207+
assert(off_entry2_called_ == true);
208+
off_entry2_called_ = false;
188209
assert(off_exit_called_ == true);
189210
off_exit_called_ = false;
211+
assert(off_exit2_called_ == true);
212+
off_exit2_called_ = false;
190213
assert(on_recall_event_called_ == true);
191214
on_recall_event_called_ = false;
192215
CheckAllFalse();
193216

194217
fsm_.React(EvtTurnOn::MakeShared());
195218
assert(off_exit_called_ == true);
196-
assert(on_entry_called_ == true);
197-
assert(on_recall_event_called_ == true);
198-
assert(fsm_.CurrentState() == &Fsm::kGreen);
199219
off_exit_called_ = false;
220+
assert(off_exit2_called_ == true);
221+
off_exit2_called_ = false;
222+
assert(on_entry_called_ == true);
200223
on_entry_called_ = false;
224+
assert(on_recall_event_called_ == true);
201225
on_recall_event_called_ = false;
226+
assert(fsm_.CurrentState() == &Fsm::kGreen);
202227
CheckAllFalse();
203228

204229
fsm_.React(EvtTurnOn::MakeShared());
@@ -211,10 +236,10 @@ class StatemachineImpl
211236

212237
fsm_.React(EvtGoRed::MakeShared());
213238
assert(yellow_red_transition1_called_ == true);
214-
assert(yellow_red_transition2_called_ == true);
215-
assert(fsm_.CurrentState() == &Fsm::kRed);
216239
yellow_red_transition1_called_ = false;
240+
assert(yellow_red_transition2_called_ == true);
217241
yellow_red_transition2_called_ = false;
242+
assert(fsm_.CurrentState() == &Fsm::kRed);
218243
CheckAllFalse();
219244

220245
fsm_.React(EvtGoYellow::MakeShared());
@@ -235,10 +260,12 @@ class StatemachineImpl
235260

236261
fsm_.React(EvtTurnOff::MakeShared());
237262
assert(on_exit_called_ == true);
238-
assert(off_entry_called_ == true);
239-
assert(fsm_.CurrentState() == &Fsm::kOff);
240263
on_exit_called_ = false;
264+
assert(off_entry_called_ == true);
241265
off_entry_called_ = false;
266+
assert(off_entry2_called_ == true);
267+
off_entry2_called_ = false;
268+
assert(fsm_.CurrentState() == &Fsm::kOff);
242269
CheckAllFalse();
243270

244271
fsm_.React(EvtGoGreen::MakeShared());
@@ -271,7 +298,11 @@ class StatemachineImpl
271298
}
272299
};
273300

274-
const Fsm::State Fsm::kOff("Off", &FsmOffHandler, nullptr, nullptr, &Fsm::Impl::FsmOffEntry, &Fsm::Impl::FsmOffExit);
301+
const std::array<Fsm::State::EntryExitType, 2> Fsm::FsmOffEntryActions =
302+
std::to_array<Fsm::State::EntryExitType>({&Fsm::Impl::FsmOffEntry, &Fsm::Impl::FsmOffEntry2});
303+
const std::array<Fsm::State::EntryExitType, 2> Fsm::FsmOffExitActions =
304+
std::to_array<Fsm::State::EntryExitType>({&Fsm::Impl::FsmOffExit, &Fsm::Impl::FsmOffExit2});
305+
const Fsm::State Fsm::kOff("Off", &FsmOffHandler, nullptr, nullptr, FsmOffEntryActions, FsmOffExitActions);
275306
const Fsm::HistoryState Fsm::kOn("On", &FsmOnHandler, nullptr, &kGreen, &Fsm::Impl::FsmOnEntry, &Fsm::Impl::FsmOnExit);
276307
const Fsm::State Fsm::kGreen("Green", &FsmGreenHandler, &kOn);
277308
const Fsm::State Fsm::kYellow("Yellow", &FsmYellowHandler, &kOn);

0 commit comments

Comments
 (0)