bux API Reference 1.9.0
Static library of whatever are seen required in general purpose but not directly supported from Modern C++. Or whatever reusable originated from my side projects.
Loading...
Searching...
No Matches
FA.h
Go to the documentation of this file.
1#pragma once
2
3// FA stands for Finite Automoton
4
5#include "XException.h" // RUNTIME_ERROR()
6#include <algorithm> // std::set_difference()
7#include <concepts> // std::convertible_to<>, std::invocable<>
8#include <list> // std::list<>
9#include <map> // std::map<>
10#include <set> // std::set<>
11#include <vector> // std::vector<>
12
13namespace bux {
14
15//
16// Types
17//
21{
22public:
23
24 // Nonvirtuals
25 C_NfaState();
26 C_NfaState(const C_NfaState &a) = default;
27 C_NfaState &operator=(const C_NfaState &a) = default;
28 auto operator<=>(const C_NfaState &a) const { return id <=> a.id; }
29 bool operator==(const C_NfaState &a) const { return id == a.id; }
30
31private:
32
33 // Data
34 unsigned id;
35 static unsigned nextId;
36};
37
38enum
39{
41 FA_REPEATABLE = 1<<1
42};
43
44template<class T_Inputs>
46{
47 // Class Methods
48 static bool equalInput(const T_Inputs &a, const T_Inputs &b);
49 static void inputDifference(T_Inputs &dst, const T_Inputs &src);
50 static void inputIntersection(T_Inputs &dst, const T_Inputs &src);
51 static void inputUnion(T_Inputs &dst, const T_Inputs &src);
52 static bool isEmptyInput(const T_Inputs &src);
53};
54
55template<class T_Inputs, class T_Action, class C_Traits> class C_DFA;
56
57template<class T_Inputs, class T_Action, class C_Traits = C_FA_Traits<T_Inputs>>
58class C_NFA
65{
66public:
67
68 // Nonvirtuals
69 C_NFA() = default;
70 C_NFA(const C_NFA &a);
71 C_NFA(C_NFA &&a);
72 C_NFA(const T_Inputs &inputs);
73 void operator=(const C_NFA &a);
74 void operator=(C_NFA &&a);
75 void operator|=(const C_NFA &a);
76 void operator+=(const C_NFA &a) { (void)append(a); }
77 void operator+=(const T_Inputs &inputs) { (void)append(inputs); }
78 C_NFA &append(const C_NFA &a);
79 C_NFA &append(const T_Inputs &inputs);
80 C_NFA &changeTo(int options);
81 template<class T> void setAction(T &&action);
82 size_t totalFinalStates() const { return F.size(); }
83
84private:
85
86 // Types
87 struct C_FinalState: C_NfaState
88 {
89 // Data
90 T_Action m_Tag;
91
92 // Nonvirtuals
93 C_FinalState() = default;
94 C_FinalState(const C_NfaState &a, const T_Action &tag): C_NfaState(a), m_Tag(tag) {}
95 };
96 typedef std::vector<C_FinalState> C_FinalStates;
97
98 struct C_NfaInputSet
99 {
100 // Data
101 T_Inputs m_UserInputs;
102 bool m_Epsilon;
103
104 // Ctor
105 C_NfaInputSet(bool epsilon = false): m_Epsilon(epsilon) {}
106 };
107 typedef std::map<C_NfaState,C_NfaInputSet> C_Transitions;
108 typedef std::map<C_NfaState,C_Transitions> C_TransitionMap;
109
110 // Data
111 C_NfaState q0; // starting point index of Q
112 C_FinalStates F; // final states of Q
113 C_TransitionMap delta; // transition relation
114
115 // Nonvirtuals
116 void gatherStates(std::set<C_NfaState> &usedStates) const;
117 const C_NFA &checkReuse(const std::set<C_NfaState> &usedStates, C_NFA &replacement) const;
118
119 friend class C_DFA<T_Inputs,T_Action,C_Traits>;
120};
121
122template<class T_Inputs, class T_Action, class C_Traits = C_FA_Traits<T_Inputs>>
123class C_DFA
130{
131public:
132
133 // Types
134 typedef std::set<T_Action> C_Conflict;
135
136 // Nonvirtuals
137 template<class F_PickAction>
138 C_DFA(const C_NFA<T_Inputs,T_Action,C_Traits> &nfa, F_PickAction pickAction) requires
139 requires (int tag, const C_Conflict &conflict) {
140 { pickAction(tag, conflict) }->std::convertible_to<T_Action>;
141 }
142 {
143 C_FinalMap Fraw;
144 C_TransitionMap deltaRaw;
145 auto n = nfa2dfa(nfa, Fraw, deltaRaw, pickAction);
146 minDfa(Fraw, deltaRaw, n, F, delta);
147 }
148 template<class F_Get>
149 void eachFinalState(F_Get get) const requires std::invocable<F_Get,int,const T_Action&>
150 {
151 for (const auto &i: F)
152 get(i.first, i.second);
153 }
154 template<class F_Get>
155 void eachTransition(F_Get get) const requires std::invocable<F_Get,int,const T_Inputs&,int>
156 {
157 for (const auto &i: delta)
158 for (const auto &j: i.second)
159 get(i.first, j.second, j.first);
160 }
161 bool isFinal(int state, T_Action &action) const;
162 // Return true and assign action if state is final; return false otherwise
163 static int startingState() { return 0; }
164 size_t totalFinalStates() const { return F.size(); }
165
166private:
167
168 // Types
169 typedef std::set<C_NfaState> C_NfaClosure;
170
171 struct C_TaggedNfaClosure
172 {
173 C_NfaClosure m_Closure;
174 int m_Tag;
175
176 C_TaggedNfaClosure(const C_NfaClosure &closure):
177 m_Closure(closure), m_Tag(0)
178 {}
179 };
180
181 typedef typename C_NFA<T_Inputs,T_Action,C_Traits>::C_TransitionMap C_SourceDelta;
182 typedef std::map<int,T_Action> C_FinalMap;
183 typedef std::map<int,T_Inputs> C_State2Inputs;
184 typedef std::map<int,C_State2Inputs> C_TransitionMap;
185
186 typedef std::set<int> C_DfaClosure;
187 struct C_TaggedDfaClosure
188 {
189 C_DfaClosure m_Closure;
190 int m_Tag;
191
192 C_TaggedDfaClosure()
193 {}
194 C_TaggedDfaClosure(const C_DfaClosure& closure): m_Closure(closure)
195 {}
196 };
197 typedef std::list<C_TaggedDfaClosure> C_DfaClosures;
198 typedef std::map<T_Action,C_DfaClosure> C_Action2Closure;
199
200 //Data
201 C_FinalMap F;
202 C_TransitionMap delta;
203
204 // Nonvirtuals
205 static void buildA2C(const C_FinalMap &Ffat, const C_DfaClosure &closure,
206 C_Action2Closure &a2c);
207 static void createClosure(C_NfaClosure &c, const C_SourceDelta &delta);
208 static typename C_DfaClosures::const_iterator findDfaClosure(const C_DfaClosures &Q, int state);
209 static void minDfa(const C_FinalMap &Ffat, const C_TransitionMap &deltaFat,
210 int totalFatStates, C_FinalMap &Fmin, C_TransitionMap &deltaMin);
211 template<class F_PickAction>
212 static int nfa2dfa(const C_NFA<T_Inputs,T_Action,C_Traits> &nfa, C_FinalMap &F,
213 C_TransitionMap &delta, F_PickAction pickAction);
214 // Return total of the resulting DFA states
215};
216
217//
218// Class Template Implementations
219//
220template<class T_Inputs, class T_Action, class C_Traits>
222 q0(a.q0), F(a.F), delta(a.delta)
223{
224}
225
226template<class T_Inputs, class T_Action, class C_Traits>
228{
229 F.swap(a.F);
230 delta.swap(a.delta);
231}
232
233template<class T_Inputs, class T_Action, class C_Traits>
235{
236 C_FinalState f;
237 delta[q0][f].m_UserInputs = inputs;
238 F.emplace_back(f);
239}
240
241template<class T_Inputs, class T_Action, class C_Traits>
243{
244 q0 = a.q0;
245 F = a.F;
246 delta = a.delta;
247}
248
249template<class T_Inputs, class T_Action, class C_Traits>
251{
252 q0 = a.q0;
253 F.swap(a.F);
254 delta.swap(a.delta);
255}
256
257template<class T_Inputs, class T_Action, class C_Traits>
259{
260 if (F.empty())
261 *this = _a;
262 else
263 {
264 std::set<C_NfaState> usedStates;
265 gatherStates(usedStates);
266 C_NFA _;
267 const C_NFA &a = _a.checkReuse(usedStates, _);
268 F.insert(F.end(), a.F.begin(), a.F.end());
269 delta.insert(a.delta.begin(), a.delta.end());
270 delta[q0][a.q0].m_Epsilon =true;
271 }
272}
273
274template<class T_Inputs, class T_Action, class C_Traits>
276{
277 if (F.empty())
278 *this = _a;
279 else
280 {
281 std::set<C_NfaState> usedStates;
282 gatherStates(usedStates);
283 C_NFA _;
284 const C_NFA &a = _a.checkReuse(usedStates, _);
285 delta.insert(a.delta.begin(), a.delta.end());
286 for (const auto &i: F)
287 delta[i][a.q0].m_Epsilon = true;
288 F = a.F;
289 }
290 return *this;
291}
292
293template<class T_Inputs, class T_Action, class C_Traits>
295{
296 C_FinalState f;
297 if (F.empty())
298 delta[q0][f].m_UserInputs = inputs;
299 else
300 {
301 for (const auto &i: F)
302 delta[i][f].m_UserInputs = inputs;
303
304 F.clear();
305 }
306 F.push_back(f);
307 return *this;
308}
309
310template<class T_Inputs, class T_Action, class C_Traits>
312{
313 for (const auto &i: F)
314 {
315 if (FA_REPEATABLE &options)
316 delta[i][q0].m_Epsilon = true;
317 if (FA_OPTIONAL &options)
318 delta[q0][i].m_Epsilon = true;
319 }
320 return *this;
321}
322
323template<class T_Inputs, class T_Action, class C_Traits>
325 const std::set<C_NfaState> &usedStates,
326 C_NFA<T_Inputs,T_Action,C_Traits> &replacement ) const
327{
328 typedef std::map<C_NfaState,C_NfaState> C_Map;
329 C_Map map;
330 for (const auto &i: delta)
331 {
332 if (usedStates.find(i.first) != usedStates.end())
333 map[i.first];
334
335 for (const auto &j: i.second)
336 if (usedStates.find(j.first) != usedStates.end())
337 map[j.first];
338 }
339 if (map.empty())
340 // No conflict
341 return *this;
342
343 C_Map::const_iterator found = map.find(q0);
344 replacement.q0 = found != map.end()? found->second: q0;
345
346 for (const auto &i: F)
347 {
348 found = map.find(i);
349 replacement.F.emplace_back(found != map.end()? found->second: i, i.m_Tag);
350 }
351
352 for (const auto &i: delta)
353 {
354 found = map.find(i.first);
355 auto &t =replacement.delta[found != map.end()? found->second: i.first];
356 for (const auto &j: i.second)
357 {
358 found = map.find(j.first);
359 t[found != map.end()? found->second: j.first] =j.second;
360 }
361 }
362 return replacement;
363}
364
365template<class T_Inputs, class T_Action, class C_Traits>
366void C_NFA<T_Inputs,T_Action,C_Traits>::gatherStates(std::set<C_NfaState> &usedStates) const
367{
368 for (const auto &i: delta)
369 {
370 usedStates.insert(i.first);
371 for (const auto &j: i.second)
372 usedStates.insert(j.first);
373 }
374}
375
376template<class T_Inputs, class T_Action, class C_Traits>
377template<class T>
379{
380 for (auto &i: F)
381 i.m_Tag = std::forward<T>(action);
382}
383
384template<class T_Inputs, class T_Action, class C_Traits>
386 const C_FinalMap &Ffat,
387 const C_DfaClosure &closure,
388 C_Action2Closure &a2c )
389{
390 for (const auto &i: Ffat)
391 {
392 if (closure.find(i.first) != closure.end())
393 a2c[i.second].insert(i.first);
394 }
395}
396
397template<class T_Inputs, class T_Action, class C_Traits>
398void C_DFA<T_Inputs,T_Action,C_Traits>::createClosure(C_NfaClosure &c, const C_SourceDelta &delta)
399{
400 C_NfaClosure test(c);
401 while (true)
402 {
403 C_NfaClosure add;
404 for (const auto &i: test)
405 {
406 const auto found = delta.find(i);
407 if (found != delta.end())
408 {
409 for (const auto &j: found->second)
410 if (j.second.m_Epsilon && c.find(j.first) == c.end())
411 add.insert(j.first);
412 }
413 }
414 if (add.empty())
415 break;
416
417 c.insert(add.begin(), add.end());
418 test.swap(add);
419 }
420}
421
422template<class T_Inputs, class T_Action, class C_Traits>
423auto C_DFA<T_Inputs,T_Action,C_Traits>::findDfaClosure(const C_DfaClosures &Q, int state) -> typename C_DfaClosures::const_iterator
424{
425 for (auto i = Q.begin(), end = Q.end(); i != end; ++i)
426 {
427 if (i->m_Closure.find(state) != i->m_Closure.end())
428 // Found
429 return i;
430 }
431 RUNTIME_ERROR("State {} not found", state);
432}
433
434template<class T_Inputs, class T_Action, class C_Traits>
435bool C_DFA<T_Inputs,T_Action,C_Traits>::isFinal(int state, T_Action &action) const
436{
437 const auto i =F.find(state);
438 if (i != F.end())
439 {
440 action = i->second;
441 return true;
442 }
443 return false;
444}
445
446template<class T_Inputs, class T_Action, class C_Traits>
448 const C_FinalMap &Ffat,
449 const C_TransitionMap &deltaFat,
450 int totalFatStates,
451 C_FinalMap &Fmin,
452 C_TransitionMap &deltaMin )
453{
454 // Figure 7.7: Algorithm MinDFA
455 C_DfaClosures Qfat;
456 Qfat.emplace_back();
457 Qfat.emplace_back();
458 auto &part0 = Qfat.front().m_Closure;
459 auto &part1 = Qfat.back().m_Closure;
460 int tag =0;
461 for (const auto &i: Ffat)
462 {
463 part0.insert(i.first);
464 while (tag < i.first)
465 part1.insert(tag++);
466
467 ++tag;
468 }
469 while (tag < totalFatStates)
470 part1.insert(tag++);
471
472 bool changed;
473 do
474 {
475 changed = false;
476 C_DfaClosures Qmin;
477 for (const auto &i: Qfat)
478 {
479 auto fat = i.m_Closure;
480 while (!fat.empty())
481 {
482 C_DfaClosure slim;
483 auto j = fat.begin();
484 slim.insert(*j);
485 typedef std::map<const C_DfaClosure*,T_Inputs> C_CmpMap;
486 C_CmpMap cmpmap;
487 auto k = deltaFat.find(*j);
488 if (k != deltaFat.end())
489 for (const auto &m: k->second)
490 cmpmap[&findDfaClosure(Qfat, m.first)->m_Closure] = m.second;
491
492 while (++j != fat.end())
493 {
494 C_CmpMap map;
495 bool deal = true;
496 k = deltaFat.find(*j);
497 if (k != deltaFat.end())
498 for (const auto &m: k->second)
499 {
500 const auto *t = &findDfaClosure(Qfat, m.first)->m_Closure;
501 auto found = cmpmap.find(t);
502 if (found != cmpmap.end() &&
503 C_Traits::equalInput(m.second, found->second))
504 {
505 map[t] = m.second;
506 continue;
507 }
508 deal = false;
509 break;
510 }
511 if (deal)
512 {
513 auto i_map = map.begin();
514 for (auto &j_cmp: cmpmap)
515 {
516 if (i_map == map.end() ||
517 i_map->first != j_cmp.first ||
518 !C_Traits::equalInput(i_map->second, j_cmp.second))
519 {
520 deal = false;
521 break;
522 }
523 ++i_map;
524 }
525 if (deal && i_map == map.end())
526 slim.insert(*j);
527 }
528 }
529 Qmin.emplace_back(slim);
530 C_DfaClosure temp;
531 std::set_difference(fat.begin(), fat.end(),
532 slim.begin(), slim.end(), std::inserter(temp, temp.begin()));
533 fat.swap(temp);
534 }
535 }
536 if (Qmin.size() == Qfat.size())
537 {
538 for (auto i =Qmin.begin(), end =Qmin.end(); i != end; ++i)
539 {
540 C_Action2Closure a2c;
541 buildA2C(Ffat, i->m_Closure, a2c);
542 if (a2c.size() > 1)
543 {
544 // Solve conflict
545 auto j = a2c.begin();
546 i->m_Closure.swap(j->second); // overwrite the superset
547 auto next = i;
548 ++next;
549 while (++j != a2c.end())
550 i = Qmin.insert(next, j->second);
551 }
552 }
553 }
554 if (Qmin.size() != Qfat.size())
555 {
556 Qfat.swap(Qmin);
557 changed =true;
558 }
559 } while (changed);
560
561 // Tagging
562 tag =0;
563 for (auto i = Qfat.begin(), end = Qfat.end(); i != end; ++i, ++tag)
564 {
565 if (tag && i->m_Closure.find(0) != i->m_Closure.end())
566 // Q0 is always tagged 0
567 {
568 i->m_Tag = 0;
569 Qfat.front().m_Tag = tag;
570 auto t = Fmin.find(0);
571 if (t != Fmin.end())
572 {
573 const auto a = t->second;
574 Fmin.erase(t);
575 Fmin[tag] = a;
576 }
577 }
578 else
579 i->m_Tag = tag;
580
581 C_Action2Closure a2c;
582 buildA2C(Ffat, i->m_Closure, a2c);
583 if (!a2c.empty())
584 {
585 Fmin[i->m_Tag] = a2c.begin()->first;
586 if (a2c.size() > 1)
587 // Impossible
588 RUNTIME_ERROR("a2c.size() == ()", a2c.size());
589 }
590 }
591 for (const auto &i: deltaFat)
592 {
593 auto &dst_i = deltaMin[findDfaClosure(Qfat,i.first)->m_Tag];
594 for (const auto &j: i.second)
595 {
596 const auto value = findDfaClosure(Qfat,j.first)->m_Tag;
597 for (const auto &dst_j: dst_i)
598 {
599 if (C_Traits::equalInput(dst_j.second, j.second))
600 {
601 if (dst_j.first == value)
602 // Aleady added
603 goto PostInsertion;
604
605 RUNTIME_ERROR("Contradicted mapping");
606 }
607 }
608 C_Traits::inputUnion(dst_i[value], j.second);
609 PostInsertion:;
610 }
611 }
612}
613
614template<class T_Inputs, class T_Action, class C_Traits>
615template<class F_PickAction>
616int C_DFA<T_Inputs,T_Action,C_Traits>::nfa2dfa(const C_NFA<T_Inputs,T_Action,C_Traits> &nfa,
617 C_FinalMap &F, C_TransitionMap &delta, F_PickAction pickAction)
618{
619 // Figure 7.5 (p245): Algorithm NFA->DFA
620 std::list<C_TaggedNfaClosure> Q; // collector of all states
621 Q.emplace_back(C_NfaClosure{});
622 auto *const q0 = &Q.front().m_Closure; // starting point index of Q
623 q0->insert(nfa.q0);
624 createClosure(*q0, nfa.delta);
625
626 typedef std::pair<T_Inputs, const C_TaggedNfaClosure*> C_InputClosurePair;
627 typedef std::vector<C_InputClosurePair> C_Input2Closure;
628 std::map<const C_TaggedNfaClosure*, C_Input2Closure,
629 bool (*)(const C_TaggedNfaClosure*,const C_TaggedNfaClosure*)>
630 deltaNfa([](const C_TaggedNfaClosure *a, const C_TaggedNfaClosure *b)->bool {
631 return a->m_Closure < b->m_Closure;
632 }); // transition relation
633 bool changed;
634 do
635 {
636 changed =false;
637 for (auto &q: Q)
638 {
639 if (q.m_Tag)
640 continue;
641
642 typedef std::map<C_NfaClosure,T_Inputs> C_ShiftMap;
643 C_ShiftMap map;
644 q.m_Tag = true;
645 for (const auto &j: q.m_Closure)
646 {
647 auto found = nfa.delta.find(j);
648 if (found != nfa.delta.end())
649 for (const auto &k: found->second)
650 {
651 if (!C_Traits::isEmptyInput(k.second.m_UserInputs))
652 {
653 C_NfaClosure key;
654 key.insert(k.first);
655 C_Traits::inputUnion(map[key], k.second.m_UserInputs);
656 }
657 }
658 }
659 // Here map is already created with keys of state singletons and values without epsilon
660 C_ShiftMap partitionedMap;
661 MergeAgain:
662 switch (map.size())
663 {
664 case 1:
665 partitionedMap.insert(*map.begin());
666 break;
667 case 0:
668 break;
669 default: // > 1
670 for (auto i = map.begin(), end = map.end(); i != end; ++i)
671 for (auto j = i; ++j != end;)
672 {
673 // Emptyness of (i - j)
674 T_Inputs insetsect(i->second);
675 C_Traits::inputIntersection(insetsect, j->second);
676 if (C_Traits::isEmptyInput(insetsect))
677 continue;
678
679 if (map.begin() != i)
680 // Move away the disjointed part first
681 {
682 partitionedMap.insert(map.begin(), i);
683 map.erase(map.begin(), i);
684 }
685 C_NfaClosure key(i->first);
686 key.insert(j->first.begin(), j->first.end());
687
688 T_Inputs t(i->second);
689 C_Traits::inputDifference(t, insetsect);
690 if (C_Traits::isEmptyInput(t))
691 map.erase(i);
692 else
693 i->second = t;
694
695 t = j->second;
696 C_Traits::inputDifference(t, insetsect);
697 if (C_Traits::isEmptyInput(t))
698 map.erase(j);
699 else
700 j->second = t;
701
702 map[key] =insetsect;
703 goto MergeAgain;
704 }
705 partitionedMap.insert(map.begin(), map.end());
706 } // switch (map.size())
707 map.swap(partitionedMap);
708 /* Here map is with
709 * keys union of which equals to union of original keys
710 * and
711 * values which together partition the union of all original values except episilon.
712 */
713 for (const auto &j: map)
714 {
715 C_TaggedNfaClosure t(j.first);
716 createClosure(t.m_Closure, nfa.delta);
717 const C_TaggedNfaClosure *next;
718 for (const auto &k: Q)
719 if (t.m_Closure == k.m_Closure)
720 {
721 next = &k;
722 goto postAddClosure;
723 }
724 Q.emplace_back(t); // new state t
725 next = &Q.back();
726 postAddClosure:
727 deltaNfa[&q].emplace_back(j.second, next);
728 changed =true;
729 }
730 }
731 } while (changed);
732
733 int tag = 0;
734 for (auto &i: Q)
735 {
736 i.m_Tag = tag++;
737 C_Conflict conflict;
738 for (const auto &j: nfa.F)
739 {
740 if (i.m_Closure.find(j) != i.m_Closure.end())
741 conflict.insert(j.m_Tag);
742 }
743 if (!conflict.empty())
744 {
745 if (conflict.size() > 1)
746 // Solve conflict
747 {
748 auto action = pickAction(i.m_Tag, conflict);
749 if (action == T_Action())
750 RUNTIME_ERROR("Interrupted");
751
752 F[i.m_Tag] = action;
753 }
754 else
755 F[i.m_Tag] = *conflict.begin();
756 }
757 }
758
759 for (const auto &i: deltaNfa)
760 {
761 auto &dstMap = delta[i.first->m_Tag];
762 for (const auto &j: i.second)
763 C_Traits::inputUnion(dstMap[j.second->m_Tag], j.first);
764 }
765 return tag;
766}
767
768} // namespace bux
#define RUNTIME_ERROR(fmtStr,...)
Wrap FILE(DATE)#__LINE__ FUNCTION: msg into std::runtime_error.
Definition XException.h:32
static int startingState()
Definition FA.h:163
void eachFinalState(F_Get get) const
Definition FA.h:149
size_t totalFinalStates() const
Definition FA.h:164
C_DFA(const C_NFA< T_Inputs, T_Action, C_Traits > &nfa, F_PickAction pickAction)
Definition FA.h:138
bool isFinal(int state, T_Action &action) const
Definition FA.h:435
void eachTransition(F_Get get) const
Definition FA.h:155
std::set< T_Action > C_Conflict
Definition FA.h:134
void operator|=(const C_NFA &a)
Definition FA.h:258
C_NFA & append(const C_NFA &a)
Definition FA.h:275
void operator+=(const T_Inputs &inputs)
Definition FA.h:77
void operator+=(const C_NFA &a)
Definition FA.h:76
C_NFA & changeTo(int options)
Definition FA.h:311
size_t totalFinalStates() const
Definition FA.h:82
void setAction(T &&action)
Definition FA.h:378
C_NFA()=default
void operator=(const C_NFA &a)
Definition FA.h:242
C_NfaState(const C_NfaState &a)=default
bool operator==(const C_NfaState &a) const
Definition FA.h:29
auto operator<=>(const C_NfaState &a) const
Definition FA.h:28
C_NfaState & operator=(const C_NfaState &a)=default
THE common namespace of bux library.
Definition AtomiX.cpp:3
@ FA_OPTIONAL
Definition FA.h:40
@ FA_REPEATABLE
Definition FA.h:41
static void inputUnion(T_Inputs &dst, const T_Inputs &src)
static bool isEmptyInput(const T_Inputs &src)
static void inputDifference(T_Inputs &dst, const T_Inputs &src)
static bool equalInput(const T_Inputs &a, const T_Inputs &b)
static void inputIntersection(T_Inputs &dst, const T_Inputs &src)