A C++ library for YAML-configured finite state machines. Because your spaghetti code deserves better.
- YAML-based configuration: Define state machines using human-readable YAML files
- Event-driven architecture: React to events with flexible callback system
- Type-safe: Modern C++23 with strong type checking
- Extensible: Easy to extend with custom states and transitions
- Well-tested: Comprehensive test suite using Google Test
- Cross-platform: Works on Linux, macOS, and Windows
FSMConfig provides full Docker integration for consistent development and CI/CD environments.
DevContainer (Recommended for Development):
# Open project in VSCode DevContainer
F1 → Dev Containers: Reopen in ContainerDocker for CI/Testing:
# Build Docker image
docker build -t fsmconfig:ci .
# Run tests in Docker
docker run --rm fsmconfig:ci bash -c "
mkdir build && cd build && \
cmake -DCMAKE_BUILD_TYPE=Release .. && \
cmake --build . -j\$(nproc) && \
ctest --output-on-failure
"| Approach | Use Case | Dockerfile |
|---|---|---|
| DevContainer | Interactive development with VSCode | .devcontainer/Dockerfile |
| CI/CD | Automated testing and builds | Dockerfile |
For complete Docker documentation, see DOCKER.md.
- CMake 3.15 or higher
- C++23 compatible compiler (GCC 11+, Clang 12+, MSVC 19.28+)
- yaml-cpp library
- Google Test (for building tests)
# Configure project
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
# Build project
cmake --build . -j$(nproc)
# Run tests
ctest --output-on-failure# Build Docker image
docker build -t fsmconfig:ci .
# Build project in Docker
docker run --rm -v $(pwd):/workspace -w /workspace fsmconfig:ci bash -c "
mkdir -p build && cd build && \
cmake .. && \
cmake --build . -j\$(nproc)
"
# Run tests in Docker
docker run --rm -v $(pwd):/workspace -w /workspace/build fsmconfig:ci ctest --output-on-failure# Debug build (with debug symbols)
cmake .. -DCMAKE_BUILD_TYPE=Debug
# Release build (optimized)
cmake .. -DCMAKE_BUILD_TYPE=Release
# Disable tests
cmake .. -DBUILD_TESTS=OFF
# Disable examples
cmake .. -DBUILD_EXAMPLES=OFF- Operating System: Linux, macOS, or Windows
- Compiler: GCC 14+, Clang 17+, or MSVC 19.35+
- Build System: CMake 3.15+
- Libraries: yaml-cpp, Google Test
- IDE: Visual Studio Code with C/C++ and CMake Tools extensions
- Debugger: GDB (Linux/macOS) or Visual Studio Debugger (Windows)
- Code Analysis: clang-tidy, clang-format
- Version Control: Git
The easiest way to set up a development environment is using VSCode DevContainer:
- Install Docker Desktop
- Install Visual Studio Code
- Install Dev Containers extension
- Open the project in VSCode
- Press
F1and selectDev Containers: Reopen in Container
The DevContainer automatically includes:
- GCC 14 and CMake
- yaml-cpp and Google Test
- VSCode extensions (C/C++, CMake Tools, clang-format)
- Development tools (gdb, valgrind, clang-tidy)
# Configure (Debug mode)
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Debug
# Build
cmake --build . -j$(nproc)
# Run tests
ctest --output-on-failure
# Run specific test
./tests/test_state_machine
# Format code
clang-format -i src/**/*.cpp include/**/*.hppCreate a YAML configuration file (config.yaml):
states:
idle:
on_enter: on_idle_enter
on_exit: on_idle_exit
active:
on_enter: on_active_enter
on_exit: on_active_exit
paused:
on_enter: on_paused_enter
on_exit: on_paused_exit
transitions:
- from: idle
to: active
event: start
- from: active
to: paused
event: pause
- from: paused
to: active
event: resume
- from: paused
to: idle
event: stopUse the library in your C++ code:
#include <fsmconfig/state_machine.hpp>
#include <iostream>
class App {
public:
void run() {
// Create state machine from YAML config file
fsmconfig::StateMachine fsm("config.yaml");
// Register callbacks (names must match YAML on_enter/on_exit)
fsm.registerStateCallback("idle", "on_enter", &App::onIdleEnter, this);
fsm.registerStateCallback("idle", "on_exit", &App::onIdleExit, this);
fsm.registerStateCallback("active", "on_enter", &App::onActiveEnter, this);
fsm.registerStateCallback("active", "on_exit", &App::onActiveExit, this);
// Start the state machine (enters initial state)
fsm.start();
// Trigger events
fsm.triggerEvent("start"); // idle -> active
fsm.triggerEvent("pause"); // active -> paused
fsm.triggerEvent("resume"); // paused -> active
fsm.triggerEvent("stop"); // paused -> idle
fsm.stop();
}
private:
void onIdleEnter() { std::cout << "-> idle\n"; }
void onIdleExit() { std::cout << "<- idle\n"; }
void onActiveEnter() { std::cout << "-> active\n"; }
void onActiveExit() { std::cout << "<- active\n"; }
};
int main() {
App app;
app.run();
return 0;
}For more examples, see the examples/ directory.
The project uses Google Test for unit testing.
# Run all tests
cd build && ctest --output-on-failure
# Run specific test
ctest -R test_name --output-on-failure
# Run tests with verbose output
ctest --verbose
# Run test directly
./build/tests/test_state_machineContributions are welcome! Please follow these guidelines:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Add tests for new functionality
- Ensure all tests pass (
ctest --output-on-failure) - Format your code (
clang-format -i src/**/*.cpp include/**/*.hpp) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- yaml-cpp for YAML parsing
- Google Test for testing framework
- CMake for build system
Version: 0.1.0 | C++ Standard: C++23 | CMake: 3.15+