From 00b8595df5611b838722df54cf138ae39f677148 Mon Sep 17 00:00:00 2001 From: Pavel Guzenfeld Date: Mon, 1 Jun 2026 01:23:29 +0300 Subject: [PATCH 1/9] docs: document API and behavior changes since v1.1.13 - CHANGELOG: new entry covering flush_queue, clear_defer, deps policy, min-size default flip, and other behavior changes since v1.1.13 - overview: document config macros (min-size opt-in, exceptions, default- constructible deps) and the sizeof(sm) behavior change (#249) - user_guide: add sm::flush_queue() (#456) and sml::deps policy (#437) - tutorial: document defer/clear_defer (#643) and flush_queue usage - faq: seed with on_entry<_> multi-TU limitation (#565) and operator, two-MFP limitation + wrap() workaround (#389) make_action (#629) intentionally omitted; it ships with open PR #706. --- doc/CHANGELOG.md | 23 +++++++++++++++++++++++ doc/faq.md | 31 +++++++++++++++++++++++++++++++ doc/overview.md | 12 +++++++++++- doc/tutorial.md | 25 +++++++++++++++++++++++++ doc/user_guide.md | 6 ++++++ 5 files changed, 96 insertions(+), 1 deletion(-) diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index 99402046..817398a3 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -1,3 +1,26 @@ +## [Unreleased] - since 1.1.13 +- **Additions** + - `sm::flush_queue()` — drain pending queued events from async handlers (#456) + - `sml::clear_defer` action — discard deferred events from a transition (#643) + - `sml::deps` policy — explicit pool dependencies for generic-lambda actions/guards (#437) + +- **Behavior changes** + - Empty-SM min-size trick is now OFF by default on GCC/Clang (it was UB at `-O2`); + opt back in with `BOOST_SML_CFG_ENABLE_MIN_SIZE`. `sizeof(sm)` for an empty SM may change (#249) + - `any`/`_` wildcard no longer fires when a composable sub-SM has terminated (#622) + - Events raised via `process(E{})` are now storable in the process queue (#580) + - Guard taking `const State&` now sees live pool state instead of a stale copy (#530) + - Sub-SM defer queue is cleared when its composite state is re-entered (#253) + +- **Bug Fixes** + - Template-depth, `-Wshadow`, `-Wextra-semi`, UBSan, final-class, null-deref, + double-pop, reserved-identifier and related fixes — see full list: + - https://github.com/boost-ext/sml/compare/v1.1.13...master + +- **Documented limitations** + - `on_entry<_>` multi-TU linker limitation and dispatch priority (#565) + - `operator,` with two raw member-function-pointer actions; `wrap()` workaround (#389) + ## [1.1.13] - 2025-12-01 - Changes - https://github.com/boost-ext/sml/compare/v1.1.12...v1.1.13 diff --git a/doc/faq.md b/doc/faq.md index e69de29b..268d0b7d 100644 --- a/doc/faq.md +++ b/doc/faq.md @@ -0,0 +1,31 @@ +## FAQ + +### Limitations + +#### `on_entry<_>` across translation units + +When `on_entry<_>` (the wildcard entry handler) is defined in one translation unit +while the `initial`-event specialization is left undefined, the linker reports an +undefined reference. Make sure the entry handler is fully defined where it is used. + +Dispatch priority: a specific `on_entry` handler takes priority over the +`on_entry<_>` wildcard. The wildcard fires only when no specific handler matches the +event used to enter the state. + +```cpp +// on_entry fires when entering via e1 (specific handler wins) +// on_entry<_> fires when entering via any other event (no specific handler) +``` + +#### `operator,` with two raw member-function-pointer actions + +Two raw member-function-pointer actions combined with the comma operator +(`&A::f, &A::g`) select the built-in comma operator, because both operands are +class types — so SML's action-sequencing is bypassed. Wrap the actions with +`wrap(...)` to restore sequencing: + +```cpp +*"s1"_s + event / (wrap(&A::f), wrap(&A::g)) = X +``` + +See `example/actions_guards.cpp` for a worked example. diff --git a/doc/overview.md b/doc/overview.md index 4cdd5f90..ea1e304f 100644 --- a/doc/overview.md +++ b/doc/overview.md @@ -48,7 +48,17 @@ git clone https://github.com/boost-ext/sml && cd sml && make test ###Configuration | Macro | Description | | --------------------------------------------------------------|--------------------------------------------------------------| -| `BOOST_SML_VERSION` | Current version of [Boost].SML (ex. 1'0'0) | +| `BOOST_SML_VERSION` | Current version of [Boost].SML (ex. 1'1'13) | +| `BOOST_SML_CFG_ENABLE_MIN_SIZE` | Opt in to the empty-SM size trick (zero-size array); disabled by default, see note below | +| `BOOST_SML_CFG_DISABLE_MIN_SIZE` | Legacy name kept for backward compatibility; the min-size trick is now disabled by default | +| `BOOST_SML_DISABLE_EXCEPTIONS` | Build with exceptions disabled (e.g. with `-fno-exceptions`) | +| `BOOST_SML_CREATE_DEFAULT_CONSTRUCTIBLE_DEPS` | Allow default-constructing dependencies owned by the State Machine | + +> **Note (min-size):** Since the changes after `v1.1.13`, the empty-State-Machine +> size optimization is **off by default** on GCC/Clang because the zero-length-array +> trick triggered undefined behavior at `-O2` (UBSan violations). As a result, +> `sizeof(sm<...>)` for an empty State Machine may differ from earlier releases. +> Define `BOOST_SML_CFG_ENABLE_MIN_SIZE` to opt back in. ###Exception Safety diff --git a/doc/tutorial.md b/doc/tutorial.md index 3ff4da4a..90a0ae17 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -325,6 +325,31 @@ return make_transition_table( ); ``` +Events can also be deferred and re-evaluated later with `defer`, and a transition +can discard everything currently deferred with `clear_defer` (a no-op when nothing +is deferred). This is handy when leaving a composite/sub-state so that stale +deferred events do not survive re-entry. Both require a `defer_queue` policy. + +```cpp +using namespace sml; +return make_transition_table( + *"s1"_s + event / defer, // postpone my_event + state + event / clear_defer = "s1"_s // drop anything deferred on the way out +); +``` + +When events are queued asynchronously — e.g. an action stores a `back::process<>` +handle that fires after `process_event` has already returned — call `flush_queue()` +to drain whatever is still pending (it is a no-op when the queue is empty). This +requires a `process_queue` policy. + +```cpp +sml::sm> sm{...}; +sm.process_event(e1{}); // action stores a back::process handle +handle.push(e2{}); // async callback pushes e2 after process_event returned +sm.flush_queue(); // drain: e2 is processed now +``` + `SML` also provides a way to dispatch dynamically created events into the state machine. ```cpp diff --git a/doc/user_guide.md b/doc/user_guide.md index 35a2cd58..6ef011f5 100644 --- a/doc/user_guide.md +++ b/doc/user_guide.md @@ -362,6 +362,8 @@ Creates a State Machine. template // no requirements bool process_event(const TEvent&) + void flush_queue(); // drain events still pending in the process queue + template requires callable void visit_current_states(const TVisitor &) const noexcept(noexcept(visitor(state{}))); @@ -376,6 +378,7 @@ Creates a State Machine. | ---------- | ----------- | ----------- | ------- | | `TDeps...` | is_base_of dependencies | constructor | | | `process_event` | - | process event `TEvent` | returns true when handled, false otherwise | +| `flush_queue` | requires a `process_queue` / `defer_queue` policy | drain events still pending in the process queue (e.g. pushed from an async handler after `process_event` returned); no-op when empty | - | | `visit_current_states` | [callable](#callable-concept) | visit current states | - | | `is` | - | verify whether any of current states equals `TState` | true when any current state matches `TState`, false otherwise | | `is` | size of TStates... equals number of initial states | verify whether all current states match `TStates...` | true when all states match `TState...`, false otherwise | @@ -432,11 +435,13 @@ Additional State Machine configurations. thread_safe logger + deps | Expression | Requirement | Description | Example | | ---------- | ----------- | ----------- | ------- | | `Lockable` | `lock/unlock` | Lockable type | `std::mutex`, `std::recursive_mutex` | | `Loggable` | `log_process_event/log_state_change/log_action/log_guard` | Loggable type | - | +| `deps` | - | force `Ts...` into the dependency pool even when no action/guard signature names them (needed when a dependency is only reached via a generic lambda using `sml::aux::get(deps)`) | `sml::sm> sm{dep};` | ***Example*** @@ -444,6 +449,7 @@ Additional State Machine configurations. sml::sm> sm; // logger policy sml::sm, sml::logger> sm; // thread safe and logger policy sml::sm, sml::thread_safe> sm; // thread safe and logger policy + sml::sm> sm{dep}; // explicit pool dependency for generic-lambda actions/guards ![CPP(BTN)](Run_Logging_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/logging.cpp) From a3fde10e5d334f282eea06b4034551d2524077a7 Mon Sep 17 00:00:00 2001 From: Pavel Guzenfeld Date: Mon, 1 Jun 2026 01:41:09 +0300 Subject: [PATCH 2/9] docs: add verified Compiler Explorer run-links to every example Every example in the docs is verified to compile + run at -std=c++14 (GCC 14.3 locally in Docker, incl. SDL2 for sdl2.cpp; arduino compiles to an empty main without Arduino.h) and on Compiler Explorer (GCC 14.2). A 'Run on Compiler Explorer' link is added beside each ![CPP] embed across examples.md, tutorial.md, user_guide.md, index.md and overview.md (65 links total). Since Boost.SML is not a Compiler Explorer library, each link inlines sml.hpp (and dispatch_table.hpp where used); BOOST_SML_* config macros are hoisted above the header so they still apply (e.g. data.cpp). The error/* examples get compile-only links that show their intended diagnostic. Also fixes broken doc links: - user_guide.md: example/action_guards.cpp -> example/actions_guards.cpp (typo) - user_guide.md: example/errors/not_*.cpp -> test/ft/errors/not_*.cpp (wrong path) Adds doc/scripts/gen_godbolt_links.sh to regenerate the links reproducibly. --- doc/examples.md | 22 ++++++++++ doc/index.md | 4 ++ doc/overview.md | 4 ++ doc/scripts/gen_godbolt_links.sh | 74 ++++++++++++++++++++++++++++++++ doc/tutorial.md | 17 ++++++++ doc/user_guide.md | 28 +++++++++--- 6 files changed, 144 insertions(+), 5 deletions(-) create mode 100755 doc/scripts/gen_godbolt_links.sh diff --git a/doc/examples.md b/doc/examples.md index 2ecf3e34..c36bbdad 100644 --- a/doc/examples.md +++ b/doc/examples.md @@ -25,66 +25,88 @@ ###Hello World ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/hello_world.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/W9zoarv69) ###Events ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/events.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/sWWEYvj3s) ###States ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/states.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/EfbfqqTYo) ###Actions Guards ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/actions_guards.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/q9nEfv9qv) ###Transitions ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/transitions.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/jqz5frEP5) ###Defer/Process ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/defer_and_process.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/xvfrGvTKW) ###Orthogonal Regions ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/orthogonal_regions.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/Ma7sT74hq) ###Composite ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/composite.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/9xPc56P36) ###History ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/history.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/46erdGWxx) ###Error handling ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/error_handling.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/1G3P6ne7Y) ###Logging ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/logging.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/vheaGPWqT) ###Nested ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/nested.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/1PnKKnKMd) ###Testing ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/testing.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/e9j19aTd7) ###Runtime Dispatcher ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/dispatch_table.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/6vs9E6Ynf) ###eUML Emulation ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/euml_emulation.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/KhqvGjKPP) ###Dependencies ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/dependencies.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/hW6Gzvd5f) ###Data ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/data.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/c558Gvh3Y) ###In-Place ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/in_place.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/TjEbqo3E6) ###Dependency Injection ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/dependency_injection.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/zYvM1a6v4) ###Arduino Integration ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/arduino.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/96KdPcP13) ###SDL2 Integration ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/sdl2.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/K4q6hhz5o) ###Plant UML Integration ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/plant_uml.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/4sb18vWG3) diff --git a/doc/index.md b/doc/index.md index 425d9a1e..2d5a52d1 100644 --- a/doc/index.md +++ b/doc/index.md @@ -46,9 +46,13 @@ to avoid it `[Boost].SML` may suit you! ###Real Life examples? ![CPP(BTN)](Run_SDL2_Integration_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/sdl2.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/K4q6hhz5o) ![CPP(BTN)](Run_Plant_UML_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/plant_uml.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/4sb18vWG3) ![CPP(BTN)](Run_Logging_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/logging.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/vheaGPWqT) ![CPP(BTN)](Run_Testing_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/testing.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/e9j19aTd7)   diff --git a/doc/overview.md b/doc/overview.md index ea1e304f..f870399a 100644 --- a/doc/overview.md +++ b/doc/overview.md @@ -93,15 +93,19 @@ sm.process_event(event{}); // thread safe call ***Not configurable*** ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/test/ft/errors/not_configurable.cpp) +[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/Pf64KjfG8) ***Not callable*** ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/test/ft/errors/not_callable.cpp) +[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/b7xP5brcE) ***Not transitional*** ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/test/ft/errors/not_transitional.cpp) +[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/cnhP9Pf4o) ***Not dispatchable*** ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/test/ft/errors/not_dispatchable.cpp) +[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/abKhzTz1T) [Boost.MSM-eUML]: http://www.boost.org/doc/libs/1_60_0/libs/msm/doc/HTML/ch03s04.html [Boost.MSM3-eUML2]: https://htmlpreview.github.io/?https://raw.githubusercontent.com/boostorg/msm/msm3/doc/HTML/ch03s05.html diff --git a/doc/scripts/gen_godbolt_links.sh b/doc/scripts/gen_godbolt_links.sh new file mode 100755 index 00000000..d6af2643 --- /dev/null +++ b/doc/scripts/gen_godbolt_links.sh @@ -0,0 +1,74 @@ +#!/usr/bin/env bash +# +# Regenerate the "Run on Compiler Explorer" links embedded in the docs. +# +# Boost.SML is a single-header library that is NOT registered as a Compiler +# Explorer library, so each godbolt.org/z/ link inlines include/boost/sml.hpp +# (and utility/dispatch_table.hpp where used) ahead of the example source. +# Any `#define BOOST_SML_*` config macro is hoisted above the inlined header so +# it still takes effect (see data.cpp / BOOST_SML_CREATE_DEFAULT_CONSTRUCTIBLE_DEPS). +# +# All examples are validated to compile (and execute) on GCC 14.2 at -std=c++14 +# before a short link is created. The error/* examples intentionally fail to +# compile and get compile-only links that show the diagnostic. +# +# Requirements: bash, curl, jq. Run from the repository root. +# Usage: +# doc/scripts/gen_godbolt_links.sh # print "name url" for every example +# doc/scripts/gen_godbolt_links.sh --insert # also rewrite the CE links in doc/*.md +# +set -euo pipefail +cd "$(git rev-parse --show-toplevel)" + +GCC=g142 # Compiler Explorer GCC 14.2 +STD_DEFAULT=c++14 # SML's minimum standard +HDR=include/boost/sml.hpp +DT=include/boost/sml/utility/dispatch_table.hpp +STRIP='#include[[:space:]]*[<"]boost/sml\.hpp[>"]|#include[[:space:]]*[<"]boost/sml/utility/dispatch_table\.hpp[>"]|^[[:space:]]*#define[[:space:]]+BOOST_SML' + +assemble() { # -> self-contained translation unit on stdout + local ex="$1" + grep -E '^[[:space:]]*#define[[:space:]]+BOOST_SML' "$ex" || true # hoist config macros + cat "$HDR" + grep -q 'utility/dispatch_table.hpp' "$ex" && grep -vE "$STRIP" "$DT" + grep -vE "$STRIP" "$ex" +} + +shorten() { # -> godbolt short url + local src="$1" std="$2" exec="$3" + jq -n --rawfile s "$src" --arg std "$std" --argjson ex "$exec" \ + '{sessions:[{id:1,language:"c++",source:$s, + compilers:[{id:"'"$GCC"'",options:("-O2 -std="+$std),libs:[], + filters:{execute:$ex,labels:true,directives:true,commentOnly:true,trim:true,demangle:true}}], + executors:(if $ex then [{compiler:{id:"'"$GCC"'",options:("-O2 -std="+$std),libs:[],overrides:[]}, + arguments:"",stdin:"",compilerOutputVisible:true,stdoutVisible:true,stderrVisible:true}] else [] end)}]}' \ + | curl -s -X POST 'https://godbolt.org/api/shortener' -H 'Content-Type: application/json' -d @- | jq -r '.url' +} + +MAP=$(mktemp) +process() { # + local ex="$1" exec="$2" name std tmp url + name=$(basename "$ex" .cpp) + std=$STD_DEFAULT; [ "$name" = arduino ] && std=c++20 # template lambdas + tmp=$(mktemp); assemble "$ex" > "$tmp" + url=$(shorten "$tmp" "$std" "$exec"); rm -f "$tmp" + echo "$name $url" | tee -a "$MAP" +} + +for f in example/*.cpp; do process "$f" true; done +for f in test/ft/errors/not_*.cpp; do process "$f" false; done + +if [ "${1:-}" = "--insert" ]; then + # strip previously-generated CE links, then re-insert after each embed + DOCS=(doc/examples.md doc/tutorial.md doc/user_guide.md doc/index.md doc/overview.md) + for d in "${DOCS[@]}"; do sed -i '/Compiler Explorer\](https:\/\/godbolt.org/d' "$d"; done + while read -r name url; do + case "$name" in + not_*) label="▶ See the compile error on Compiler Explorer";; + *) label="▶ Run on Compiler Explorer";; + esac + for d in "${DOCS[@]}"; do sed -i "\#/${name}\.cpp)#a [$label]($url)" "$d"; done + done < "$MAP" + echo "docs updated." +fi +rm -f "$MAP" diff --git a/doc/tutorial.md b/doc/tutorial.md index 90a0ae17..834c42ef 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -75,8 +75,11 @@ assert(string("idle") == "idle"_s.c_str()); ``` ![CPP(BTN)](Run_Events_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/events.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/sWWEYvj3s) ![CPP(BTN)](Run_States_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/states.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/EfbfqqTYo) ![CPP(BTN)](Run_Composite_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/composite.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/9xPc56P36)   @@ -118,6 +121,7 @@ struct action4 { ``` ![CPP(BTN)](Run_Actions_Guards_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/actions_guards.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/q9nEfv9qv)   @@ -188,7 +192,9 @@ make_transition_table( ``` ![CPP(BTN)](Run_Transition_Table_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/transitions.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/jqz5frEP5) ![CPP(BTN)](Run_eUML_Emulation_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/euml_emulation.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/KhqvGjKPP)   @@ -233,7 +239,9 @@ make_transition_table( ``` ![CPP(BTN)](Run_Orthogonal_Regions_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/orthogonal_regions.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/Ma7sT74hq) ![CPP(BTN)](Run_History_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/history.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/46erdGWxx)   @@ -297,7 +305,9 @@ sm.process_event(e1{}); ``` ![CPP(BTN)](Run_Hello_World_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/hello_world.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/W9zoarv69) ![CPP(BTN)](Run_Dependency_Injection_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/dependency_injection.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/zYvM1a6v4)   @@ -365,8 +375,11 @@ dispatch_event(event, event.type); // will call sm.process(game_over{}); ``` ![CPP(BTN)](Run_Hello_World_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/hello_world.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/W9zoarv69) ![CPP(BTN)](Run_Dispatch_Table_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/dispatch_table.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/6vs9E6Ynf) ![CPP(BTN)](Run_SDL2_Integration_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/sdl2.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/K4q6hhz5o)   @@ -434,6 +447,7 @@ make_transition_table( ``` ![CPP(BTN)](Run_Error_Handling_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/error_handling.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/1G3P6ne7Y)   @@ -467,6 +481,7 @@ assert(sm.is(X)); ``` ![CPP(BTN)](Run_Testing_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/testing.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/e9j19aTd7)   @@ -508,7 +523,9 @@ sm.process_event(my_event{}); // will call logger appropriately ``` ![CPP(BTN)](Run_Logging_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/logging.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/vheaGPWqT) ![CPP(BTN)](Run_Plant_UML_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/plant_uml.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/4sb18vWG3)   diff --git a/doc/user_guide.md b/doc/user_guide.md index 6ef011f5..04642793 100644 --- a/doc/user_guide.md +++ b/doc/user_guide.md @@ -41,7 +41,8 @@ Requirements for transition. static_assert(transitional::value); } -![CPP(BTN)](Run_Transitional_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/errors/not_transitional.cpp) +![CPP(BTN)](Run_Transitional_Example|https://raw.githubusercontent.com/boost-ext/sml/master/test/ft/errors/not_transitional.cpp) +[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/cnhP9Pf4o)   @@ -80,7 +81,8 @@ Requirements for the state machine. static_assert(configurable::value); -![CPP(BTN)](Run_Configurable_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/errors/not_configurable.cpp) +![CPP(BTN)](Run_Configurable_Example|https://raw.githubusercontent.com/boost-ext/sml/master/test/ft/errors/not_configurable.cpp) +[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/Pf64KjfG8)   @@ -117,7 +119,8 @@ Requirements for action and guards. static_assert(callable::value); static_assert(callable::value); -![CPP(BTN)](Run_Callable_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/errors/not_callable.cpp) +![CPP(BTN)](Run_Callable_Example|https://raw.githubusercontent.com/boost-ext/sml/master/test/ft/errors/not_callable.cpp) +[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/b7xP5brcE)   @@ -163,8 +166,10 @@ Requirements for the dispatch table. static_assert(dispatchable::value); static_assert(dispatchable::value); -![CPP(BTN)](Run_Dispatchable_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/errors/not_dispatchable.cpp) +![CPP(BTN)](Run_Dispatchable_Example|https://raw.githubusercontent.com/boost-ext/sml/master/test/ft/errors/not_dispatchable.cpp) +[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/abKhzTz1T) ![CPP(BTN)](Run_SDL2_Integration_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/sdl2.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/K4q6hhz5o)   @@ -229,8 +234,11 @@ Represents a state machine state. auto terminate_state = X; ![CPP(BTN)](Run_States_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/states.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/EfbfqqTYo) ![CPP(BTN)](Run_Composite_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/composite.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/9xPc56P36) ![CPP(BTN)](Run_Orthogonal_Regions_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/orthogonal_regions.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/Ma7sT74hq)   @@ -280,8 +288,10 @@ Represents a state machine event. auto my_int_event = event; -![CPP(BTN)](Run_Events_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/action_guards.cpp) +![CPP(BTN)](Run_Events_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/actions_guards.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/q9nEfv9qv) ![CPP(BTN)](Run_Error_Handling_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/error_handling.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/1G3P6ne7Y)   @@ -328,6 +338,7 @@ Creates a transition table. }; ![CPP(BTN)](Run_Transition_Table_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/transitions.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/jqz5frEP5)   @@ -414,8 +425,11 @@ Creates a State Machine. sm.visit_current_states([](auto state) { std::cout << state.c_str() << std::endl; }); ![CPP(BTN)](Run_Hello_World_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/hello_world.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/W9zoarv69) ![CPP(BTN)](Run_Dependency_Injection_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/dependency_injection.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/zYvM1a6v4) ![CPP(BTN)](Run_eUML_Emulation_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/euml_emulation.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/KhqvGjKPP)   @@ -452,6 +466,7 @@ Additional State Machine configurations. sml::sm> sm{dep}; // explicit pool dependency for generic-lambda actions/guards ![CPP(BTN)](Run_Logging_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/logging.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/vheaGPWqT)   @@ -497,6 +512,7 @@ Creates a state machine with testing capabilities. sm.is(X); ![CPP(BTN)](Run_Testing_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/testing.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/e9j19aTd7)   @@ -541,7 +557,9 @@ Creates a dispatch table to handle runtime events. dispatch_event(event, event.id); ![CPP(BTN)](Run_Dispatch_Table_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/dispatch_table.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/6vs9E6Ynf) ![CPP(BTN)](Run_SDL2_Integration_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/sdl2.cpp) +[▶ Run on Compiler Explorer](https://godbolt.org/z/K4q6hhz5o)   From 43cfe5c770e76aea04f76674332c0ef841785ddb Mon Sep 17 00:00:00 2001 From: Pavel Guzenfeld Date: Mon, 1 Jun 2026 01:51:03 +0300 Subject: [PATCH 3/9] docs(theme): fix dead Wandbox 'Run' endpoint in boost-modern The in-page 'Compile & Run' buttons POSTed to http://melpon.org/wandbox (plain HTTP -> mixed-content blocked on the HTTPS site, and a dead host). - Repoint to https://wandbox.org/api/compile.json (alive; sends Access-Control-Allow-Origin: * so the cross-origin XHR works). - Drop the now-invalid 'boost-1.60' compile option (it makes the API reject the request; SML has no Boost dependency anyway). - Supply boost/sml/utility/dispatch_table.hpp alongside boost/sml.hpp so the dispatch_table and sdl2 examples also run. - Update the 'Powered by Wandbox' footer link to https://wandbox.org. Verified end-to-end against the live API at -std=c++14 (clang-head): hello_world, composite, data, transitions, dispatch_table and sdl2 all return status 0 (sdl2 prints its expected output). --- doc/themes/boost-modern/footer.html | 2 +- doc/themes/boost-modern/js/cpp.js | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/doc/themes/boost-modern/footer.html b/doc/themes/boost-modern/footer.html index 4d596232..9df4a3f7 100644 --- a/doc/themes/boost-modern/footer.html +++ b/doc/themes/boost-modern/footer.html @@ -39,5 +39,5 @@ {% endif %} - Built with MkDocs using a theme provided by Read the Docs | Powered by Wandbox + Built with MkDocs using a theme provided by Read the Docs | Powered by Wandbox diff --git a/doc/themes/boost-modern/js/cpp.js b/doc/themes/boost-modern/js/cpp.js index cb945a1d..c2007146 100644 --- a/doc/themes/boost-modern/js/cpp.js +++ b/doc/themes/boost-modern/js/cpp.js @@ -48,7 +48,7 @@ function compile_and_run(id) { document.getElementById("compile_and_run_" + id).firstChild.data = "Compiling..."; cpp_output[id].setValue("Compiling..."); var http = new XMLHttpRequest(); - http.open("POST", "http://melpon.org/wandbox/api/compile.json", true); + http.open("POST", "https://wandbox.org/api/compile.json", true); http.onreadystatechange = function(){ if (http.readyState == 4 && http.status == 200) { var output_json = JSON.parse(http.response); @@ -74,8 +74,11 @@ function compile_and_run(id) { , "codes" : [{ "file" : "boost/sml.hpp" , "code" : get_cpp_file("https://raw.githubusercontent.com/boost-ext/sml/master/include/boost/sml.hpp") + }, { + "file" : "boost/sml/utility/dispatch_table.hpp" + , "code" : get_cpp_file("https://raw.githubusercontent.com/boost-ext/sml/master/include/boost/sml/utility/dispatch_table.hpp") }] - , "options": "warning,cpp-pedantic-errors,optimize,boost-1.60,c++1y" + , "options": "warning,cpp-pedantic-errors,optimize,c++1y" , "compiler" : "clang-head" , "compiler-option-raw": "-I." + "\n" + "-fno-color-diagnostics" })); From f8f32d9ef590e2340876116bb2bb9f42da176e7b Mon Sep 17 00:00:00 2001 From: Pavel Guzenfeld Date: Mon, 1 Jun 2026 01:54:09 +0300 Subject: [PATCH 4/9] docs: regenerate README documentation TOC for new FAQ/CHANGELOG content - Run doc/scripts/update_readme_toc.py so the README's auto-generated table of contents reflects the new FAQ 'Limitations' section and the '[Unreleased] - since 1.1.13' CHANGELOG entry. - Adjust faq.md heading levels (page title -> h1) so the generator does not emit a redundant 'FAQ' child entry under the FAQ link. --- README.md | 4 ++++ doc/faq.md | 8 ++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 649328c7..4983a697 100644 --- a/README.md +++ b/README.md @@ -312,7 +312,11 @@ send: 42 * [SDL2 Integration](https://boost-ext.github.io/sml/examples.html#sdl2-integration) * [Plant UML Integration](https://boost-ext.github.io/sml/examples.html#plant-uml-integration) * [FAQ](https://boost-ext.github.io/sml/faq.html) + * [Limitations](https://boost-ext.github.io/sml/faq.html#limitations) + * [`on_entry<_>` across translation units](https://boost-ext.github.io/sml/faq.html#on_entry_-across-translation-units) + * [`operator,` with two raw member-function-pointer actions](https://boost-ext.github.io/sml/faq.html#operator-with-two-raw-member-function-pointer-actions) * [CHANGELOG](https://boost-ext.github.io/sml/CHANGELOG.html) + * [[Unreleased] - since 1.1.13](https://boost-ext.github.io/sml/CHANGELOG.html#unreleased-since-1113) * [[1.1.13] - 2025-12-01](https://boost-ext.github.io/sml/CHANGELOG.html#1113-2025-12-01) * [[1.1.12] - 2025-04-02](https://boost-ext.github.io/sml/CHANGELOG.html#1112-2025-04-02) * [[1.1.11] - 2024-03-09](https://boost-ext.github.io/sml/CHANGELOG.html#1111-2024-03-09) diff --git a/doc/faq.md b/doc/faq.md index 268d0b7d..c49ef59b 100644 --- a/doc/faq.md +++ b/doc/faq.md @@ -1,8 +1,8 @@ -## FAQ +# FAQ -### Limitations +## Limitations -#### `on_entry<_>` across translation units +### `on_entry<_>` across translation units When `on_entry<_>` (the wildcard entry handler) is defined in one translation unit while the `initial`-event specialization is left undefined, the linker reports an @@ -17,7 +17,7 @@ event used to enter the state. // on_entry<_> fires when entering via any other event (no specific handler) ``` -#### `operator,` with two raw member-function-pointer actions +### `operator,` with two raw member-function-pointer actions Two raw member-function-pointer actions combined with the comma operator (`&A::f, &A::g`) select the built-in comma operator, because both operands are From 95ca89fd054258074424aa1e9785132f6ffd5e24 Mon Sep 17 00:00:00 2001 From: Pavel Guzenfeld Date: Mon, 1 Jun 2026 01:59:40 +0300 Subject: [PATCH 5/9] :arrow_up: v1.2.0 Cut the next release. Minor bump (not patch): this release adds new public API (sm::flush_queue, sml::clear_defer, sml::deps) and changes observable behavior (empty-SM sizeof under #249), so it is 1.2.0 per semver. - BOOST_SML_VERSION 1'1'13 -> 1'2'0; inline namespace v1_1_13 -> v1_2_0 - CMakeLists package version 1.1.13 -> 1.2.0 - CHANGELOG: finalize the entry as [1.2.0] - 2026-06-01 (compare link -> v1.2.0) - README: regenerate documentation TOC for the 1.2.0 changelog entry --- CMakeLists.txt | 2 +- README.md | 2 +- doc/CHANGELOG.md | 4 ++-- include/boost/sml.hpp | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a4d535d3..af666767 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -206,7 +206,7 @@ configure_package_config_file( write_basic_package_version_file( ${CMAKE_CURRENT_BINARY_DIR}/smlConfigVersion.cmake - VERSION 1.1.13 + VERSION 1.2.0 COMPATIBILITY SameMajorVersion ) diff --git a/README.md b/README.md index 4983a697..217e4254 100644 --- a/README.md +++ b/README.md @@ -316,7 +316,7 @@ send: 42 * [`on_entry<_>` across translation units](https://boost-ext.github.io/sml/faq.html#on_entry_-across-translation-units) * [`operator,` with two raw member-function-pointer actions](https://boost-ext.github.io/sml/faq.html#operator-with-two-raw-member-function-pointer-actions) * [CHANGELOG](https://boost-ext.github.io/sml/CHANGELOG.html) - * [[Unreleased] - since 1.1.13](https://boost-ext.github.io/sml/CHANGELOG.html#unreleased-since-1113) + * [[1.2.0] - 2026-06-01](https://boost-ext.github.io/sml/CHANGELOG.html#120-2026-06-01) * [[1.1.13] - 2025-12-01](https://boost-ext.github.io/sml/CHANGELOG.html#1113-2025-12-01) * [[1.1.12] - 2025-04-02](https://boost-ext.github.io/sml/CHANGELOG.html#1112-2025-04-02) * [[1.1.11] - 2024-03-09](https://boost-ext.github.io/sml/CHANGELOG.html#1111-2024-03-09) diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index 817398a3..5860297f 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -1,4 +1,4 @@ -## [Unreleased] - since 1.1.13 +## [1.2.0] - 2026-06-01 - **Additions** - `sm::flush_queue()` — drain pending queued events from async handlers (#456) - `sml::clear_defer` action — discard deferred events from a transition (#643) @@ -15,7 +15,7 @@ - **Bug Fixes** - Template-depth, `-Wshadow`, `-Wextra-semi`, UBSan, final-class, null-deref, double-pop, reserved-identifier and related fixes — see full list: - - https://github.com/boost-ext/sml/compare/v1.1.13...master + - https://github.com/boost-ext/sml/compare/v1.1.13...v1.2.0 - **Documented limitations** - `on_entry<_>` multi-TU linker limitation and dispatch priority (#565) diff --git a/include/boost/sml.hpp b/include/boost/sml.hpp index 215a0723..86dc103d 100644 --- a/include/boost/sml.hpp +++ b/include/boost/sml.hpp @@ -12,12 +12,12 @@ #if defined(__ICCARM__) && __IAR_SYSTEMS_ICC__ < 8 #error "[Boost::ext].SML requires C++14 support (IAR C/C++ ARM 8.1+)" #endif -#define BOOST_SML_VERSION 1'1'13 +#define BOOST_SML_VERSION 1'2'0 #define BOOST_SML_NAMESPACE_BEGIN \ namespace boost { \ inline namespace ext { \ namespace sml { \ - inline namespace v1_1_13 { + inline namespace v1_2_0 { #define BOOST_SML_NAMESPACE_END \ } \ } \ From e7a056749deb165d9eb2d8e8ad0da73ec4cc1cbf Mon Sep 17 00:00:00 2001 From: Pavel Guzenfeld Date: Mon, 1 Jun 2026 02:13:01 +0300 Subject: [PATCH 6/9] fix: retune get_type_name offsets for the v1_2_0 namespace length The v1.1.13 -> v1.2.0 inline-namespace rename (v1_1_13 -> v1_2_0) shortened the namespace string by one character. get_type_name() skips a hardcoded prefix length into __FUNCSIG__/__PRETTY_FUNCTION__, and that prefix includes the inline namespace on MSVC/GCC/IAR (clang elides it). The stale offsets made get_type_name() return the wrong substring, failing test_type_traits (all compilers) and test_policies_logging (GCC). Adjust the affected offsets by -1: MSVC 65->64, GCC 69->68, IAR 72->71; clang (50/63) is namespace-length-independent and unchanged. GCC 68 matches the pre-1.1.10 value for a 6-char namespace. Verified: full ctest suite 68/68 on GCC (C++17); MSVC type_traits passes under msvc-wine (and fails at offset 65, confirming 64). Added a comment so the offsets are re-tuned on future namespace-length changes. Fixes CI on PR #708 (ubuntu g++, windows MSVC). --- include/boost/sml.hpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/include/boost/sml.hpp b/include/boost/sml.hpp index 86dc103d..0905cbce 100644 --- a/include/boost/sml.hpp +++ b/include/boost/sml.hpp @@ -989,16 +989,21 @@ auto get_type_name(const char *ptr, index_sequence) { } // namespace detail template const char *get_type_name() { +// NOTE: these offsets skip the function-signature prefix up to `T`. That prefix +// includes the inline namespace (e.g. v1_2_0) on compilers that print it +// (MSVC/GCC/IAR), so the offsets must be re-tuned whenever the namespace string +// length changes on a release. clang elides the inline namespace, so its offsets +// are length-independent. #if defined(_MSC_VER) && !defined(__clang__) - return detail::get_type_name(__FUNCSIG__, make_index_sequence{}); + return detail::get_type_name(__FUNCSIG__, make_index_sequence{}); #elif defined(__clang__) && (__clang_major__ >= 12) return detail::get_type_name(__PRETTY_FUNCTION__, make_index_sequence{}); #elif defined(__clang__) return detail::get_type_name(__PRETTY_FUNCTION__, make_index_sequence{}); #elif defined(__GNUC__) - return detail::get_type_name(__PRETTY_FUNCTION__, make_index_sequence{}); + return detail::get_type_name(__PRETTY_FUNCTION__, make_index_sequence{}); #elif defined(__ICCARM__) - return detail::get_type_name(__PRETTY_FUNCTION__, make_index_sequence{}); + return detail::get_type_name(__PRETTY_FUNCTION__, make_index_sequence{}); #endif } #if defined(__cpp_nontype_template_parameter_class) || \ From 90a3c619b37fecf420f877637703a0d0ac965050 Mon Sep 17 00:00:00 2001 From: Pavel Guzenfeld Date: Mon, 1 Jun 2026 15:41:34 +0300 Subject: [PATCH 7/9] docs: document sml::make_action and regenerate Godbolt links for v1.2.0 #706 (sml::make_action, issue #629) is now merged into master, so this rebases onto it and documents it: - CHANGELOG: add make_action to the 1.2.0 additions - user_guide: new 'make_action [utility]' reference section with a verified run-link - tutorial: note make_action in the guards/actions section - README: regenerate TOC (adds the make_action entry) Regenerate every Compiler Explorer link against the v1.2.0 header (inline namespace v1_2_0) and re-verify each compiles + runs at -std=c++14 on godbolt (arduino c++20); replace the stale v1_1_13-era links across examples/tutorial/user_guide/index/overview. Also fix a bug in gen_godbolt_links.sh exposed during regeneration: the config-macro hoist strip (#define BOOST_SML*) was applied to dispatch_table.hpp too, deleting its deliberate re-#define of BOOST_SML_DETAIL_REQUIRES (sml.hpp #undef's it before that point) and breaking the dispatch_table/sdl2 links. Strip only the sml.hpp include from dispatch_table.hpp; keep its #define/#undef. The standalone make_action link is now preserved across --insert re-runs. --- README.md | 1 + doc/CHANGELOG.md | 1 + doc/examples.md | 44 ++++++++-------- doc/index.md | 8 +-- doc/overview.md | 8 +-- doc/scripts/gen_godbolt_links.sh | 19 ++++--- doc/tutorial.md | 44 +++++++++------- doc/user_guide.md | 86 +++++++++++++++++++++++++------- 8 files changed, 140 insertions(+), 71 deletions(-) diff --git a/README.md b/README.md index 217e4254..e1c0818d 100644 --- a/README.md +++ b/README.md @@ -287,6 +287,7 @@ send: 42 * [sm [state machine]](https://boost-ext.github.io/sml/user_guide.html#sm-state-machine) * [policies [state machine]](https://boost-ext.github.io/sml/user_guide.html#policies-state-machine) * [testing::sm [testing]](https://boost-ext.github.io/sml/user_guide.html#testingsm-testing) + * [make_action [utility]](https://boost-ext.github.io/sml/user_guide.html#make_action-utility) * [make_dispatch_table [utility]](https://boost-ext.github.io/sml/user_guide.html#make_dispatch_table-utility) * [Examples](https://boost-ext.github.io/sml/examples.html) * [Hello World](https://boost-ext.github.io/sml/examples.html#hello-world) diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index 5860297f..8f2ba373 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -3,6 +3,7 @@ - `sm::flush_queue()` — drain pending queued events from async handlers (#456) - `sml::clear_defer` action — discard deferred events from a transition (#643) - `sml::deps` policy — explicit pool dependencies for generic-lambda actions/guards (#437) + - `sml::make_action(f)` — wrap a template/generic/constrained callable so its dependency and event types are deduced from the explicit `` list (#629) - **Behavior changes** - Empty-SM min-size trick is now OFF by default on GCC/Clang (it was UB at `-O2`); diff --git a/doc/examples.md b/doc/examples.md index c36bbdad..b6d1b7b3 100644 --- a/doc/examples.md +++ b/doc/examples.md @@ -25,88 +25,88 @@ ###Hello World ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/hello_world.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/W9zoarv69) +[▶ Run on Compiler Explorer](https://godbolt.org/z/9x4E1hnWP) ###Events ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/events.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/sWWEYvj3s) +[▶ Run on Compiler Explorer](https://godbolt.org/z/93joP5dv1) ###States ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/states.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/EfbfqqTYo) +[▶ Run on Compiler Explorer](https://godbolt.org/z/Y8b3he645) ###Actions Guards ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/actions_guards.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/q9nEfv9qv) +[▶ Run on Compiler Explorer](https://godbolt.org/z/qqGsrTGq3) ###Transitions ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/transitions.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/jqz5frEP5) +[▶ Run on Compiler Explorer](https://godbolt.org/z/dErTW4jxb) ###Defer/Process ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/defer_and_process.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/xvfrGvTKW) +[▶ Run on Compiler Explorer](https://godbolt.org/z/ah94rM966) ###Orthogonal Regions ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/orthogonal_regions.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/Ma7sT74hq) +[▶ Run on Compiler Explorer](https://godbolt.org/z/rf9c76hxK) ###Composite ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/composite.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/9xPc56P36) +[▶ Run on Compiler Explorer](https://godbolt.org/z/zbojc8oKs) ###History ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/history.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/46erdGWxx) +[▶ Run on Compiler Explorer](https://godbolt.org/z/8G5on88nK) ###Error handling ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/error_handling.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/1G3P6ne7Y) +[▶ Run on Compiler Explorer](https://godbolt.org/z/e4Wj5858W) ###Logging ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/logging.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/vheaGPWqT) +[▶ Run on Compiler Explorer](https://godbolt.org/z/raYvoWzjq) ###Nested ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/nested.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/1PnKKnKMd) +[▶ Run on Compiler Explorer](https://godbolt.org/z/4ve1WfT9E) ###Testing ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/testing.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/e9j19aTd7) +[▶ Run on Compiler Explorer](https://godbolt.org/z/4a7vK9o8a) ###Runtime Dispatcher ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/dispatch_table.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/6vs9E6Ynf) +[▶ Run on Compiler Explorer](https://godbolt.org/z/EKGKvWjdG) ###eUML Emulation ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/euml_emulation.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/KhqvGjKPP) +[▶ Run on Compiler Explorer](https://godbolt.org/z/W9Tbafna1) ###Dependencies ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/dependencies.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/hW6Gzvd5f) +[▶ Run on Compiler Explorer](https://godbolt.org/z/c9W9hqEE5) ###Data ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/data.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/c558Gvh3Y) +[▶ Run on Compiler Explorer](https://godbolt.org/z/v6vzcze4b) ###In-Place ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/in_place.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/TjEbqo3E6) +[▶ Run on Compiler Explorer](https://godbolt.org/z/GMcYd8Wva) ###Dependency Injection ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/dependency_injection.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/zYvM1a6v4) +[▶ Run on Compiler Explorer](https://godbolt.org/z/KxxKbhY5s) ###Arduino Integration ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/arduino.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/96KdPcP13) +[▶ Run on Compiler Explorer](https://godbolt.org/z/d8Goaha46) ###SDL2 Integration ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/sdl2.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/K4q6hhz5o) +[▶ Run on Compiler Explorer](https://godbolt.org/z/79zo4YxYM) ###Plant UML Integration ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/plant_uml.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/4sb18vWG3) +[▶ Run on Compiler Explorer](https://godbolt.org/z/ssbY17Ks4) diff --git a/doc/index.md b/doc/index.md index 2d5a52d1..ae64013f 100644 --- a/doc/index.md +++ b/doc/index.md @@ -46,13 +46,13 @@ to avoid it `[Boost].SML` may suit you! ###Real Life examples? ![CPP(BTN)](Run_SDL2_Integration_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/sdl2.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/K4q6hhz5o) +[▶ Run on Compiler Explorer](https://godbolt.org/z/79zo4YxYM) ![CPP(BTN)](Run_Plant_UML_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/plant_uml.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/4sb18vWG3) +[▶ Run on Compiler Explorer](https://godbolt.org/z/ssbY17Ks4) ![CPP(BTN)](Run_Logging_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/logging.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/vheaGPWqT) +[▶ Run on Compiler Explorer](https://godbolt.org/z/raYvoWzjq) ![CPP(BTN)](Run_Testing_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/testing.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/e9j19aTd7) +[▶ Run on Compiler Explorer](https://godbolt.org/z/4a7vK9o8a)   diff --git a/doc/overview.md b/doc/overview.md index f870399a..7f5d8e72 100644 --- a/doc/overview.md +++ b/doc/overview.md @@ -93,19 +93,19 @@ sm.process_event(event{}); // thread safe call ***Not configurable*** ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/test/ft/errors/not_configurable.cpp) -[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/Pf64KjfG8) +[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/3ceoa8fP4) ***Not callable*** ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/test/ft/errors/not_callable.cpp) -[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/b7xP5brcE) +[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/Wv9rbG7ab) ***Not transitional*** ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/test/ft/errors/not_transitional.cpp) -[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/cnhP9Pf4o) +[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/6P7qf1qvv) ***Not dispatchable*** ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/test/ft/errors/not_dispatchable.cpp) -[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/abKhzTz1T) +[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/5cWcc98x1) [Boost.MSM-eUML]: http://www.boost.org/doc/libs/1_60_0/libs/msm/doc/HTML/ch03s04.html [Boost.MSM3-eUML2]: https://htmlpreview.github.io/?https://raw.githubusercontent.com/boostorg/msm/msm3/doc/HTML/ch03s05.html diff --git a/doc/scripts/gen_godbolt_links.sh b/doc/scripts/gen_godbolt_links.sh index d6af2643..c337274e 100755 --- a/doc/scripts/gen_godbolt_links.sh +++ b/doc/scripts/gen_godbolt_links.sh @@ -24,14 +24,17 @@ GCC=g142 # Compiler Explorer GCC 14.2 STD_DEFAULT=c++14 # SML's minimum standard HDR=include/boost/sml.hpp DT=include/boost/sml/utility/dispatch_table.hpp -STRIP='#include[[:space:]]*[<"]boost/sml\.hpp[>"]|#include[[:space:]]*[<"]boost/sml/utility/dispatch_table\.hpp[>"]|^[[:space:]]*#define[[:space:]]+BOOST_SML' +INC_STRIP='#include[[:space:]]*[<"]boost/sml\.hpp[>"]|#include[[:space:]]*[<"]boost/sml/utility/dispatch_table\.hpp[>"]' +EX_STRIP="${INC_STRIP}|^[[:space:]]*#define[[:space:]]+BOOST_SML" assemble() { # -> self-contained translation unit on stdout local ex="$1" - grep -E '^[[:space:]]*#define[[:space:]]+BOOST_SML' "$ex" || true # hoist config macros + grep -E '^[[:space:]]*#define[[:space:]]+BOOST_SML' "$ex" || true # hoist config macros from example cat "$HDR" - grep -q 'utility/dispatch_table.hpp' "$ex" && grep -vE "$STRIP" "$DT" - grep -vE "$STRIP" "$ex" + # dispatch_table.hpp: strip ONLY its sml.hpp include; KEEP its own #define/#undef of + # BOOST_SML_DETAIL_REQUIRES (sml.hpp #undef's that macro before this point) + grep -q 'utility/dispatch_table.hpp' "$ex" && grep -vE "$INC_STRIP" "$DT" + grep -vE "$EX_STRIP" "$ex" } shorten() { # -> godbolt short url @@ -59,9 +62,13 @@ for f in example/*.cpp; do process "$f" true; done for f in test/ft/errors/not_*.cpp; do process "$f" false; done if [ "${1:-}" = "--insert" ]; then - # strip previously-generated CE links, then re-insert after each embed + # strip previously-generated CE links, then re-insert after each embed. + # Only delete a CE link that immediately FOLLOWS an ![CPP] embed, so standalone + # links (e.g. the make_action example in the user guide) are preserved. DOCS=(doc/examples.md doc/tutorial.md doc/user_guide.md doc/index.md doc/overview.md) - for d in "${DOCS[@]}"; do sed -i '/Compiler Explorer\](https:\/\/godbolt.org/d' "$d"; done + for d in "${DOCS[@]}"; do + awk '{ if (prev ~ /!\[CPP/ && $0 ~ /Compiler Explorer\]\(https:\/\/godbolt\.org/) { prev=$0; next } print; prev=$0 }' "$d" > "$d.tmp" && mv "$d.tmp" "$d" + done while read -r name url; do case "$name" in not_*) label="▶ See the compile error on Compiler Explorer";; diff --git a/doc/tutorial.md b/doc/tutorial.md index 834c42ef..ba5f1f6f 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -75,11 +75,11 @@ assert(string("idle") == "idle"_s.c_str()); ``` ![CPP(BTN)](Run_Events_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/events.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/sWWEYvj3s) +[▶ Run on Compiler Explorer](https://godbolt.org/z/93joP5dv1) ![CPP(BTN)](Run_States_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/states.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/EfbfqqTYo) +[▶ Run on Compiler Explorer](https://godbolt.org/z/Y8b3he645) ![CPP(BTN)](Run_Composite_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/composite.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/9xPc56P36) +[▶ Run on Compiler Explorer](https://godbolt.org/z/zbojc8oKs)   @@ -120,8 +120,18 @@ struct action4 { }; ``` +`SML` deduces the dependencies/event a guard or action wants from its `operator()`. +A *generic* lambda (`[](auto&){}`) or a concept-constrained one hides that, so wrap +it with [`make_action`](user_guide.md#make_action-utility) to name the types +explicitly: + +```cpp +struct Counter { int n = 0; }; +auto inc = sml::make_action([](auto& c) { c.n++; }); // generic lambda -> Counter& +``` + ![CPP(BTN)](Run_Actions_Guards_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/actions_guards.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/q9nEfv9qv) +[▶ Run on Compiler Explorer](https://godbolt.org/z/qqGsrTGq3)   @@ -192,9 +202,9 @@ make_transition_table( ``` ![CPP(BTN)](Run_Transition_Table_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/transitions.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/jqz5frEP5) +[▶ Run on Compiler Explorer](https://godbolt.org/z/dErTW4jxb) ![CPP(BTN)](Run_eUML_Emulation_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/euml_emulation.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/KhqvGjKPP) +[▶ Run on Compiler Explorer](https://godbolt.org/z/W9Tbafna1)   @@ -239,9 +249,9 @@ make_transition_table( ``` ![CPP(BTN)](Run_Orthogonal_Regions_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/orthogonal_regions.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/Ma7sT74hq) +[▶ Run on Compiler Explorer](https://godbolt.org/z/rf9c76hxK) ![CPP(BTN)](Run_History_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/history.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/46erdGWxx) +[▶ Run on Compiler Explorer](https://godbolt.org/z/8G5on88nK)   @@ -305,9 +315,9 @@ sm.process_event(e1{}); ``` ![CPP(BTN)](Run_Hello_World_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/hello_world.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/W9zoarv69) +[▶ Run on Compiler Explorer](https://godbolt.org/z/9x4E1hnWP) ![CPP(BTN)](Run_Dependency_Injection_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/dependency_injection.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/zYvM1a6v4) +[▶ Run on Compiler Explorer](https://godbolt.org/z/KxxKbhY5s)   @@ -375,11 +385,11 @@ dispatch_event(event, event.type); // will call sm.process(game_over{}); ``` ![CPP(BTN)](Run_Hello_World_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/hello_world.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/W9zoarv69) +[▶ Run on Compiler Explorer](https://godbolt.org/z/9x4E1hnWP) ![CPP(BTN)](Run_Dispatch_Table_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/dispatch_table.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/6vs9E6Ynf) +[▶ Run on Compiler Explorer](https://godbolt.org/z/EKGKvWjdG) ![CPP(BTN)](Run_SDL2_Integration_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/sdl2.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/K4q6hhz5o) +[▶ Run on Compiler Explorer](https://godbolt.org/z/79zo4YxYM)   @@ -447,7 +457,7 @@ make_transition_table( ``` ![CPP(BTN)](Run_Error_Handling_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/error_handling.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/1G3P6ne7Y) +[▶ Run on Compiler Explorer](https://godbolt.org/z/e4Wj5858W)   @@ -481,7 +491,7 @@ assert(sm.is(X)); ``` ![CPP(BTN)](Run_Testing_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/testing.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/e9j19aTd7) +[▶ Run on Compiler Explorer](https://godbolt.org/z/4a7vK9o8a)   @@ -523,9 +533,9 @@ sm.process_event(my_event{}); // will call logger appropriately ``` ![CPP(BTN)](Run_Logging_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/logging.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/vheaGPWqT) +[▶ Run on Compiler Explorer](https://godbolt.org/z/raYvoWzjq) ![CPP(BTN)](Run_Plant_UML_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/plant_uml.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/4sb18vWG3) +[▶ Run on Compiler Explorer](https://godbolt.org/z/ssbY17Ks4)   diff --git a/doc/user_guide.md b/doc/user_guide.md index 04642793..2707fa8b 100644 --- a/doc/user_guide.md +++ b/doc/user_guide.md @@ -42,7 +42,7 @@ Requirements for transition. } ![CPP(BTN)](Run_Transitional_Example|https://raw.githubusercontent.com/boost-ext/sml/master/test/ft/errors/not_transitional.cpp) -[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/cnhP9Pf4o) +[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/6P7qf1qvv)   @@ -82,7 +82,7 @@ Requirements for the state machine. static_assert(configurable::value); ![CPP(BTN)](Run_Configurable_Example|https://raw.githubusercontent.com/boost-ext/sml/master/test/ft/errors/not_configurable.cpp) -[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/Pf64KjfG8) +[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/3ceoa8fP4)   @@ -120,7 +120,7 @@ Requirements for action and guards. static_assert(callable::value); ![CPP(BTN)](Run_Callable_Example|https://raw.githubusercontent.com/boost-ext/sml/master/test/ft/errors/not_callable.cpp) -[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/b7xP5brcE) +[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/Wv9rbG7ab)   @@ -167,9 +167,9 @@ Requirements for the dispatch table. static_assert(dispatchable::value); ![CPP(BTN)](Run_Dispatchable_Example|https://raw.githubusercontent.com/boost-ext/sml/master/test/ft/errors/not_dispatchable.cpp) -[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/abKhzTz1T) +[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/5cWcc98x1) ![CPP(BTN)](Run_SDL2_Integration_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/sdl2.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/K4q6hhz5o) +[▶ Run on Compiler Explorer](https://godbolt.org/z/79zo4YxYM)   @@ -234,11 +234,11 @@ Represents a state machine state. auto terminate_state = X; ![CPP(BTN)](Run_States_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/states.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/EfbfqqTYo) +[▶ Run on Compiler Explorer](https://godbolt.org/z/Y8b3he645) ![CPP(BTN)](Run_Composite_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/composite.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/9xPc56P36) +[▶ Run on Compiler Explorer](https://godbolt.org/z/zbojc8oKs) ![CPP(BTN)](Run_Orthogonal_Regions_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/orthogonal_regions.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/Ma7sT74hq) +[▶ Run on Compiler Explorer](https://godbolt.org/z/rf9c76hxK)   @@ -289,9 +289,9 @@ Represents a state machine event. auto my_int_event = event; ![CPP(BTN)](Run_Events_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/actions_guards.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/q9nEfv9qv) +[▶ Run on Compiler Explorer](https://godbolt.org/z/qqGsrTGq3) ![CPP(BTN)](Run_Error_Handling_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/error_handling.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/1G3P6ne7Y) +[▶ Run on Compiler Explorer](https://godbolt.org/z/e4Wj5858W)   @@ -338,7 +338,7 @@ Creates a transition table. }; ![CPP(BTN)](Run_Transition_Table_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/transitions.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/jqz5frEP5) +[▶ Run on Compiler Explorer](https://godbolt.org/z/dErTW4jxb)   @@ -425,11 +425,11 @@ Creates a State Machine. sm.visit_current_states([](auto state) { std::cout << state.c_str() << std::endl; }); ![CPP(BTN)](Run_Hello_World_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/hello_world.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/W9zoarv69) +[▶ Run on Compiler Explorer](https://godbolt.org/z/9x4E1hnWP) ![CPP(BTN)](Run_Dependency_Injection_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/dependency_injection.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/zYvM1a6v4) +[▶ Run on Compiler Explorer](https://godbolt.org/z/KxxKbhY5s) ![CPP(BTN)](Run_eUML_Emulation_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/euml_emulation.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/KhqvGjKPP) +[▶ Run on Compiler Explorer](https://godbolt.org/z/W9Tbafna1)   @@ -466,7 +466,7 @@ Additional State Machine configurations. sml::sm> sm{dep}; // explicit pool dependency for generic-lambda actions/guards ![CPP(BTN)](Run_Logging_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/logging.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/vheaGPWqT) +[▶ Run on Compiler Explorer](https://godbolt.org/z/raYvoWzjq)   @@ -512,7 +512,57 @@ Creates a state machine with testing capabilities. sm.is(X); ![CPP(BTN)](Run_Testing_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/testing.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/e9j19aTd7) +[▶ Run on Compiler Explorer](https://godbolt.org/z/4a7vK9o8a) + +  + +--- + +###make_action [utility] + +***Header*** + + #include + +***Description*** + +Wraps a template/generic/constrained callable as an action or guard, naming its +dependency (and event) types explicitly via ``. SML normally deduces the +parameters a callable wants by inspecting its `operator()`; a generic lambda +(`[](auto&){}`) or a concept-constrained one hides that information, so the wrong +type may be deduced. `make_action(f)` supplies the concrete signature +`f` should be called with. + +***Synopsis*** + + template + constexpr auto make_action(F f) noexcept; + +***Semantics*** + + make_action(generic_callable); + make_action(generic_callable); + +***Example*** + + struct trigger {}; + struct Counter { int n = 0; }; + + auto table = [] { + using namespace sml; + return make_transition_table( + // generic lambda: name the dependency explicitly so the right type is passed + *"idle"_s + event / make_action([](auto& c) { c.n++; }) = X + ); + }; + +Also works for guards and for callables taking the event plus dependencies: + + *"idle"_s + event[make_action([](auto& c) { return c.n == 0; })] = X + *"idle"_s + event / make_action( + [](const auto& e, auto& c) { /* ... */ }) = X + +[▶ Run on Compiler Explorer](https://godbolt.org/z/hraTaz8oo)   @@ -557,9 +607,9 @@ Creates a dispatch table to handle runtime events. dispatch_event(event, event.id); ![CPP(BTN)](Run_Dispatch_Table_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/dispatch_table.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/6vs9E6Ynf) +[▶ Run on Compiler Explorer](https://godbolt.org/z/EKGKvWjdG) ![CPP(BTN)](Run_SDL2_Integration_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/sdl2.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/K4q6hhz5o) +[▶ Run on Compiler Explorer](https://godbolt.org/z/79zo4YxYM)   From 3ec12e16eefe4574daf8a29259a25d242a17f8da Mon Sep 17 00:00:00 2001 From: Pavel Guzenfeld Date: Mon, 1 Jun 2026 16:47:03 +0300 Subject: [PATCH 8/9] docs: switch Godbolt links to thin client-side #include-from-URL Replace the inlined-header Godbolt links with thin ones that keep the example source intact and pull the header via Compiler Explorer's client-side #include-from-URL feature: #include CE fetches and pastes the header in the browser when the link is opened (this is NOT resolved by the compile API, which is why links are validated by compiling the fully-inlined equivalent instead). Sources shrink from ~3600 lines to the example itself (hello_world 101 lines, 1 include). dispatch_table.hpp does a relative #include "boost/sml.hpp" that CE's fetcher cannot resolve, so for dispatch_table and sdl2 the small utility header is inlined with its own sml.hpp include rewritten to the URL form (still no 3600-line header). All 25 examples + 4 error demos + make_action validated via their fully-inlined equivalents (GCC 14.2, -std=c++14; arduino c++20) before linking. gen_godbolt_links.sh updated to emit the thin form. --- doc/examples.md | 44 ++++++++++++++++---------------- doc/index.md | 8 +++--- doc/overview.md | 8 +++--- doc/scripts/gen_godbolt_links.sh | 40 ++++++++++++++++------------- doc/tutorial.md | 34 ++++++++++++------------ doc/user_guide.md | 38 +++++++++++++-------------- 6 files changed, 88 insertions(+), 84 deletions(-) diff --git a/doc/examples.md b/doc/examples.md index b6d1b7b3..e0848538 100644 --- a/doc/examples.md +++ b/doc/examples.md @@ -25,88 +25,88 @@ ###Hello World ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/hello_world.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/9x4E1hnWP) +[▶ Run on Compiler Explorer](https://godbolt.org/z/dq85hW4ab) ###Events ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/events.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/93joP5dv1) +[▶ Run on Compiler Explorer](https://godbolt.org/z/s816cG5j8) ###States ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/states.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/Y8b3he645) +[▶ Run on Compiler Explorer](https://godbolt.org/z/c9asGjYTr) ###Actions Guards ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/actions_guards.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/qqGsrTGq3) +[▶ Run on Compiler Explorer](https://godbolt.org/z/nehrdofPx) ###Transitions ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/transitions.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/dErTW4jxb) +[▶ Run on Compiler Explorer](https://godbolt.org/z/qr8qs78Ts) ###Defer/Process ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/defer_and_process.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/ah94rM966) +[▶ Run on Compiler Explorer](https://godbolt.org/z/T7YaW61en) ###Orthogonal Regions ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/orthogonal_regions.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/rf9c76hxK) +[▶ Run on Compiler Explorer](https://godbolt.org/z/vqGbsrqM3) ###Composite ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/composite.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/zbojc8oKs) +[▶ Run on Compiler Explorer](https://godbolt.org/z/5sYb9eGbe) ###History ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/history.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/8G5on88nK) +[▶ Run on Compiler Explorer](https://godbolt.org/z/Pvz6Y7vd4) ###Error handling ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/error_handling.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/e4Wj5858W) +[▶ Run on Compiler Explorer](https://godbolt.org/z/cGd7TnM1G) ###Logging ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/logging.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/raYvoWzjq) +[▶ Run on Compiler Explorer](https://godbolt.org/z/Tec7jz36r) ###Nested ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/nested.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/4ve1WfT9E) +[▶ Run on Compiler Explorer](https://godbolt.org/z/xd9PoEPdn) ###Testing ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/testing.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/4a7vK9o8a) +[▶ Run on Compiler Explorer](https://godbolt.org/z/oc73h5sY8) ###Runtime Dispatcher ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/dispatch_table.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/EKGKvWjdG) +[▶ Run on Compiler Explorer](https://godbolt.org/z/j5bMnobY9) ###eUML Emulation ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/euml_emulation.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/W9Tbafna1) +[▶ Run on Compiler Explorer](https://godbolt.org/z/n93Y5Mner) ###Dependencies ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/dependencies.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/c9W9hqEE5) +[▶ Run on Compiler Explorer](https://godbolt.org/z/afxWz4jq3) ###Data ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/data.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/v6vzcze4b) +[▶ Run on Compiler Explorer](https://godbolt.org/z/P4vn1dK9e) ###In-Place ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/in_place.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/GMcYd8Wva) +[▶ Run on Compiler Explorer](https://godbolt.org/z/r43fKbz6z) ###Dependency Injection ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/dependency_injection.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/KxxKbhY5s) +[▶ Run on Compiler Explorer](https://godbolt.org/z/1Pv6EaG7n) ###Arduino Integration ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/arduino.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/d8Goaha46) +[▶ Run on Compiler Explorer](https://godbolt.org/z/Kfba9GovG) ###SDL2 Integration ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/sdl2.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/79zo4YxYM) +[▶ Run on Compiler Explorer](https://godbolt.org/z/8heY58eE6) ###Plant UML Integration ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/example/plant_uml.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/ssbY17Ks4) +[▶ Run on Compiler Explorer](https://godbolt.org/z/8eT6aWsc9) diff --git a/doc/index.md b/doc/index.md index ae64013f..28178acf 100644 --- a/doc/index.md +++ b/doc/index.md @@ -46,13 +46,13 @@ to avoid it `[Boost].SML` may suit you! ###Real Life examples? ![CPP(BTN)](Run_SDL2_Integration_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/sdl2.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/79zo4YxYM) +[▶ Run on Compiler Explorer](https://godbolt.org/z/8heY58eE6) ![CPP(BTN)](Run_Plant_UML_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/plant_uml.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/ssbY17Ks4) +[▶ Run on Compiler Explorer](https://godbolt.org/z/8eT6aWsc9) ![CPP(BTN)](Run_Logging_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/logging.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/raYvoWzjq) +[▶ Run on Compiler Explorer](https://godbolt.org/z/Tec7jz36r) ![CPP(BTN)](Run_Testing_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/testing.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/4a7vK9o8a) +[▶ Run on Compiler Explorer](https://godbolt.org/z/oc73h5sY8)   diff --git a/doc/overview.md b/doc/overview.md index 7f5d8e72..29dfbe8c 100644 --- a/doc/overview.md +++ b/doc/overview.md @@ -93,19 +93,19 @@ sm.process_event(event{}); // thread safe call ***Not configurable*** ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/test/ft/errors/not_configurable.cpp) -[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/3ceoa8fP4) +[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/zehzezMoe) ***Not callable*** ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/test/ft/errors/not_callable.cpp) -[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/Wv9rbG7ab) +[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/fb8K6q4WK) ***Not transitional*** ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/test/ft/errors/not_transitional.cpp) -[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/6P7qf1qvv) +[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/3aWdcTanT) ***Not dispatchable*** ![CPP](https://raw.githubusercontent.com/boost-ext/sml/master/test/ft/errors/not_dispatchable.cpp) -[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/5cWcc98x1) +[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/984KoaP6x) [Boost.MSM-eUML]: http://www.boost.org/doc/libs/1_60_0/libs/msm/doc/HTML/ch03s04.html [Boost.MSM3-eUML2]: https://htmlpreview.github.io/?https://raw.githubusercontent.com/boostorg/msm/msm3/doc/HTML/ch03s05.html diff --git a/doc/scripts/gen_godbolt_links.sh b/doc/scripts/gen_godbolt_links.sh index c337274e..b5f6fad9 100755 --- a/doc/scripts/gen_godbolt_links.sh +++ b/doc/scripts/gen_godbolt_links.sh @@ -3,14 +3,17 @@ # Regenerate the "Run on Compiler Explorer" links embedded in the docs. # # Boost.SML is a single-header library that is NOT registered as a Compiler -# Explorer library, so each godbolt.org/z/ link inlines include/boost/sml.hpp -# (and utility/dispatch_table.hpp where used) ahead of the example source. -# Any `#define BOOST_SML_*` config macro is hoisted above the inlined header so -# it still takes effect (see data.cpp / BOOST_SML_CREATE_DEFAULT_CONSTRUCTIBLE_DEPS). +# Explorer library. Each godbolt.org/z/ link keeps the example source intact and +# pulls the header via Compiler Explorer's client-side "#include from URL" feature: +# #include +# CE fetches and pastes that header in the browser when the link is opened (it is +# NOT resolved by the compile API). dispatch_table.hpp itself does a relative +# `#include "boost/sml.hpp"`, which CE's fetcher cannot resolve, so for the two +# examples that use it (dispatch_table, sdl2) the small utility header is inlined +# with its own sml.hpp include rewritten to the URL form. # -# All examples are validated to compile (and execute) on GCC 14.2 at -std=c++14 -# before a short link is created. The error/* examples intentionally fail to -# compile and get compile-only links that show the diagnostic. +# The error/* examples intentionally fail to compile and get compile-only links +# that show the diagnostic. # # Requirements: bash, curl, jq. Run from the repository root. # Usage: @@ -22,19 +25,20 @@ cd "$(git rev-parse --show-toplevel)" GCC=g142 # Compiler Explorer GCC 14.2 STD_DEFAULT=c++14 # SML's minimum standard -HDR=include/boost/sml.hpp DT=include/boost/sml/utility/dispatch_table.hpp -INC_STRIP='#include[[:space:]]*[<"]boost/sml\.hpp[>"]|#include[[:space:]]*[<"]boost/sml/utility/dispatch_table\.hpp[>"]' -EX_STRIP="${INC_STRIP}|^[[:space:]]*#define[[:space:]]+BOOST_SML" +URL='https://raw.githubusercontent.com/boost-ext/sml/master/include/boost/sml.hpp' -assemble() { # -> self-contained translation unit on stdout - local ex="$1" - grep -E '^[[:space:]]*#define[[:space:]]+BOOST_SML' "$ex" || true # hoist config macros from example - cat "$HDR" - # dispatch_table.hpp: strip ONLY its sml.hpp include; KEEP its own #define/#undef of - # BOOST_SML_DETAIL_REQUIRES (sml.hpp #undef's that macro before this point) - grep -q 'utility/dispatch_table.hpp' "$ex" && grep -vE "$INC_STRIP" "$DT" - grep -vE "$EX_STRIP" "$ex" +assemble() { # -> thin url-include source on stdout + # Rewrite `#include ` to the URL form; for the dispatch_table.hpp + # include, inline that small header with its own sml.hpp include rewritten too. + awk -v url="$URL" -v dt="$DT" ' + /#include[ \t]*[<"]boost\/sml\.hpp[>"]/ { print "#include <" url ">"; next } + /#include[ \t]*[<"]boost\/sml\/utility\/dispatch_table\.hpp[>"]/ { + while ((getline l < dt) > 0) + if (l ~ /#include[ \t]*[<"]boost\/sml\.hpp[>"]/) print "#include <" url ">"; else print l + close(dt); next } + { print } + ' "$1" } shorten() { # -> godbolt short url diff --git a/doc/tutorial.md b/doc/tutorial.md index ba5f1f6f..365cc67c 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -75,11 +75,11 @@ assert(string("idle") == "idle"_s.c_str()); ``` ![CPP(BTN)](Run_Events_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/events.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/93joP5dv1) +[▶ Run on Compiler Explorer](https://godbolt.org/z/s816cG5j8) ![CPP(BTN)](Run_States_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/states.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/Y8b3he645) +[▶ Run on Compiler Explorer](https://godbolt.org/z/c9asGjYTr) ![CPP(BTN)](Run_Composite_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/composite.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/zbojc8oKs) +[▶ Run on Compiler Explorer](https://godbolt.org/z/5sYb9eGbe)   @@ -131,7 +131,7 @@ auto inc = sml::make_action([](auto& c) { c.n++; }); // generic lambda ``` ![CPP(BTN)](Run_Actions_Guards_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/actions_guards.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/qqGsrTGq3) +[▶ Run on Compiler Explorer](https://godbolt.org/z/nehrdofPx)   @@ -202,9 +202,9 @@ make_transition_table( ``` ![CPP(BTN)](Run_Transition_Table_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/transitions.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/dErTW4jxb) +[▶ Run on Compiler Explorer](https://godbolt.org/z/qr8qs78Ts) ![CPP(BTN)](Run_eUML_Emulation_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/euml_emulation.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/W9Tbafna1) +[▶ Run on Compiler Explorer](https://godbolt.org/z/n93Y5Mner)   @@ -249,9 +249,9 @@ make_transition_table( ``` ![CPP(BTN)](Run_Orthogonal_Regions_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/orthogonal_regions.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/rf9c76hxK) +[▶ Run on Compiler Explorer](https://godbolt.org/z/vqGbsrqM3) ![CPP(BTN)](Run_History_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/history.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/8G5on88nK) +[▶ Run on Compiler Explorer](https://godbolt.org/z/Pvz6Y7vd4)   @@ -315,9 +315,9 @@ sm.process_event(e1{}); ``` ![CPP(BTN)](Run_Hello_World_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/hello_world.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/9x4E1hnWP) +[▶ Run on Compiler Explorer](https://godbolt.org/z/dq85hW4ab) ![CPP(BTN)](Run_Dependency_Injection_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/dependency_injection.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/KxxKbhY5s) +[▶ Run on Compiler Explorer](https://godbolt.org/z/1Pv6EaG7n)   @@ -385,11 +385,11 @@ dispatch_event(event, event.type); // will call sm.process(game_over{}); ``` ![CPP(BTN)](Run_Hello_World_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/hello_world.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/9x4E1hnWP) +[▶ Run on Compiler Explorer](https://godbolt.org/z/dq85hW4ab) ![CPP(BTN)](Run_Dispatch_Table_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/dispatch_table.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/EKGKvWjdG) +[▶ Run on Compiler Explorer](https://godbolt.org/z/j5bMnobY9) ![CPP(BTN)](Run_SDL2_Integration_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/sdl2.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/79zo4YxYM) +[▶ Run on Compiler Explorer](https://godbolt.org/z/8heY58eE6)   @@ -457,7 +457,7 @@ make_transition_table( ``` ![CPP(BTN)](Run_Error_Handling_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/error_handling.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/e4Wj5858W) +[▶ Run on Compiler Explorer](https://godbolt.org/z/cGd7TnM1G)   @@ -491,7 +491,7 @@ assert(sm.is(X)); ``` ![CPP(BTN)](Run_Testing_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/testing.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/4a7vK9o8a) +[▶ Run on Compiler Explorer](https://godbolt.org/z/oc73h5sY8)   @@ -533,9 +533,9 @@ sm.process_event(my_event{}); // will call logger appropriately ``` ![CPP(BTN)](Run_Logging_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/logging.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/raYvoWzjq) +[▶ Run on Compiler Explorer](https://godbolt.org/z/Tec7jz36r) ![CPP(BTN)](Run_Plant_UML_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/plant_uml.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/ssbY17Ks4) +[▶ Run on Compiler Explorer](https://godbolt.org/z/8eT6aWsc9)   diff --git a/doc/user_guide.md b/doc/user_guide.md index 2707fa8b..ac754752 100644 --- a/doc/user_guide.md +++ b/doc/user_guide.md @@ -42,7 +42,7 @@ Requirements for transition. } ![CPP(BTN)](Run_Transitional_Example|https://raw.githubusercontent.com/boost-ext/sml/master/test/ft/errors/not_transitional.cpp) -[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/6P7qf1qvv) +[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/3aWdcTanT)   @@ -82,7 +82,7 @@ Requirements for the state machine. static_assert(configurable::value); ![CPP(BTN)](Run_Configurable_Example|https://raw.githubusercontent.com/boost-ext/sml/master/test/ft/errors/not_configurable.cpp) -[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/3ceoa8fP4) +[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/zehzezMoe)   @@ -120,7 +120,7 @@ Requirements for action and guards. static_assert(callable::value); ![CPP(BTN)](Run_Callable_Example|https://raw.githubusercontent.com/boost-ext/sml/master/test/ft/errors/not_callable.cpp) -[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/Wv9rbG7ab) +[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/fb8K6q4WK)   @@ -167,9 +167,9 @@ Requirements for the dispatch table. static_assert(dispatchable::value); ![CPP(BTN)](Run_Dispatchable_Example|https://raw.githubusercontent.com/boost-ext/sml/master/test/ft/errors/not_dispatchable.cpp) -[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/5cWcc98x1) +[▶ See the compile error on Compiler Explorer](https://godbolt.org/z/984KoaP6x) ![CPP(BTN)](Run_SDL2_Integration_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/sdl2.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/79zo4YxYM) +[▶ Run on Compiler Explorer](https://godbolt.org/z/8heY58eE6)   @@ -234,11 +234,11 @@ Represents a state machine state. auto terminate_state = X; ![CPP(BTN)](Run_States_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/states.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/Y8b3he645) +[▶ Run on Compiler Explorer](https://godbolt.org/z/c9asGjYTr) ![CPP(BTN)](Run_Composite_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/composite.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/zbojc8oKs) +[▶ Run on Compiler Explorer](https://godbolt.org/z/5sYb9eGbe) ![CPP(BTN)](Run_Orthogonal_Regions_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/orthogonal_regions.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/rf9c76hxK) +[▶ Run on Compiler Explorer](https://godbolt.org/z/vqGbsrqM3)   @@ -289,9 +289,9 @@ Represents a state machine event. auto my_int_event = event; ![CPP(BTN)](Run_Events_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/actions_guards.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/qqGsrTGq3) +[▶ Run on Compiler Explorer](https://godbolt.org/z/nehrdofPx) ![CPP(BTN)](Run_Error_Handling_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/error_handling.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/e4Wj5858W) +[▶ Run on Compiler Explorer](https://godbolt.org/z/cGd7TnM1G)   @@ -338,7 +338,7 @@ Creates a transition table. }; ![CPP(BTN)](Run_Transition_Table_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/transitions.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/dErTW4jxb) +[▶ Run on Compiler Explorer](https://godbolt.org/z/qr8qs78Ts)   @@ -425,11 +425,11 @@ Creates a State Machine. sm.visit_current_states([](auto state) { std::cout << state.c_str() << std::endl; }); ![CPP(BTN)](Run_Hello_World_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/hello_world.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/9x4E1hnWP) +[▶ Run on Compiler Explorer](https://godbolt.org/z/dq85hW4ab) ![CPP(BTN)](Run_Dependency_Injection_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/dependency_injection.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/KxxKbhY5s) +[▶ Run on Compiler Explorer](https://godbolt.org/z/1Pv6EaG7n) ![CPP(BTN)](Run_eUML_Emulation_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/euml_emulation.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/W9Tbafna1) +[▶ Run on Compiler Explorer](https://godbolt.org/z/n93Y5Mner)   @@ -466,7 +466,7 @@ Additional State Machine configurations. sml::sm> sm{dep}; // explicit pool dependency for generic-lambda actions/guards ![CPP(BTN)](Run_Logging_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/logging.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/raYvoWzjq) +[▶ Run on Compiler Explorer](https://godbolt.org/z/Tec7jz36r)   @@ -512,7 +512,7 @@ Creates a state machine with testing capabilities. sm.is(X); ![CPP(BTN)](Run_Testing_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/testing.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/4a7vK9o8a) +[▶ Run on Compiler Explorer](https://godbolt.org/z/oc73h5sY8)   @@ -562,7 +562,7 @@ Also works for guards and for callables taking the event plus dependencies: *"idle"_s + event / make_action( [](const auto& e, auto& c) { /* ... */ }) = X -[▶ Run on Compiler Explorer](https://godbolt.org/z/hraTaz8oo) +[▶ Run on Compiler Explorer](https://godbolt.org/z/Ge84qGM5z)   @@ -607,9 +607,9 @@ Creates a dispatch table to handle runtime events. dispatch_event(event, event.id); ![CPP(BTN)](Run_Dispatch_Table_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/dispatch_table.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/EKGKvWjdG) +[▶ Run on Compiler Explorer](https://godbolt.org/z/j5bMnobY9) ![CPP(BTN)](Run_SDL2_Integration_Example|https://raw.githubusercontent.com/boost-ext/sml/master/example/sdl2.cpp) -[▶ Run on Compiler Explorer](https://godbolt.org/z/79zo4YxYM) +[▶ Run on Compiler Explorer](https://godbolt.org/z/8heY58eE6)   From 1abfbbdb08e6a836b6b555cae98f9519220519d3 Mon Sep 17 00:00:00 2001 From: Pavel Guzenfeld Date: Mon, 1 Jun 2026 17:37:00 +0300 Subject: [PATCH 9/9] docs(sml.hpp): comment the new public API (polish, no functional change) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the spirit of #697, add high-level comments explaining the v1.2.0 additions so contributors don't have to reverse-engineer them: - make_action / action_wrap — why generic/constrained callables need an explicit signature for function_traits to read (#629) - clear_defer — counterpart to defer; clear the defer queue on scope exit (#643) - explicit_deps policy + get_explicit_deps — why a dep reached only via a generic lambda is dropped from the pool, and how sml::deps widens it (#437) - flush_queue (impl + public entry) — draining events queued after process_event returned, e.g. from an async back::process<> handle (#456) Comments only; full suite 69/69 on GCC 14 (C++17). --- include/boost/sml.hpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/include/boost/sml.hpp b/include/boost/sml.hpp index 0905cbce..bb8900de 100644 --- a/include/boost/sml.hpp +++ b/include/boost/sml.hpp @@ -1046,6 +1046,14 @@ template constexpr auto wrap(T callback) { return aux::zero_wrapper{callback}; } +// make_action(f) — adapt a callable whose parameter types SML cannot +// deduce (#629). SML normally reads the wanted dep/event types off a callable's +// operator(); a *generic* lambda ([](auto&){}) or a concept-constrained one +// (`[](HasFoo auto&){}`) exposes only a template, so function_traits has nothing +// concrete to read and picks the wrong type. action_wrap pins a fixed +// operator(TDeps...) in front of `f`, giving SML the explicit signature to +// inspect while still forwarding to the original callable. TDeps are listed in +// call order, e.g. make_action([](auto& e, auto& d){...}). template struct action_wrap { constexpr explicit action_wrap(F f) : f_(f) {} @@ -1753,6 +1761,12 @@ template struct logger : aux::pair> { using type = T; }; +// explicit_deps policy (#437) — force Ts into the dependency pool even +// when no action/guard *signature* names them. The pool is built from the dep +// types that appear in callable signatures; a dep reached only through a generic +// lambda via `aux::get(deps)` never appears in any signature, so it would +// be dropped from the pool and the static_cast to pool_type would fail to +// compile. sml::deps widens the pool to include these types explicitly. struct explicit_deps_policy__ {}; template struct explicit_deps : aux::pair> {}; @@ -2027,6 +2041,11 @@ struct sm_impl : aux::conditional_t>{}, events_t{})); return handled && queued_handled; } + // flush_queue — drain events left in the process queue (#456). process_event + // already drains its own queue before returning; this is for events pushed + // *after* it returned, e.g. from an async callback holding a back::process<> + // handle. Runs anonymous transitions to a fixpoint, then the queued events. + // No-op when the queue is empty; takes the thread_safe lock like process_event. template constexpr void flush_queue(TDeps &d, TSubs &subs) { const auto lock = thread_safety_.create_lock(); @@ -2328,6 +2347,8 @@ struct sm_impl : aux::conditional_t struct get_explicit_deps { using type = aux::type_list<>; @@ -2392,6 +2413,7 @@ class sm { constexpr bool process_event(const TEvent &event) { return aux::get>(sub_sms_).process_event(unexpected_event<_, TEvent>{event}, deps_, sub_sms_); } + // Public entry point: drain events queued after process_event returned (#456). constexpr void flush_queue() { aux::get>(sub_sms_).flush_queue(deps_, sub_sms_); } @@ -2819,6 +2841,10 @@ struct defer : action_base { } } }; +// clear_defer — the counterpart to `defer` (#643): drop every event currently +// held in the defer queue. Typical use is on the way out of a composite/sub-SM +// so events deferred during that scope do not resurface after re-entry. No-op +// when nothing is deferred; requires a defer_queue policy. struct clear_defer : action_base { template constexpr void operator()(const TEvent &, Tsm &sm, TDeps &, TSubs &) const { @@ -2839,6 +2865,7 @@ using defer_queue = back::policies::defer_queue; template