Skip to content
This repository was archived by the owner on Mar 4, 2025. It is now read-only.

Commit bddb1cc

Browse files
committed
enum for states, refactored names, refactored tail recursion
- You can now use an enum to represent states in the state machine. - Huge refatcoring of class names - Tail recursion deleted (GoToState method)
1 parent add2c83 commit bddb1cc

15 files changed

Lines changed: 299 additions & 101 deletions
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
6+
namespace Library.CallbackInvokers
7+
{
8+
public class StateCallbackInvoker<TState>
9+
{
10+
public StateCallback<TState> Callback { get; private set; }
11+
12+
public StateCallbackInvoker(StateCallback<TState> callback)
13+
{
14+
Callback = callback;
15+
}
16+
17+
public void Invoke(TState state)
18+
{
19+
Callback(state);
20+
}
21+
}
22+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
6+
namespace Library.CallbackInvokers
7+
{
8+
public class TransitionCallbackInvoker<TState>
9+
{
10+
public ArcCallback<TState> Callback { get; private set; }
11+
12+
public TransitionCallbackInvoker(ArcCallback<TState> callback)
13+
{
14+
Callback = callback;
15+
}
16+
17+
public void Invoke(TState source, TState target)
18+
{
19+
Callback(source, target);
20+
}
21+
}
22+
}

Library/Exceptions/StateMachineException.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public StateMachineException(ErrorCodes ec, string message, Exception innerExcep
2525
ErrorCode = ec;
2626
}
2727

28-
public static string MakeArcName(string source, string target)
28+
public static string MakeArcName<TState>(TState source, TState target)
2929
{
3030
return string.Format("{0} -> {1}", source, target);
3131
}

Library/Library.csproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,11 @@
7474
<Reference Include="System.Xml" />
7575
</ItemGroup>
7676
<ItemGroup>
77-
<Compile Include="Arc.cs" />
78-
<Compile Include="Callbacks\ArcCallbackInvoker.cs" />
77+
<Compile Include="Transition.cs" />
78+
<Compile Include="CallbackInvokers\TransitionCallbackInvoker.cs" />
7979
<Compile Include="ErrorCodes.cs" />
80-
<Compile Include="Callbacks\StateCallbackInvoker.cs" />
81-
<Compile Include="State.cs" />
80+
<Compile Include="CallbackInvokers\StateCallbackInvoker.cs" />
81+
<Compile Include="StateContainer.cs" />
8282
<Compile Include="StateMachine.cs" />
8383
<Compile Include="Properties\AssemblyInfo.cs" />
8484
<Compile Include="Exceptions\StateMachineException.cs" />

Library/StateContainer.cs

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using Library.CallbackInvokers;
6+
using Library.Exceptions;
7+
8+
namespace Library
9+
{
10+
public class StateContainer<TState>
11+
{
12+
private Dictionary<TState, Transition<TState>> _arcsMap;
13+
private IList<StateCallbackInvoker<TState>> _enterCallbacks;
14+
private IList<StateCallbackInvoker<TState>> _exitCallbacks;
15+
16+
public TState Name { get; private set; }
17+
18+
public Transition<TState> this[StateContainer<TState> s]
19+
{
20+
get
21+
{
22+
if (!_arcsMap.ContainsKey(s.Name))
23+
{
24+
return null;
25+
}
26+
27+
return _arcsMap[s.Name];
28+
}
29+
}
30+
31+
public StateContainer(TState stateName)
32+
{
33+
Name = stateName;
34+
35+
_arcsMap = new Dictionary<TState, Transition<TState>>();
36+
_enterCallbacks = new List<StateCallbackInvoker<TState>>();
37+
_exitCallbacks = new List<StateCallbackInvoker<TState>>();
38+
}
39+
40+
public void AddArc(StateContainer<TState> s)
41+
{
42+
if (_arcsMap.ContainsKey(s.Name))
43+
{
44+
throw new StateMachineException(ErrorCodes.AlreadyPresentArc, StateMachineException.MakeArcName(Name, s.Name));
45+
}
46+
47+
Transition<TState> a = new Transition<TState>(this, s);
48+
_arcsMap[s.Name] = a;
49+
}
50+
51+
public void AddStateCallback(StateCallback<TState> method, bool enter)
52+
{
53+
StateCallbackInvoker<TState> sci = new StateCallbackInvoker<TState>(method);
54+
55+
if (enter)
56+
{
57+
_enterCallbacks.Add(sci);
58+
}
59+
else
60+
{
61+
_exitCallbacks.Add(sci);
62+
}
63+
}
64+
65+
public void AddTransitArcCallback(TState target, ArcCallback<TState> method)
66+
{
67+
if (!_arcsMap.ContainsKey(target))
68+
{
69+
throw new StateMachineException(ErrorCodes.UnknownArc, StateMachineException.MakeArcName(Name, target));
70+
}
71+
72+
Transition<TState> a = _arcsMap[target];
73+
74+
a.AddTransitionCallback(method);
75+
}
76+
77+
public void CallEnterCallbacks()
78+
{
79+
foreach (StateCallbackInvoker<TState> sci in _enterCallbacks)
80+
{
81+
sci.Invoke(Name);
82+
}
83+
}
84+
85+
public void CallExitCallbacks()
86+
{
87+
foreach (StateCallbackInvoker<TState> sci in _exitCallbacks)
88+
{
89+
sci.Invoke(Name);
90+
}
91+
}
92+
}
93+
}

Library/StateMachine.cs

Lines changed: 47 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -3,157 +3,140 @@
33
using System.Linq;
44
using System.Text;
55
using Library.Exceptions;
6-
using Library.Callbacks;
6+
using Library.CallbackInvokers;
77

88
namespace Library
99
{
10-
public delegate void StateCallback(string currentState);
11-
public delegate void ArcCallback(string sourceState, string targetState);
10+
public delegate void StateCallback<TState>(TState currentState);
11+
public delegate void ArcCallback<TState>(TState sourceState, TState targetState);
1212

13-
public class StateMachine
13+
public class StateMachine<TState>
1414
{
15-
private Dictionary<string, State> _statesMap;
16-
private string _postedState;
15+
private IDictionary<TState, StateContainer<TState>> _statesMap;
1716

1817
public bool Transiting;
19-
public State CurrentState { get; private set; }
20-
private State this[string stateName]
18+
public StateContainer<TState> CurrentState { get; private set; }
19+
private StateContainer<TState> this[TState state]
2120
{
2221
get
2322
{
24-
if (!_statesMap.ContainsKey(stateName))
23+
if (!_statesMap.ContainsKey(state))
2524
{
2625
return null;
2726
}
2827

29-
return _statesMap[stateName];
28+
return _statesMap[state];
3029
}
3130
}
3231

3332

3433
public StateMachine()
3534
{
36-
_statesMap = new Dictionary<string, State>();
37-
_postedState = string.Empty;
35+
_statesMap = new Dictionary<TState, StateContainer<TState>>();
3836
Transiting = false;
3937

4038
CurrentState = null;
4139
}
4240

43-
public void AddState(string stateName)
41+
public void AddState(TState stateName)
4442
{
4543
if (this[stateName] != null)
4644
{
47-
throw new StateMachineException(ErrorCodes.AlreadyPresentState, stateName);
45+
throw new StateMachineException(ErrorCodes.AlreadyPresentState, stateName.ToString());
4846
}
4947

50-
State s = new State(stateName);
48+
StateContainer<TState> s = new StateContainer<TState>(stateName);
5149
_statesMap[stateName] = s;
5250
}
5351

54-
public void AddArc(string source, string target)
52+
public void AddTransition(TState source, TState target)
5553
{
56-
State sourceState = this[source];
54+
StateContainer<TState> sourceState = this[source];
5755

5856
if (sourceState == null)
5957
{
60-
throw new StateMachineException(ErrorCodes.UnknownState, source);
58+
throw new StateMachineException(ErrorCodes.UnknownState, source.ToString());
6159
}
6260

63-
State targetState = this[target];
61+
StateContainer<TState> targetState = this[target];
6462

6563
if (targetState == null)
6664
{
67-
throw new StateMachineException(ErrorCodes.UnknownState, target);
65+
throw new StateMachineException(ErrorCodes.UnknownState, target.ToString());
6866
}
6967

7068
sourceState.AddArc(targetState);
7169
}
7270

73-
public void AddEnterStateCallback(string targetStateName, StateCallback method)
71+
public void AddEnterStateCallback(TState targetStateName, StateCallback<TState> method)
7472
{
75-
State targetState = this[targetStateName];
73+
StateContainer<TState> targetState = this[targetStateName];
7674

7775
if (targetState == null)
7876
{
79-
throw new StateMachineException(ErrorCodes.UnknownState, targetStateName);
77+
throw new StateMachineException(ErrorCodes.UnknownState, targetStateName.ToString());
8078
}
8179

8280
targetState.AddStateCallback(method, true);
8381
}
8482

85-
public void AddExitStateCallback(string targetStateName, StateCallback method)
83+
public void AddExitStateCallback(TState targetStateName, StateCallback<TState> method)
8684
{
87-
State targetState = this[targetStateName];
85+
StateContainer<TState> targetState = this[targetStateName];
8886

8987
if (targetState == null)
9088
{
91-
throw new StateMachineException(ErrorCodes.UnknownState, targetStateName);
89+
throw new StateMachineException(ErrorCodes.UnknownState, targetStateName.ToString());
9290
}
9391

9492
targetState.AddStateCallback(method, false);
9593
}
9694

97-
public void AddTransitionCallback(string source, string target, ArcCallback method)
95+
public void AddTransitionCallback(TState source, TState target, ArcCallback<TState> method)
9896
{
99-
State s = this[source];
97+
StateContainer<TState> s = this[source];
10098

10199
if (s == null)
102100
{
103-
throw new StateMachineException(ErrorCodes.UnknownState, source);
101+
throw new StateMachineException(ErrorCodes.UnknownState, source.ToString());
104102
}
105103

106104
s.AddTransitArcCallback(target, method);
107105
}
108106

109-
public void GoToState(string stateName)
107+
public void GoToState(TState stateName)
110108
{
111-
if (Transiting)
109+
try
112110
{
113-
if (_postedState.Length != 0)
111+
if (Transiting)
114112
{
115-
throw new StateMachineException(ErrorCodes.PostedStateAreadySet, string.Empty);
113+
return;
116114
}
117115

118-
_postedState = stateName;
119-
return;
120-
}
121-
122-
try
123-
{
124-
PostedStateRestart:
125116
Transiting = true;
117+
StateContainer<TState> target = this[stateName];
126118

127-
State target = this[stateName];
119+
if (target == null)
120+
{
121+
throw new StateMachineException(ErrorCodes.UnknownState, stateName.ToString());
122+
}
128123

129-
if (target == null)
130-
{
131-
throw new StateMachineException(ErrorCodes.UnknownState, stateName);
132-
}
124+
if (CurrentState != null)
125+
{
126+
Transition<TState> arc = CurrentState[target];
133127

134-
if (CurrentState != null)
128+
if (arc == null)
135129
{
136-
Arc arc = CurrentState[target];
137-
138-
if (arc == null)
139-
{
140-
throw new StateMachineException(ErrorCodes.InvalidTransition, StateMachineException.MakeArcName(CurrentState.Name, target.Name));
141-
}
142-
143-
CurrentState.CallExitCallbacks();
144-
arc.CallTransitionCallbacks();
130+
throw new StateMachineException(ErrorCodes.InvalidTransition, StateMachineException.MakeArcName(CurrentState.Name, target.Name));
145131
}
146132

147-
CurrentState = target;
148-
target.CallEnterCallbacks();
149-
Transiting = false;
133+
CurrentState.CallExitCallbacks();
134+
arc.CallTransitionCallbacks();
135+
}
150136

151-
if (_postedState.Length != 0)
152-
{
153-
stateName = _postedState;
154-
_postedState = string.Empty;
155-
goto PostedStateRestart; //tail recursion
156-
}
137+
CurrentState = target;
138+
target.CallEnterCallbacks();
139+
Transiting = false;
157140
}
158141
catch
159142
{

0 commit comments

Comments
 (0)