44
44
#include " maxplus/base/basic_types.h"
45
45
#include " maxplus/base/exception/exception.h"
46
46
#include " maxplus/base/string/cstring.h"
47
+ #include < functional>
47
48
#include < list>
48
49
#include < map>
49
50
#include < memory>
50
51
#include < set>
52
+ #include < utility>
51
53
52
54
namespace FSM {
53
55
@@ -210,6 +212,7 @@ class FiniteStateMachine {
210
212
[[nodiscard]] virtual const SetOfStateRefs &getInitialStates () const = 0;
211
213
[[nodiscard]] virtual const SetOfStateRefs &getFinalStates () const = 0;
212
214
[[nodiscard]] virtual const SetOfStates &getStates () const = 0;
215
+ [[nodiscard]] virtual SetOfStateRefs getStateRefs () const = 0;
213
216
[[nodiscard]] virtual const SetOfEdges &getEdges () const = 0;
214
217
};
215
218
@@ -250,8 +253,9 @@ class DepthFirstSearch {
250
253
SetOfEdgeRefs::CIter iter;
251
254
};
252
255
253
- protected:
254
256
using DfsStack = std::list<DFSStackItem>;
257
+
258
+ protected:
255
259
DfsStack dfsStack;
256
260
257
261
public:
@@ -266,60 +270,147 @@ class DepthFirstSearch {
266
270
267
271
virtual void onSimpleCycle (DfsStack &stack){};
268
272
273
+ const FiniteStateMachine &getFSM () { return this ->fsm ; }
274
+
269
275
explicit DepthFirstSearch (const FiniteStateMachine &targetFsm) : fsm(targetFsm){};
270
276
271
277
// Execute the depth first search
272
- void DoDepthFirstSearch (const StateRef &startingState , bool fullDFS = false ) {
278
+ void DoDepthFirstSearch (const SetOfStateRefs &startingStates , bool fullDFS = false ) {
273
279
// store visited states
274
280
SetOfStateRefs visitedStates;
275
281
SetOfStateRefs statesOnStack;
276
282
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 ());
293
311
}
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 ();
304
323
} 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
+ }
311
342
}
312
343
}
313
344
}
314
345
}
315
346
347
+ void DoDepthFirstSearch (const StateRef &startingState, bool fullDFS = false ) {
348
+ SetOfStateRefs stateSet;
349
+ stateSet.insert (startingState);
350
+ return this ->DoDepthFirstSearch (stateSet, fullDFS);
351
+ }
352
+
316
353
// Execute the depth first search
317
354
void DoDepthFirstSearch (bool fullDFS = false ) {
318
- this ->DoDepthFirstSearch (this ->fsm .getInitialState (), fullDFS);
355
+ this ->DoDepthFirstSearch (this ->fsm .getInitialStates (), fullDFS);
319
356
}
320
357
321
- protected:
358
+ void abortDFS () { this ->_abort = true ; }
359
+
360
+ private:
322
361
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
+ }
323
414
};
324
415
325
416
// Check for cycles
@@ -339,30 +430,15 @@ class DetectCycle : public DepthFirstSearch {
339
430
bool checkForCycles () { return this ->checkForCycles (nullptr ); }
340
431
341
432
bool checkForCycles (ListOfStateRefs *cycle) {
342
- this ->visitedStates .clear ();
343
433
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 ;
358
437
}
359
438
360
439
private:
361
- SetOfStateRefs visitedStates;
362
440
ListOfStateRefs *cycle = nullptr ;
363
441
364
- void onEnterState (StateRef s) override { this ->visitedStates .insert (s); }
365
-
366
442
void onSimpleCycle (DfsStack &stack) override {
367
443
if (!this ->hasCycle ) {
368
444
if (this ->cycle != nullptr ) {
@@ -371,6 +447,7 @@ class DetectCycle : public DepthFirstSearch {
371
447
}
372
448
}
373
449
this ->hasCycle = true ;
450
+ this ->abortDFS ();
374
451
}
375
452
}
376
453
};
@@ -657,6 +734,14 @@ class FiniteStateMachine : public Abstract::FiniteStateMachine {
657
734
return this ->states ;
658
735
};
659
736
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
+
660
745
[[nodiscard]] const SetOfEdges<StateLabelType, EdgeLabelType> &getEdges () const override {
661
746
return this ->edges ;
662
747
};
0 commit comments