Skip to content

tkem/fsmlite

Repository files navigation

fsmlite CI build status Documentation build status Test coverage License

fsmlite is a lightweight finite state machine framework for C++17. It is based on concepts first presented by David Abrahams and Aleksey Gurtovoy in C++ Template Metaprogramming, with additional ideas taken liberally from Boost's Meta State Machine (MSM), and slightly "modernized" to make use of features more recently introduced to the C++ standard.

The canonical CD player example (with CD-Text and auto-play support!) therefore looks somewhat like this:

#include "fsmlite.h"

#include <string>

class player: public fsmlite::fsm<player> {
    // grant base class access to private transition_table
    friend class fsmlite::fsm<player>;

    std::string cd_title;
    bool autoplay = false;

public:
    enum states { Stopped, Open, Empty, Playing, Paused };

    player(state_type init_state = Empty) : fsm(init_state) { }

    void set_autoplay(bool f) { autoplay = f; }

    bool is_autoplay() const { return autoplay; }

    const std::string& get_cd_title() const { return cd_title; }

    struct play {};
    struct open_close {};
    struct cd_detected {
        std::string title;
        bool bad() const { return title.empty(); }
    };
    struct stop {};
    struct pause {};

private:
    void start_playback();
    void start_autoplay(const cd_detected& cd);
    void open_drawer();
    void close_drawer();
    void store_cd_info(const cd_detected& cd);
    void stop_playback();
    void pause_playback();
    void resume_playback();
    void stop_and_open();

private:
    using m = player;  // for brevity

    using transition_table = table<
//       Start    Event        Target   Action              Guard (optional)
//  ----+--------+------------+--------+-------------------+-----------------+-
    row< Stopped, play,        Playing, &m::start_playback                    >,
    row< Stopped, open_close,  Open,    &m::open_drawer                       >,
    row< Open,    open_close,  Empty,   &m::close_drawer                      >,
    row< Empty,   open_close,  Open,    &m::open_drawer                       >,
    row< Empty,   cd_detected, Open,    &m::open_drawer,    &cd_detected::bad >,
    row< Empty,   cd_detected, Playing, &m::start_autoplay, &m::is_autoplay   >,
    row< Empty,   cd_detected, Stopped, &m::store_cd_info   /* fallback */    >,
    row< Playing, stop,        Stopped, &m::stop_playback                     >,
    row< Playing, pause,       Paused,  &m::pause_playback                    >,
    row< Playing, open_close,  Open,    &m::stop_and_open                     >,
    row< Paused,  play,        Playing, &m::resume_playback                   >,
    row< Paused,  stop,        Stopped, &m::stop_playback                     >,
    row< Paused,  open_close,  Open,    &m::stop_and_open                     >
//  ----+--------+------------+--------+-------------------+-----------------+-
    >;
};

player p;                                       // p.current_state() == player::Empty
p.process_event(player::open_close());          // p.current_state() == player::Open
p.process_event(player::open_close());          // p.current_state() == player::Empty
p.process_event(player::cd_detected{"Help!"});  // p.current_state() == player::Stopped
p.process_event(player::play());                // p.current_state() == player::Playing
p.process_event(player::pause());               // p.current_state() == player::Paused

Basic Documentation is available, but please also have a look at the unit tests for example usage.

License

Copyright (c) 2015-2025 Thomas Kemmer

Licensed under the MIT License (MIT).

About

Lightweight finite state machine framework for C++17

Resources

License

Security policy

Stars

Watchers

Forks