4444#include " maxplus/base/basic_types.h"
4545#include " maxplus/base/exception/exception.h"
4646#include " maxplus/base/string/cstring.h"
47+ #include < functional>
4748#include < list>
4849#include < map>
4950#include < memory>
5051#include < set>
52+ #include < utility>
5153
5254namespace FSM {
5355
@@ -210,6 +212,7 @@ class FiniteStateMachine {
210212 [[nodiscard]] virtual const SetOfStateRefs &getInitialStates () const = 0;
211213 [[nodiscard]] virtual const SetOfStateRefs &getFinalStates () const = 0;
212214 [[nodiscard]] virtual const SetOfStates &getStates () const = 0;
215+ [[nodiscard]] virtual SetOfStateRefs getStateRefs () const = 0;
213216 [[nodiscard]] virtual const SetOfEdges &getEdges () const = 0;
214217};
215218
@@ -250,8 +253,9 @@ class DepthFirstSearch {
250253 SetOfEdgeRefs::CIter iter;
251254 };
252255
253- protected:
254256 using DfsStack = std::list<DFSStackItem>;
257+
258+ protected:
255259 DfsStack dfsStack;
256260
257261public:
@@ -266,60 +270,147 @@ class DepthFirstSearch {
266270
267271 virtual void onSimpleCycle (DfsStack &stack){};
268272
273+ const FiniteStateMachine &getFSM () { return this ->fsm ; }
274+
269275 explicit DepthFirstSearch (const FiniteStateMachine &targetFsm) : fsm(targetFsm){};
270276
271277 // Execute the depth first search
272- void DoDepthFirstSearch (const StateRef &startingState , bool fullDFS = false ) {
278+ void DoDepthFirstSearch (const SetOfStateRefs &startingStates , bool fullDFS = false ) {
273279 // store visited states
274280 SetOfStateRefs visitedStates;
275281 SetOfStateRefs statesOnStack;
276282
277- // put initial state on the stack
278- dfsStack.emplace_back (startingState);
279- this ->onEnterState (startingState);
280-
281- while (!(dfsStack.empty ())) {
282- DFSStackItem &si = dfsStack.back ();
283-
284- // current item complete?
285- if (si.atEnd ()) {
286- // pop it from stack
287- this ->onLeaveState (si.getState ());
288- const auto *const s = si.getState ();
289- statesOnStack.erase (s);
290- if (fullDFS) {
291- assert (visitedStates.includesState (s));
292- visitedStates.erase (s);
283+ this ->_abort = false ;
284+
285+ // for each of the starting states
286+ auto nextStartingState = startingStates.begin ();
287+ while (nextStartingState != startingStates.end ()) {
288+
289+ // skip states we have already visited
290+ while (nextStartingState != startingStates.end ()
291+ && visitedStates.includesState (*nextStartingState)) {
292+ nextStartingState++;
293+ }
294+ // if we did not find any state anymore
295+ if (nextStartingState == startingStates.end ()) {
296+ break ;
297+ }
298+
299+ statesOnStack.clear ();
300+ StateRef s = *nextStartingState;
301+ dfsStack.emplace_back (s);
302+ statesOnStack.insert (s);
303+ visitedStates.insert (s);
304+ this ->onEnterState (s);
305+
306+ while (!this ->_abort && !(dfsStack.empty ())) {
307+ DFSStackItem &si = dfsStack.back ();
308+ if (!visitedStates.includesState (si.getState ())) {
309+ this ->onEnterState (si.getState ());
310+ visitedStates.insert (si.getState ());
293311 }
294- dfsStack.pop_back ();
295- } else {
296- // goto next edge
297- const auto *e = *(si.getIter ());
298- si.advance ();
299- StateRef dest = e->getDestination ();
300- bool revisit = statesOnStack.includesState (dest);
301- if (revisit) {
302- // cycle found
303- this ->onSimpleCycle (dfsStack);
312+ // current item complete?
313+ if (si.atEnd ()) {
314+ // pop it from stack
315+ this ->onLeaveState (si.getState ());
316+ const auto *const s = si.getState ();
317+ statesOnStack.erase (s);
318+ if (fullDFS) {
319+ assert (visitedStates.includesState (s));
320+ visitedStates.erase (s);
321+ }
322+ dfsStack.pop_back ();
304323 } else {
305- // if target state not visited before
306- dfsStack.emplace_back (dest);
307- this ->onTransition (*e);
308- this ->onEnterState (dest);
309- visitedStates.insert (dest);
310- statesOnStack.insert (dest);
324+ // goto next edge
325+ const auto *e = *(si.getIter ());
326+ si.advance ();
327+ StateRef dest = e->getDestination ();
328+ bool revisit = statesOnStack.includesState (dest);
329+ if (revisit) {
330+ // cycle found
331+ this ->onSimpleCycle (dfsStack);
332+ } else {
333+ if (!visitedStates.includesState (dest)) {
334+ // if target state not visited before
335+ dfsStack.emplace_back (dest);
336+ this ->onTransition (*e);
337+ this ->onEnterState (dest);
338+ visitedStates.insert (dest);
339+ statesOnStack.insert (dest);
340+ }
341+ }
311342 }
312343 }
313344 }
314345 }
315346
347+ void DoDepthFirstSearch (const StateRef &startingState, bool fullDFS = false ) {
348+ SetOfStateRefs stateSet;
349+ stateSet.insert (startingState);
350+ return this ->DoDepthFirstSearch (stateSet, fullDFS);
351+ }
352+
316353 // Execute the depth first search
317354 void DoDepthFirstSearch (bool fullDFS = false ) {
318- this ->DoDepthFirstSearch (this ->fsm .getInitialState (), fullDFS);
355+ this ->DoDepthFirstSearch (this ->fsm .getInitialStates (), fullDFS);
319356 }
320357
321- protected:
358+ void abortDFS () { this ->_abort = true ; }
359+
360+ private:
322361 const FiniteStateMachine &fsm;
362+ bool _abort{};
363+ };
364+
365+ class DepthFirstSearchLambda : public DepthFirstSearch {
366+
367+ public:
368+ DepthFirstSearchLambda (const DepthFirstSearchLambda &) = delete ;
369+ DepthFirstSearchLambda &operator =(const DepthFirstSearchLambda &other) = delete ;
370+ DepthFirstSearchLambda (DepthFirstSearch &&) = delete ;
371+ DepthFirstSearchLambda &operator =(DepthFirstSearchLambda &&) = delete ;
372+
373+ private:
374+ using TOnEnterLambda = std::function<void (StateRef s)>;
375+ TOnEnterLambda _onEnterStateLambda;
376+ using TOnLeaveLambda = std::function<void (StateRef s)>;
377+ TOnLeaveLambda _onLeaveStateLambda;
378+ using TOnTransitionLambda = std::function<void (const Edge &e)>;
379+ TOnTransitionLambda _onTransitionLambda;
380+ using TOnSimpleCycleLambda = std::function<void (const DepthFirstSearch::DfsStack &stack)>;
381+ TOnSimpleCycleLambda _onSimpleCycleLambda;
382+
383+ public:
384+ ~DepthFirstSearchLambda () override = default ;
385+
386+ void onEnterState (StateRef s) override { this ->_onEnterStateLambda (s); };
387+
388+ void onLeaveState (StateRef s) override { this ->_onLeaveStateLambda (s); };
389+
390+ void onTransition (const Edge &e) override { this ->_onTransitionLambda (e); };
391+
392+ void onSimpleCycle (DepthFirstSearch::DfsStack &stack) override {
393+ this ->_onSimpleCycleLambda (stack);
394+ };
395+
396+ explicit DepthFirstSearchLambda (const FiniteStateMachine &targetFsm) :
397+ _onEnterStateLambda([](StateRef) {}),
398+ _onLeaveStateLambda ([](StateRef) {}),
399+ _onTransitionLambda ([](const Edge &) {}),
400+ _onSimpleCycleLambda ([](const DepthFirstSearch::DfsStack &) {}),
401+ DepthFirstSearch (targetFsm){};
402+
403+ void setOnEnterLambda (TOnEnterLambda lambda) { this ->_onEnterStateLambda = std::move (lambda); }
404+
405+ void setOnLeaveLambda (TOnLeaveLambda lambda) { this ->_onLeaveStateLambda = std::move (lambda); }
406+
407+ void setOnTransitionLambda (TOnTransitionLambda lambda) {
408+ this ->_onTransitionLambda = std::move (lambda);
409+ }
410+
411+ void setOnSimpleCycleLambda (TOnSimpleCycleLambda lambda) {
412+ this ->_onSimpleCycleLambda = std::move (lambda);
413+ }
323414};
324415
325416// Check for cycles
@@ -339,30 +430,15 @@ class DetectCycle : public DepthFirstSearch {
339430 bool checkForCycles () { return this ->checkForCycles (nullptr ); }
340431
341432 bool checkForCycles (ListOfStateRefs *cycle) {
342- this ->visitedStates .clear ();
343433 this ->cycle = cycle;
344- const SetOfStates &states = this ->fsm .getStates ();
345- auto nextStartingState = states.begin ();
346- while (nextStartingState != states.end ()) {
347- this ->DoDepthFirstSearch ((*nextStartingState).second ->getReference ());
348- if (this ->hasCycle ) {
349- return true ;
350- }
351- while (nextStartingState != states.end ()
352- && this ->visitedStates .includesState (
353- (*nextStartingState).second ->getReference ())) {
354- nextStartingState++;
355- }
356- }
357- return false ;
434+ const SetOfStateRefs states = this ->getFSM ().getStateRefs ();
435+ this ->DoDepthFirstSearch (states);
436+ return this ->hasCycle ;
358437 }
359438
360439private:
361- SetOfStateRefs visitedStates;
362440 ListOfStateRefs *cycle = nullptr ;
363441
364- void onEnterState (StateRef s) override { this ->visitedStates .insert (s); }
365-
366442 void onSimpleCycle (DfsStack &stack) override {
367443 if (!this ->hasCycle ) {
368444 if (this ->cycle != nullptr ) {
@@ -371,6 +447,7 @@ class DetectCycle : public DepthFirstSearch {
371447 }
372448 }
373449 this ->hasCycle = true ;
450+ this ->abortDFS ();
374451 }
375452 }
376453};
@@ -657,6 +734,14 @@ class FiniteStateMachine : public Abstract::FiniteStateMachine {
657734 return this ->states ;
658735 };
659736
737+ [[nodiscard]] FSM::Abstract::SetOfStateRefs getStateRefs () const override {
738+ FSM::Abstract::SetOfStateRefs result;
739+ for (const auto &s : this ->states ) {
740+ result.insert (s.second ->getReference ());
741+ }
742+ return result;
743+ };
744+
660745 [[nodiscard]] const SetOfEdges<StateLabelType, EdgeLabelType> &getEdges () const override {
661746 return this ->edges ;
662747 };
0 commit comments