All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.myire.util.FiniteStateMachine Maven / Gradle / Ivy

/*
 * Copyright 2009, 2016 Peter Franzen. All rights reserved.
 *
 * Licensed under the Apache License v2.0: http://www.apache.org/licenses/LICENSE-2.0
 */
package org.myire.util;

import java.util.function.BiFunction;
import static java.util.Objects.requireNonNull;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe;


/**
 * A Finite State Machine is defined by
 *
    *
  • a finite set of possible states, {@code S}
  • *
  • a initial state {@code s0}, which is a member of {@code S}
  • *
  • a finite set of recognized input symbols {@code I}, called the input alphabet
  • *
  • a finite set of output symbols {@code O}, called the output alphabet
  • *
  • a state transition function (also called the next function) {@code T: S x I -> S} that * maps pairs of state and input symbol to states
  • *
  • an output function {@code G: S x I -> O} that maps pairs of state and input symbol to output * symbols
  • *
* This implementation is a Mealy machine, meaning that the output is determined both by its * current state and the current input (as opposed to a Moore machine whose output is * determined solely by the current state). *

* The concept of final (or accepting) states is not supported by this implementation. Users can * however easily add this by comparing the FSM's current state to an externally defined set of * final states when there is no more input. *

* Whether or not {@code null} is valid state or a valid symbol in the input and output alphabets is * a property of the next and output functions. The FSM itself puts no restrictions on using * {@code null}. *

* The possible states, input alphabet, and output alphabet are all parametrized types. There are * no restrictions on these types, but the fact that that the sets are finite may imply that using * {@code Enum} types is a good choice. *

* Instances of this class are not safe for use by multiple threads without external * synchronization. * * @param The type that defines the set of possible states for the FSM. * @param The type that defines the input alphabet for the FSM. * @param The type that defines the output alphabet. * * @author Peter Franzen */ @NotThreadSafe public class FiniteStateMachine { private final S fInitialState; private S fCurrentState; private final BiFunction fNextFunction; private final BiFunction fOutputFunction; /** * Create a new {@code FiniteStateMachine}. * * @param pInitialState The FSM's initial state. * @param pNextFunction The FSM's next function. * @param pOutputFunction The FSM's output function. * * @throws NullPointerException if any of the function parameters is null. */ public FiniteStateMachine( @Nullable S pInitialState, @Nonnull BiFunction pNextFunction, @Nonnull BiFunction pOutputFunction) { fInitialState = pInitialState; fCurrentState = pInitialState; fNextFunction = requireNonNull(pNextFunction); fOutputFunction = requireNonNull(pOutputFunction); } /** * Get the current state of the FSM. * * @return The current state of the FSM. */ @Nullable public S getCurrentState() { return fCurrentState; } /** * Consume an input symbol and emit the result of the output function. The FSM will be * transitioned into the appropriate state as defined by the state transition function. The * new current state can be retrieved by calling {@link #getCurrentState()}. * * @param pInput The input symbol. * * @return The result of the output function. */ @Nullable public O consumeAndEmit(@Nullable I pInput) { S aNextState = fNextFunction.apply(fCurrentState, pInput); O aOutput = fOutputFunction.apply(fCurrentState, pInput); fCurrentState = aNextState; return aOutput; } /** * Reset the FSM by setting its current state to the initial state. This is not a state * transition; neither the next function nor the output function will be called, and no output * will be emitted. */ public void reset() { fCurrentState = fInitialState; } }