Skip to content

Commit

Permalink
Clean up the visitor for transitions
Browse files Browse the repository at this point in the history
  • Loading branch information
David Mesquita-Morris committed Mar 28, 2015
1 parent 19bfc24 commit 78df37b
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 53 deletions.
80 changes: 47 additions & 33 deletions src/Bootstrap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,59 +9,65 @@
using System.Linq;

namespace Steelbreeze.Behavior.StateMachines {
/// <summary>
/// Holds the behaviour for a given element used within the bootstrapping process
/// </summary>
/// <typeparam name="TInstance">The type of the state machine instance.</typeparam>
internal class ElementBehaviour<TInstance> where TInstance : class, IActiveStateConfiguration<TInstance> {
internal Action<Object, TInstance, Boolean> Leave;
internal Action<Object, TInstance, Boolean> BeginEnter;
internal Action<Object, TInstance, Boolean> EndEnter;
internal Action<Object, TInstance, Boolean> Enter;
}

/// <summary>
/// Bootstraps a state machine model.
/// </summary>
/// <typeparam name="TInstance">The type of the state machine instnce.</typeparam>
/// <remarks>Bootstrapping a state machine model pre-determines all operations and evaluations required when traversing a transition; the results are then cached within the transition.</remarks>
internal class Bootstrap<TInstance> : Visitor<TInstance, Boolean> where TInstance : class, IActiveStateConfiguration<TInstance> {
private class Actions {
internal Action<Object, TInstance, Boolean> Leave;
internal Action<Object, TInstance, Boolean> BeginEnter;
internal Action<Object, TInstance, Boolean> EndEnter;
internal Action<Object, TInstance, Boolean> Enter;
}
private static BootstrapTransitions<TInstance> bootstrapTransitions = new BootstrapTransitions<TInstance> ();

/// <summary>
/// Cache of the behaviour required within the state machine model.
/// </summary>
private Dictionary<Element<TInstance>, Actions> behaviour;
private Dictionary<Element<TInstance>, ElementBehaviour<TInstance>> behaviour;

/// <summary>
/// Returns the behaviour for a given element within the state machine model.
/// </summary>
/// <param name="element">The element to return the behaviour for.</param>
/// <returns>The state machine behaviour for a given model element.</returns>
private Actions Behaviour (Element<TInstance> element) {
Actions result = null;
private ElementBehaviour<TInstance> ElementBehaviour (Element<TInstance> element) {
ElementBehaviour<TInstance> result = null;

if (!behaviour.TryGetValue (element, out result))
behaviour.Add (element, result = new Actions ());
behaviour.Add (element, result = new ElementBehaviour<TInstance> ());

return result;
}

public override void VisitElement (Element<TInstance> element, Boolean deepHistoryAbove) {
#if DEBUG
Behaviour (element).Leave += (message, instance, history) => Console.WriteLine ("{0} leave {1}", instance, element);
Behaviour (element).BeginEnter += (message, instance, history) => Console.WriteLine ("{0} enter {1}", instance, element);
ElementBehaviour (element).Leave += (message, instance, history) => Console.WriteLine ("{0} leave {1}", instance, element);
ElementBehaviour (element).BeginEnter += (message, instance, history) => Console.WriteLine ("{0} enter {1}", instance, element);
#endif
}

public override void VisitRegion (Region<TInstance> region, Boolean deepHistoryAbove) {
foreach (var vertex in region.Vertices)
vertex.Accept (this, deepHistoryAbove || (region.Initial != null && region.Initial.Kind == PseudoStateKind.DeepHistory));

Behaviour (region).Leave += (message, instance, history) => {
ElementBehaviour (region).Leave += (message, instance, history) => {
State<TInstance> current = instance[ region ];
if (Behaviour (current).Leave != null) {
Behaviour (current).Leave (message, instance, history);
if (ElementBehaviour (current).Leave != null) {
ElementBehaviour (current).Leave (message, instance, history);
}
};

if (deepHistoryAbove || region.Initial == null || region.Initial.IsHistory) {
Behaviour (region).EndEnter += (message, instance, history) => {
ElementBehaviour (region).EndEnter += (message, instance, history) => {
Vertex<TInstance> initial = region.Initial;
if (history || region.Initial.IsHistory) {
Expand All @@ -71,63 +77,71 @@ public override void VisitRegion (Region<TInstance> region, Boolean deepHistoryA
initial = region.Initial;
}
Behaviour (initial).Enter (message, instance, history || region.Initial.Kind == PseudoStateKind.DeepHistory);
ElementBehaviour (initial).Enter (message, instance, history || region.Initial.Kind == PseudoStateKind.DeepHistory);
};
} else
Behaviour (region).EndEnter += Behaviour (region.Initial).Enter;
ElementBehaviour (region).EndEnter += ElementBehaviour (region.Initial).Enter;

this.VisitElement (region, deepHistoryAbove);

Behaviour (region).Enter = Behaviour (region).BeginEnter + Behaviour (region).EndEnter;
ElementBehaviour (region).Enter = ElementBehaviour (region).BeginEnter + ElementBehaviour (region).EndEnter;
}

public override void VisitVertex (Vertex<TInstance> vertex, Boolean deepHistoryAbove) {
this.VisitElement (vertex, deepHistoryAbove);

Behaviour (vertex).EndEnter += vertex.Completion;
Behaviour (vertex).Enter = Behaviour (vertex).BeginEnter + Behaviour (vertex).EndEnter;
ElementBehaviour (vertex).EndEnter += vertex.Completion;
ElementBehaviour (vertex).Enter = ElementBehaviour (vertex).BeginEnter + ElementBehaviour (vertex).EndEnter;
}

public override void VisitPseudoState (PseudoState<TInstance> pseudoState, Boolean deepHistoryAbove) {
this.VisitVertex (pseudoState, deepHistoryAbove);

if (pseudoState.Kind == PseudoStateKind.Terminate)
Behaviour (pseudoState).Enter += (message, instance, history) => instance.IsTerminated = true;
ElementBehaviour (pseudoState).Enter += (message, instance, history) => instance.IsTerminated = true;
}

public override void VisitState (State<TInstance> state, Boolean deepHistoryAbove) {
foreach (var region in state.Regions) {
region.Accept (this, deepHistoryAbove);

Behaviour (state).Leave += Behaviour (region).Leave;
Behaviour (state).EndEnter += Behaviour (region).Enter;
ElementBehaviour (state).Leave += ElementBehaviour (region).Leave;
ElementBehaviour (state).EndEnter += ElementBehaviour (region).Enter;
}

this.VisitVertex (state, deepHistoryAbove);

if (state.exit != null)
Behaviour (state).Leave += state.OnExit;
ElementBehaviour (state).Leave += state.OnExit;

if (state.entry != null)
Behaviour (state).BeginEnter += state.OnEntry;
ElementBehaviour (state).BeginEnter += state.OnEntry;

Behaviour (state).BeginEnter += (message, instance, history) => {
ElementBehaviour (state).BeginEnter += (message, instance, history) => {
if (state.Region != null)
instance[ state.Region ] = state;
};

Behaviour (state).Enter = Behaviour (state).BeginEnter + Behaviour (state).EndEnter;
ElementBehaviour (state).Enter = ElementBehaviour (state).BeginEnter + ElementBehaviour (state).EndEnter;
}

public override void VisitStateMachine (StateMachine<TInstance> stateMachine, bool param) {
behaviour = new Dictionary<Element<TInstance>, Actions> ();
public override void VisitStateMachine (StateMachine<TInstance> stateMachine, Boolean param) {
behaviour = new Dictionary<Element<TInstance>, ElementBehaviour<TInstance>> ();

base.VisitStateMachine (stateMachine, param);

stateMachine.initialise = Behaviour (stateMachine).Enter;
stateMachine.initialise = ElementBehaviour (stateMachine).Enter;

stateMachine.Accept (bootstrapTransitions, ElementBehaviour); ;
}
}

public override void VisitTransition (Transition<TInstance> transition, Boolean deepHistoryAbove) {
/// <summary>
/// Bootstraps the transitions after all elements have been bootstrapped
/// </summary>
/// <typeparam name="TInstance">The type of the state machine instance</typeparam>
internal class BootstrapTransitions<TInstance> : Visitor<TInstance, Func<Element<TInstance>, ElementBehaviour<TInstance>>> where TInstance : class, IActiveStateConfiguration<TInstance> {
public override void VisitTransition (Transition<TInstance> transition, Func<Element<TInstance>, ElementBehaviour<TInstance>> Behaviour) {
// reset the traverse operation to cater for re-initialisation
transition.Traverse = null;

Expand Down Expand Up @@ -181,7 +195,7 @@ public override void VisitTransition (Transition<TInstance> transition, Boolean

transition.Traverse += Behaviour (element).BeginEnter;

if (element is State<TInstance>) {
if (element is State<TInstance>) { // TODO: find a way to remove the is/as code
var state = element as State<TInstance>;

if (state.IsOrthogonal) {
Expand Down
12 changes: 12 additions & 0 deletions src/Transition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -196,5 +196,17 @@ public Transition<TInstance> Effect (params Action[] behavior) {
public void OnEffect (Object message, TInstance instance, Boolean history) { // TODO: sort out protection models
this.effect (message, instance);
}

/// <summary>
/// Accepts a visitor
/// </summary>
/// <param name="visitor">The visitor to visit.</param>
/// <param name="param">A parameter passed to the visitor when visiting the transition.</param>
/// <remarks>
/// A visitor will walk the state machine model from this element to all child elements including transitions calling the approritate visit method on the visitor.
/// </remarks>
public void Accept<TParam> (Visitor<TInstance, TParam> visitor, TParam param) {
visitor.VisitTransition (this, param);
}
}
}
23 changes: 3 additions & 20 deletions src/Visitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ public virtual void VisitRegion (Region<TInstance> region, TParam param) {
/// <param name="param">The parameter passed to the visitor.</param>
public virtual void VisitVertex (Vertex<TInstance> vertex, TParam param) {
this.VisitElement (vertex, param);

foreach (var transition in vertex.Transitions)
transition.Accept (this, param);
}

/// <summary>
Expand Down Expand Up @@ -78,26 +81,6 @@ public virtual void VisitFinalState (FinalState<TInstance> finalState, TParam pa
/// <param name="param">The parameter passed to the visitor.</param>
public virtual void VisitStateMachine (StateMachine<TInstance> stateMachine, TParam param) {
this.VisitState (stateMachine, param);

this.VisitTransition (stateMachine as Vertex<TInstance>, param);
}

private void VisitTransition (Region<TInstance> region, TParam param) {
foreach (var vertex in region.Vertices)
this.VisitTransition (vertex, param);
}

private void VisitTransition (Vertex<TInstance> vertex, TParam param) {
foreach (var transition in vertex.Transitions)
this.VisitTransition (transition, param);

if (vertex is State<TInstance>) {
var state = vertex as State<TInstance>;

if (state.IsComposite)
foreach (var region in state.Regions)
this.VisitTransition (region, param);
}
}

/// <summary>
Expand Down

0 comments on commit 78df37b

Please sign in to comment.