Readit News logoReadit News
Posted by u/zigrazor 8 months ago
Show HN: CXXStateTree – A modern C++ library for hierarchical state machinesgithub.com/ZigRazor/CXXSt...
Hi HN!

I've built [CXXStateTree](https://github.com/ZigRazor/CXXStateTree), a modern C++ header-only library to create hierarchical state machines with clean, intuitive APIs.

It supports: - Deeply nested states - Entry/exit handlers - State transitions with guards and actions - Asynchronous transitions with `co_await` (C++20 coroutines) - Optional runtime type identification for flexibility

It's ideal for complex control logic, embedded systems, games, robotics, and anywhere you'd use a finite state machine.

I’d love feedback, use cases, or contributions from the community!

Repo: https://github.com/ZigRazor/CXXStateTree

jeffreygoesto · 8 months ago
Nice and compact. I only wound have two nitpicks:

The Readme sais "zero heap allocations" but the code uses list and unordered map and moves, did you mean "zero allocations after state tree building"?

Also for embedded it would be useful to separate all in/out, dot export etc. to a second library that you can omit on small targets.

zigrazor · 8 months ago
yes, it means "zero allocations after state tree building". Thank you for the suggestions, I think we could separate target with compilation switch. If you want you can open an issue on the repo. Thank you so much
rpaddock · 8 months ago
In some Embedded areas where safety is of high concern following the Motor Industry Software Reliability Association (MISRA) guidelines is a requirement.

There may be no heap at all and memory must be pre-allocated at system initialization. Otherwise CXXStateTree sounds like it could be very useful in my Embedded devices, which rarely have enough Flash or RAM space, which is the nature of the work.

https://misra.org.uk

wangii · 8 months ago
how is it better than https://github.com/boost-ext/sml ?

there are about 1 million c++ state machines, and sml happens to be the best, or one of them. how does yours differentiate?

canyp · 8 months ago
I was about to complain about the use of strings in both libraries, both for the lack of type safety as well as the possible runtime allocation, but then I looked at the assembly for the sml example and there are no strings in the binary other than the obvious "send" one.

What exactly happened there? It looks like make_transition_table() is doing some serious magic. Or are the state transitions evaluated at compile-time given that there is no input in the example, and then the transition table gets compiled out?

Anyway, I think it would help OP's library to have some assembly output in the readme as well.

aw1621107 · 8 months ago
Looks like SML is using user-defined literals [0, 1] to effectively pre-process the string literal into state/event objects. Looks like the string itself is turned into a template parameter in the process and I believe those shouldn't show up in the compiled code (maybe unless there's some mangling-related thing going on?)

[0]: https://en.cppreference.com/w/cpp/language/user_literal.html

[1]: https://github.com/boost-ext/sml/blob/f232328b49adf708737bef...

baymotion · 8 months ago
Related idea for those using python: https://github.com/baymotion/smax.
zigrazor · 8 months ago
I want to create a python binding with PyBind11 and create a simple interface with a very good performance for Embedded systems
dgan · 8 months ago
i am by no means a C++ expert, but isn't "pragma once" frowned upon?
kookamamie · 8 months ago
No, it is the way. Edit: no one has time for inventing unique names for include guards.
hdhdjd · 8 months ago
Does anyone write those by hand anyway in any kind of project the size where it would matter?

#pragma once is broken by design

motorest · 8 months ago
> No, it is the way.

No, this is completely wrong. Pragma once is non-standard compiler directive. It might be supported by some compilers such as msvc but technically it is not even C++.

There are only two options: include guards, and modules.

alt187 · 8 months ago
All terrestrial compilers support `#pragma once`.

In the C++ community (as lots of other things are), rejecting `#pragma once` is a long-standing tradition of worshipping the decaying body of prehistoric compilers for

It's unclear what benefits this approach has achieved, but don't disturb it, or else.

benreesman · 8 months ago
You'll see a fairly even split amongst S-tier, "possibly headed for standardization" level libraries. I'd say there's a skew for `#ifndef` in projects that are more "aspires to the standard library" and for `#pragma once` in projects that are more focused on like a very specific vertical.

`#pragma once` seems to be far preferred for internal code, there's an argument for being strictly conforming if you're putting out a library. I've converted stuff to `#ifndef` before sharing it, but I think heavy C++ people usually type `#pragma once` in the privacy of their own little repository.

- `spdlog`: `#pragma once` https://github.com/gabime/spdlog/blob/v1.x/include/spdlog/as...

- `absl`: `#ifndef` https://github.com/abseil/abseil-cpp/blob/master/absl/base/a...

- `zpp_bits`: `#ifndef` https://github.com/eyalz800/zpp_bits/blob/main/zpp_bits.h

- `stringzilla` `#ifndef` https://github.com/ashvardanian/StringZilla/blob/main/includ...

sam_bishop · 8 months ago
I've avoided #pragma once because of reports that it slows down gcc/g++: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58770

But given that I haven't seen any mention of that issue in other comments, I wonder if it really is an issue.

zigrazor · 8 months ago
please someone open an Issue on the repo(https://github.com/ZigRazor/CXXStateTree/issues), to substitute the #pragma once with the more classic include guards with the motivation explained in the comment. Thank you
happyweasel · 8 months ago
vcpkg it
zigrazor · 8 months ago
You can open an Issue on that on the repo (https://github.com/ZigRazor/CXXStateTree/issues) so we can track these changes.

Another idea is to create a Python binding with a release of a package