Skip to content

Commit

Permalink
Simplified provided context classes
Browse files Browse the repository at this point in the history
The XContext and DictionaryContext classes provide now have simpler
non-templatised version available
  • Loading branch information
David Mesquita-Morris committed Jan 5, 2015
1 parent bd3abc8 commit e847423
Show file tree
Hide file tree
Showing 21 changed files with 134 additions and 122 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Welcome to state.cs

The current stable release is 5.1.0.
The current stable release is 5.1.1.

If you're using state.cs I'd love to hear about it; please e-mail me at [email protected]

Expand Down
38 changes: 14 additions & 24 deletions examples/Player.cs
Original file line number Diff line number Diff line change
@@ -1,23 +1,13 @@
/* state v5 finite state machine library
* Copyright (c) 2014 Steelbreeze Limited
/* State v5 finite state machine library
* http://www.steelbreeze.net/state.cs
* Copyright (c) 2014-5 Steelbreeze Limited
* Licensed under MIT and GPL v3 licences
*/
using System;
using System.Xml.Linq;

namespace Steelbreeze.Behavior.StateMachines.Examples
{
/// <summary>
/// Basic example of state machine state implementation
/// </summary>
public sealed class Context : XContext<Context> {
public Context( String name ) : base( new XAttribute( "name", name ) ) { }

public override string ToString() {
return this.XElement.Attribute( "name" ).Value;
}
}

/// <summary>
/// A controller for a simple cassette player
/// </summary>
Expand All @@ -29,18 +19,18 @@ public class Player
{
static void Main() {
// create the state machine model
var model = new StateMachine<Context>( "player" );
var initial = new PseudoState<Context>( "initial", model, PseudoStateKind.Initial );
var operational = new State<Context>( "operational", model );
var choice = new PseudoState<Context>( "choice", model, PseudoStateKind.Choice );
var final = new FinalState<Context>( "final", model );
var model = new StateMachine<XContext>( "player" );
var initial = new PseudoState<XContext>( "initial", model, PseudoStateKind.Initial );
var operational = new State<XContext>( "operational", model );
var choice = new PseudoState<XContext>( "choice", model, PseudoStateKind.Choice );
var final = new FinalState<XContext>( "final", model );

var history = new PseudoState<Context>( "history", operational, PseudoStateKind.DeepHistory );
var stopped = new State<Context>( "stopped", operational );
var active = new State<Context>( "active", operational ).Entry( EngageHead ).Exit( DisengageHead );
var history = new PseudoState<XContext>( "history", operational, PseudoStateKind.DeepHistory );
var stopped = new State<XContext>( "stopped", operational );
var active = new State<XContext>( "active", operational ).Entry( EngageHead ).Exit( DisengageHead );

var running = new State<Context>( "running", active ).Entry( StartMotor ).Exit( StopMotor );
var paused = new State<Context>( "paused", active );
var running = new State<XContext>( "running", active ).Entry( StartMotor ).Exit( StopMotor );
var paused = new State<XContext>( "paused", active );

// create the transitions between vertices of the model
initial.To( operational ).Effect( DisengageHead, StartMotor );
Expand All @@ -58,7 +48,7 @@ static void Main() {
operational.When<String>( command => command == "current" ).Effect( state => Console.WriteLine( state.XElement ) );

// create an instance of the state machine state
var context = new Context( "example" );
var context = new XContext();

// initialises the state machine state (enters the region for the first time, causing transition from the initial PseudoState)
model.Initialise( context );
Expand Down
10 changes: 8 additions & 2 deletions src/DictionaryContext.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* State v5 finite state machine library
* Copyright (c) 2014 Steelbreeze Limited
* http://www.steelbreeze.net/state.cs
* Copyright (c) 2014-5 Steelbreeze Limited
* Licensed under MIT and GPL v3 licences
*/
using System;
Expand Down Expand Up @@ -40,4 +41,9 @@ Vertex<TContext> IContext<TContext>.this[ Region<TContext> region ] {
}
}
}
}

/// <summary>
/// A simple sample of an object to extend as a base for a state machine context object.
/// </summary>
public class DictionaryContext : DictionaryContext<DictionaryContext> { }
}
3 changes: 2 additions & 1 deletion src/FinalState.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* State v5 finite state machine library
* Copyright (c) 2014 Steelbreeze Limited
* http://www.steelbreeze.net/state.cs
* Copyright (c) 2014-5 Steelbreeze Limited
* Licensed under MIT and GPL v3 licences
*/
using System;
Expand Down
3 changes: 2 additions & 1 deletion src/IContext.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* State v5 finite state machine library
* Copyright (c) 2014 Steelbreeze Limited
* http://www.steelbreeze.net/state.cs
* Copyright (c) 2014-5 Steelbreeze Limited
* Licensed under MIT and GPL v3 licences
*/
using System;
Expand Down
3 changes: 2 additions & 1 deletion src/NamedElement.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* State v5 finite state machine library
* Copyright (c) 2014 Steelbreeze Limited
* http://www.steelbreeze.net/state.cs
* Copyright (c) 2014-5 Steelbreeze Limited
* Licensed under MIT and GPL v3 licences
*/
using System;
Expand Down
3 changes: 2 additions & 1 deletion src/PseudoState.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* State v5 finite state machine library
* Copyright (c) 2014 Steelbreeze Limited
* http://www.steelbreeze.net/state.cs
* Copyright (c) 2014-5 Steelbreeze Limited
* Licensed under MIT and GPL v3 licences
*/
using System;
Expand Down
4 changes: 2 additions & 2 deletions src/PseudoStateKind.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/* State v5 finite state machine library
* Copyright (c) 2014 Steelbreeze Limited
* http://www.steelbreeze.net/state.cs
* Copyright (c) 2014-5 Steelbreeze Limited
* Licensed under MIT and GPL v3 licences
*/

