/// <summary> /// Convert the builder into an immutable state machinee. /// </summary> /// <returns>Immutable state machine.</returns> /// <exception cref="InvalidOperationException">Thrown when there is no registered initial state.<br/> /// Or when there are no registered states.<br/> /// Or when a transition refers to a non-registered state.</exception> public StateMachine <TState, TEvent, TParameter> Build() { if (!hasInitialState) { throw new InvalidOperationException("The state machine builder doesn't have registered an initial state."); } if (this.states.Count == 0) { throw new InvalidOperationException("The state machine builder doesn't have registered any state."); } Dictionary <TState, int> statesMap = new Dictionary <TState, int>(); int i = 0; foreach (KeyValuePair <TState, StateBuilder <TState, TEvent, TParameter> > kv in this.states) { statesMap.Add(kv.Key, i++); } List <State <TState, TEvent> > states = new List <State <TState, TEvent> >(); ListSlot <Transition <TState, TEvent> > transitions = new ListSlot <Transition <TState, TEvent> >(new List <Transition <TState, TEvent> >()); // TODO: Use deconstruction pattern when upload to .Net Standard 2.1 foreach (KeyValuePair <TState, StateBuilder <TState, TEvent, TParameter> > kv in this.states) { states.Add(kv.Value.ToState(kv.Key, transitions, statesMap)); } return(new StateMachine <TState, TEvent, TParameter>(initialState.TryGetStateIndex(statesMap), states, transitions.Extract())); }
internal State <TState, TEvent> ToState(TState state, ListSlot <Transition <TState, TEvent> > transitions, Dictionary <TState, int> statesMap) { Dictionary <TEvent, int> trans = new Dictionary <TEvent, int>(); // TODO: Use deconstruction pattern when upload to .Net Standard 2.1 foreach (KeyValuePair <TEvent, TransitionBuilder <TState, TEvent, TParameter> > kv in this.transitions) { int slot = transitions.Reserve(); trans.Add(kv.Key, slot); if (kv.Value is null) { transitions.Store(new Transition <TState, TEvent>(-1, null, (0, 0)), slot); } else { transitions.Store(kv.Value.ToTransition(transitions, statesMap, State), slot); } } return(new State <TState, TEvent>( state, Helper.Combine(ref onEntry, ref onEntryWithParameter), Helper.Combine(ref onExit, ref onExitWithParameter), Helper.Combine(ref onUpdate, ref onUpdateWithParameter), trans )); }
internal override Transition <TState, TEvent> ToTransition(ListSlot <Transition <TState, TEvent> > transitions, Dictionary <TState, int> statesMap, TState currentState) { if (slaves == null) { return(new Transition <TState, TEvent>(GetGoto(statesMap, currentState), GetDo(), (0, 0), guard)); } (int from, int to)range = transitions.Reserve(slaves.Count); int i = range.from; foreach (SlaveTransitionBuilder <TState, TEvent, TParameter, SlaveTransitionBuilder <TState, TEvent, TParameter, TParent> > slave in slaves) { transitions.Store(slave.ToTransition(transitions, statesMap, currentState), i); i++; } Debug.Assert(i == range.to); return(new Transition <TState, TEvent>(GetGoto(statesMap, currentState), GetDo(), range, guard)); }
internal abstract Transition <TState, TEvent> ToTransition(ListSlot <Transition <TState, TEvent> > transitions, Dictionary <TState, int> statesMap, TState currentState);