namespace Steelbreeze.Behavior.StateMachines {
/// <summary>
/// Defines the specific semantics of a PseudoState in which it is used.
Expand Down
5 changes: 2 additions & 3 deletions src/Region.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* State v5 finite state machine library
* Copyright (c) 2014 Steelbreeze Limited
* http://www.steelbreeze.net/state.cs
* Copyright (c) 2014-5 Steelbreeze Limited
* Licensed under MIT and GPL v3 licences
*/
using System;
Expand Down Expand Up @@ -76,7 +77,6 @@ public static implicit operator Region<TContext>( State<TContext> state ) {
/// </summary>
public IEnumerable<Vertex<TContext>> Vertices { get { return this.vertices; } }

internal readonly StateMachine<TContext> Root;
internal PseudoState<TContext> Initial = null;

private readonly HashSet<Vertex<TContext>> vertices = new HashSet<Vertex<TContext>>();
Expand All @@ -92,7 +92,6 @@ public Region( String name, StateMachine<TContext> parent )
Trace.Assert( name != null, "Regions must have a name" );
Trace.Assert( parent != null, "Regions must have a parent" );

this.Root = parent;
this.parent = parent;

parent.Add( this );
Expand Down
3 changes: 2 additions & 1 deletion src/State.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* State v5 finite state machine library
* Copyright (c) 2014 Steelbreeze Limited
* http://www.steelbreeze.net/state.cs
* Copyright (c) 2014-5 Steelbreeze Limited
* Licensed under MIT and GPL v3 licences
*/
using System;
Expand Down
7 changes: 6 additions & 1 deletion src/StateMachine.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
/* State v5 finite state machine library
* Copyright (c) 2014 Steelbreeze Limited
* http://www.steelbreeze.net/state.cs
* Copyright (c) 2014-5 Steelbreeze Limited
* Licensed under MIT and GPL v3 licences
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

// TODO: inherit from State (thereby enabling a machine to be used in another region if required)
namespace Steelbreeze.Behavior.StateMachines {
/// <summary>
/// A StateMachine is the root node of a hierarchical state machine model.
Expand Down Expand Up @@ -40,7 +42,10 @@ public sealed class StateMachine<TContext> : StateMachineElement<TContext> where
/// <param name="name">The name of the StateMachine.</param>
public StateMachine( String name )
: base( name, null ) {

Trace.Assert( name != null, "StateMachines must have a name" );

this.Root = this;
}

internal void Add( Region<TContext> region ) {
Expand Down
13 changes: 11 additions & 2 deletions src/StateMachineElement.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* State v5 finite state machine library
* Copyright (c) 2014 Steelbreeze Limited
* http://www.steelbreeze.net/state.cs
* Copyright (c) 2014-5 Steelbreeze Limited
* Licensed under MIT and GPL v3 licences
*/
using System;
Expand All @@ -21,6 +22,11 @@ public abstract class StateMachineElement<TContext> : NamedElement where TContex
/// </summary>
public abstract StateMachineElement<TContext> Parent { get; }

/// <summary>
/// The parent state machine that this element forms a part of.
/// </summary>
public StateMachine<TContext> Root { get; protected set; }

/// <summary>
/// Returns the elements ancestors.
/// </summary>
Expand All @@ -31,7 +37,10 @@ public abstract class StateMachineElement<TContext> : NamedElement where TContex
internal Action<Object, TContext, Boolean> EndEnter;
internal Action<Object, TContext, Boolean> Enter;

internal StateMachineElement( String name, StateMachineElement<TContext> parent ) : base( name, parent ) { }
internal StateMachineElement( String name, StateMachineElement<TContext> parent ) : base( name, parent ) {
if( parent != null )
this.Root = parent.Root;
}

internal void Reset() {
this.Leave = null;
Expand Down
23 changes: 14 additions & 9 deletions src/Transition.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* state v5 finite state machine library
* Copyright (c) 2014 Steelbreeze Limited
/* State v5 finite state machine library
* http://www.steelbreeze.net/state.cs
* Copyright (c) 2014-5 Steelbreeze Limited
* Licensed under MIT and GPL v3 licences
*/
using System;
Expand Down Expand Up @@ -262,28 +263,32 @@ internal void BootstrapTransitions() {

// complex (external) transitions
} else {
int i = 0, l = Math.Min( this.Source.Ancestors.Count(), this.Source.Ancestors.Count() );
var sourceAncestors = this.Source.Ancestors;
var targetAncestors = this.Target.Ancestors;
var sourceAncestorsCount = sourceAncestors.Count();
var targetAncestorsCount = targetAncestors.Count();
int i = 0, l = Math.Min( sourceAncestorsCount, sourceAncestorsCount );

// find the index of the first uncommon ancestor
while( ( i < l ) && this.Source.Ancestors.ElementAt( i ) == this.Target.Ancestors.ElementAt( i ) ) ++i;
while( ( i < l ) && sourceAncestors.ElementAt( i ) == targetAncestors.ElementAt( i ) ) ++i;

// validation rule (not in hte UML spec currently)
Trace.Assert( this.Source.Ancestors.ElementAt( i ) is Region<TContext> == false, "Transitions may not cross sibling orthogonal regions" );
Trace.Assert( sourceAncestors.ElementAt( i ) is Region<TContext> == false, "Transitions may not cross sibling orthogonal regions" );

// leave the first uncommon ancestor
this.Traverse = ( i < this.Source.Ancestors.Count() ? this.Source.Ancestors.ElementAt( i ) : this.Source ).Leave;
this.Traverse = ( i < sourceAncestorsCount ? sourceAncestors.ElementAt( i ) : this.Source ).Leave;

// perform the transition effect
if( this.effect != null )
this.Traverse += this.OnEffect;

// edge case when transitioning to a state in the vertex ancestry
if( i >= this.Target.Ancestors.Count() )
if( i >= targetAncestorsCount )
this.Traverse += this.Target.BeginEnter;

// enter the target ancestry
while( i < this.Target.Ancestors.Count() )
this.Target.Ancestors.ElementAt( i++ ).BootstrapEnter( ref this.Traverse, i < this.Target.Ancestors.Count() ? this.Target.Ancestors.ElementAt( i ) : null );
while( i < targetAncestorsCount )
targetAncestors.ElementAt( i++ ).BootstrapEnter( ref this.Traverse, i < targetAncestorsCount ? targetAncestors.ElementAt( i ) : null );

// trigger cascade
this.Traverse += this.Target.EndEnter;
Expand Down
5 changes: 2 additions & 3 deletions src/Vertex.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* State v5 finite state machine library
* Copyright (c) 2014 Steelbreeze Limited
* http://www.steelbreeze.net/state.cs
* Copyright (c) 2014-5 Steelbreeze Limited
* Licensed under MIT and GPL v3 licences
*/
using System;
Expand All @@ -11,7 +12,6 @@ namespace Steelbreeze.Behavior.StateMachines {
/// <typeparam name="TContext">The type of the state machine instance.</typeparam>
public abstract class Vertex<TContext> : StateMachineElement<TContext> where TContext : IContext<TContext> {
internal readonly Region<TContext> Region;
internal readonly StateMachine<TContext> Root;
internal Boolean IsFinal { get { return this.transitions == null; } }

private Transition<TContext>[] transitions; // trading off model building performance for runtime performance
Expand All @@ -24,7 +24,6 @@ public abstract class Vertex<TContext> : StateMachineElement<TContext> where TCo

internal Vertex( String name, Region<TContext> parent, Func<Transition<TContext>[], Object, TContext, Transition<TContext>> selector )
: base( name, parent ) {
this.Root = parent.Root;
this.Region = parent;
this.selector = selector;

Expand Down
13 changes: 9 additions & 4 deletions src/XContext.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/* State v5 finite state machine library
* Copyright (c) 2014 Steelbreeze Limited
* http://www.steelbreeze.net/state.cs
* Copyright (c) 2014-5 Steelbreeze Limited
* Licensed under MIT and GPL v3 licences
*/
using System;
*/using System;
using System.Linq;
using System.Xml.Linq;

Expand All @@ -29,7 +29,7 @@ public abstract class XContext<TContext> : IContext<TContext> where TContext : I
/// Creates a new instance of the XmlContext class.
/// </summary>
/// <param name="content">Any additional XML structure that you may need under the root element.</param>
public XContext( params object[] content ){
public XContext( params object[] content ) {
this.XElement = new XElement( "stateMachineContext", content );

this.XElement.Add( new XAttribute( "terminated", false ) );
Expand Down Expand Up @@ -90,4 +90,9 @@ private XElement this[ Region<TContext> region ] {
}
}
}

/// <summary>
/// A sample of an object to extend as a base for a state machine context objects based on an XElement.
/// </summary>
public class XContext : XContext<XContext> { }
}
23 changes: 12 additions & 11 deletions tests/History/Shallow.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* state v5 finite state machine library
* Copyright (c) 2014 Steelbreeze Limited
/* State v5 finite state machine library
* http://www.steelbreeze.net/state.cs
* Copyright (c) 2014-5 Steelbreeze Limited
* Licensed under MIT and GPL v3 licences
*/
using System;
Expand All @@ -8,24 +9,24 @@
namespace Steelbreeze.Behavior.StateMachines.Tests.History {
public class Shallow {
public static void Test() {
var model = new StateMachine<TestState>( "history" );
var model = new StateMachine<DictionaryContext>( "history" );

var initial = new PseudoState<TestState>( "initial", model );
var shallow = new State<TestState>( "shallow", model );
var deep = new State<TestState>( "deep", model );
var final = new FinalState<TestState>( "final", model );
var initial = new PseudoState<DictionaryContext>( "initial", model );
var shallow = new State<DictionaryContext>( "shallow", model );
var deep = new State<DictionaryContext>( "deep", model );
var final = new FinalState<DictionaryContext>( "final", model );

var s1 = new State<TestState>( "s1", shallow );
var s2 = new State<TestState>( "s2", shallow );
var s1 = new State<DictionaryContext>( "s1", shallow );
var s2 = new State<DictionaryContext>( "s2", shallow );

initial.To( shallow );
new PseudoState<TestState>( "shallow", shallow, PseudoStateKind.ShallowHistory ).To( s1 );
new PseudoState<DictionaryContext>( "shallow", shallow, PseudoStateKind.ShallowHistory ).To( s1 );
s1.To( s2 ).When<String>( c => c == "move" );
shallow.To( deep ).When<String>( c => c == "go deep" );
deep.To( shallow ).When<String>( c => c == "go shallow" );
s2.To( final ).When<String>( c => c == "end" );

var instance = new TestState();
var instance = new DictionaryContext();

model.Initialise( instance );

Expand Down
5 changes: 3 additions & 2 deletions tests/Program.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* state v5 finite state machine library
* Copyright (c) 2014 Steelbreeze Limited
/* State v5 finite state machine library
* http://www.steelbreeze.net/state.cs
* Copyright (c) 2014-5 Steelbreeze Limited
* Licensed under MIT and GPL v3 licences
*/
using System;
Expand Down
13 changes: 0 additions & 13 deletions tests/TestState.cs

This file was deleted.

Loading

0 comments on commit e847423

Please sign in to comment.