andrew-gresyk / hfsm Goto Github PK
View Code? Open in Web Editor NEWHierarchical Finite State Machine Framework
License: MIT License
Hierarchical Finite State Machine Framework
License: MIT License
Question:
Is there a best-practice for indicating that a certain action is not allowed?
My intuition is to throw an exception from the react()
method if that action is not allowed for a particular state. Will that cause problems?
This would be very helpful for debugging run-time issues.
When is the substitute()
method called on a State implementation?
From reading through the tests, it looks like it's called on a state before
enter()
on the new state, and before leave()
is called on the previous state.
Is that always the case? Just want to make sure I understand that correctly.
When would one typically want to implement that method?
Thanks!
#include <new>
#define HFSM_ENABLE_LOG_INTERFACE
#include "machine_single.hpp"
struct Logger : hfsm::LoggerInterface {
void record(const std::type_index&, const char* const stateName, const Method,
const char* const methodName) override {}
};
struct Context {};
using M = hfsm::Machine<Context>;
struct TestEvent {};
struct TestState : M::Base {
void react(const TestEvent&, Control&, Context&) {}
using M::Base::react;
};
using FsmNtag = M::PeerRoot<TestState>;
int main(int argc, char const* argv[]) {
Context context;
Logger logger;
FsmNtag machine(context, &logger);
machine.react(TestEvent{});
return 0;
}
>clang++ -std=c++14 .\bug.cpp
In file included from .\bug.cpp:4:
./machine_single.hpp:2127:49: error: use 'template' keyword to treat 'react' as a dependent template name
HFSM_IF_LOGGER(if (logger) log<decltype(&Head::react<TEvent>), LoggerInterface::Method::React>(*logger));
^
template
./machine_single.hpp:912:31: note: expanded from macro 'HFSM_IF_LOGGER'
#define HFSM_IF_LOGGER(...) __VA_ARGS__
^
1 error generated.
/home/kevin/a17/pkg/linux/include/hfsm/machine.inl: In member function ‘void hfsm::M<TContext, TMaxSubstitutions>::_O< <template-parameter-2-1>, <template-parameter-2-2> >::Sub<TN, TI>::wideForwardRequest(unsigned int, enum hfsm::M<TContext, TMaxSubstitutions>::Transition::Type)’:
/home/kevin/a17/pkg/linux/include/hfsm/machine.inl:1146:6: error: ‘prong’ was not declared in this scope
if (prong == ProngIndex)
I cant' compile codes of example well by vs 17 on the windows 10.
These are some error information as following.
main.cpp
1>d:\myfile\hfsm-master\include\hfsm\detail\wrap.hpp(49): error C2338:
1>d:\myfile\hfsm-master\include\hfsm\detail\type_info.hpp(14): note: 参见对正在编译的 类 模板 实例化 "hfsm::detail::Wrapstd::type_index" 的引用
1>streetlight.cpp
1>d:\myfile\hfsm-master\include\hfsm\detail\wrap.hpp(49): error C2338:
1>d:\myfile\hfsm-master\include\hfsm\detail\type_info.hpp(14): note: 参见对正在编译的 类 模板 实例化 "hfsm::detail::Wrapstd::type_index" 的引用
1>正在生成代码...
1>已完成生成项目“HFSM-vs.vcxproj”的操作 - 失败。
Reproduced on Ubuntu 16.04 and 17.10.
To reproduce:
$ mkdir build && cd build
$ cmake ..
$ make
$ ./hfsm_test
hfsm_test: ../test/../hfsm/machine.inl:1671: void hfsm::M<TContext, TMaxSubstitutions>::_R< <template-parameter-2-1> >::requestScheduled(hfsm::M<TContext, TMaxSubstitutions>::Transition) [with TApex = hfsm::M<Context, 4>::_C<hfsm::M<Context, 4>::_B<hfsm::M<Context, 4>::Bare>, hfsm::M<Context, 4>::_C<A, A_1, hfsm::M<Context, 4>::_C<A_2, A_2_1, A_2_2> >, hfsm::M<Context, 4>::_O<B, hfsm::M<Context, 4>::_C<B_1, B_1_1, B_1_2>, hfsm::M<Context, 4>::_C<B_2, B_2_1, B_2_2> > >; TContext = Context; unsigned int TMaxSubstitutions = 4]: Assertion `!forksFork.activeType' failed.
Aborted (core dumped)
Backtrace from gdb:
#0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
#1 0x00007ffff7490f5d in __GI_abort () at abort.c:90
#2 0x00007ffff7486f17 in __assert_fail_base (fmt=<optimized out>,
assertion=assertion@entry=0x555555590ae9 "!forksFork.activeType",
file=file@entry=0x5555555909db "../test/../hfsm/machine.inl", line=line@entry=1671,
function=function@entry=0x555555595720 <hfsm::M<Context, 4u>::_R<hfsm::M<Context, 4u>::_C<hfsm::M<Context, 4u>::_B<hfsm::M<Context, 4u>::Bare>, hfsm::M<Context, 4u>::_C<A, A_1, hfsm::M<Context, 4u>::_C<A_2, A_2_1, A_2_2> >, hfsm::M<Context, 4u>::_O<B, hfsm::M<Context, 4u>::_C<B_1, B_1_1, B_1_2>, hfsm::M<Context, 4u>::_C<B_2, B_2_1, B_2_2> > > >::requestScheduled(hfsm::M<Context, 4u>::Transition)::__PRETTY_FUNCTION__> "void hfsm::M<TContext, TMaxSubstitutions>::_R< <template-parameter-2-1> >::requestScheduled(hfsm::M<TContext, TMaxSubstitutions>::Transition) [with TApex = hfsm::M<Context, 4>::_C<hfsm::M<Context, 4>:"...) at assert.c:92
#3 0x00007ffff7486fc2 in __GI___assert_fail (assertion=0x555555590ae9 "!forksFork.activeType",
file=0x5555555909db "../test/../hfsm/machine.inl", line=1671,
function=0x555555595720 <hfsm::M<Context, 4u>::_R<hfsm::M<Context, 4u>::_C<hfsm::M<Context, 4u>::_B<hfsm::M<Context, 4u>::Bare>, hfsm::M<Context, 4u>::_C<A, A_1, hfsm::M<Context, 4u>::_C<A_2, A_2_1, A_2_2> >, hfsm::M<Context, 4u>::_O<B, hfsm::M<Context, 4u>::_C<B_1, B_1_1, B_1_2>, hfsm::M<Context, 4u>::_C<B_2, B_2_1, B_2_2> > > >::requestScheduled(hfsm::M<Context, 4u>::Transition)::__PRETTY_FUNCTION__> "void hfsm::M<TContext, TMaxSubstitutions>::_R< <template-parameter-2-1> >::requestScheduled(hfsm::M<TContext, TMaxSubstitutions>::Transition) [with TApex = hfsm::M<Context, 4>::_C<hfsm::M<Context, 4>:"...) at assert.c:101
#4 0x00005555555807c5 in hfsm::M<Context, 4u>::_R<hfsm::M<Context, 4u>::_C<hfsm::M<Context, 4u>::_B<hfsm::M<Context, 4u>::Bare>, hfsm::M<Context, 4u>::_C<A, A_1, hfsm::M<Context, 4u>::_C<A_2, A_2_1, A_2_2> >, hfsm::M<Context, 4u>::_O<B, hfsm::M<Context, 4u>::_C<B_1, B_1_1, B_1_2>, hfsm::M<Context, 4u>::_C<B_2, B_2_1, B_2_2> > > >::requestScheduled (
this=0x7fffffffd580, request=...) at ../test/../hfsm/machine.inl:1671
#5 0x000055555557fa45 in hfsm::M<Context, 4u>::_R<hfsm::M<Context, 4u>::_C<hfsm::M<Context, 4u>::_B<hfsm::M<Context, 4u>::Bare>, hfsm::M<Context, 4u>::_C<A, A_1, hfsm::M<Context, 4u>::_C<A_2, A_2_1, A_2_2> >, hfsm::M<Context, 4u>::_O<B, hfsm::M<Context, 4u>::_C<B_1, B_1_1, B_1_2>, hfsm::M<Context, 4u>::_C<B_2, B_2_1, B_2_2> > > >::processRequests (
this=0x7fffffffd580) at ../test/../hfsm/machine.inl:1571
#6 0x000055555557cdfe in hfsm::M<Context, 4u>::_R<hfsm::M<Context, 4u>::_C<hfsm::M<Context, 4u>::_B<hfsm::M<Context, 4u>::Bare>, hfsm::M<Context, 4u>::_C<A, A_1, hfsm::M<Context, 4u>::_C<A_2, A_2_1, A_2_2> >, hfsm::M<Context, 4u>::_O<B, hfsm::M<Context, 4u>::_C<B_1, B_1_1, B_1_2>, hfsm::M<Context, 4u>::_C<B_2, B_2_1, B_2_2> > > >::update (
this=0x7fffffffd580) at ../test/../hfsm/machine.inl:1536
#7 0x000055555557ad9a in main () at ../test/main.cpp:533
Great little lib! The docs should be updated since Time was removed.
I ran across your library and talks, but I'm still having a hard time connecting the dots. It would be nice if some of the examples from your talks were available as more fully worked examples... and some docs might be nice. ;-)
Is there any documentation beyond that in the README.md?
substitute()
method.test/main.cpp
without any built-in support or introductory documentation how to extend states properly. This would be helped by a more-fully worked player character example via issue #11, of course... but I wonder if perhaps some of those extensions are worth providing in the library.It would be nice if there was a "pre-compiled" version of the library into a single header file (with license included at the top). This would enable playing around with examples of using the library in an online sandbox (other than compiler explorer, which I see can include HFSM). Wandbox lets you create as many headers as you like, but building the complete set for HFSM would be tedious. It does include some header-only libs, but not yet HFSM, and that's not a general solution for the many other useful online sandboxes. The current many-file version is good for maintenance and implementation-hiding, but prohibits these other uses.
In short, could you make an example like this wandbox session "just work"?
FYI, it seems that the ned14/pcpp project is intended for this use case, and one example usage can be found here.
I often need to transition from state A to state B in response to an action. You do this by implementing the react()
method on state A for the given action. However, often the information in the action is needed by state B. Currently, the way to accomplish this is to pass the data to state B is to set a member variable in the Context object.
struct SaveAction {
std::string file_to_save;
}
struct IdleState : M::Bare {
void react(const SaveAction &action, M::Control &control, Context &context) {
context.file_to_save = action.file_to_save;
control.changeTo<SavingState>();
}
}
struct SavingState : M::Bare {
void enter(Context &context) {
// It would be nice to have a better way of accessing file_to_save.
saveFile(context.file_to_save);
}
}
This works, but I'm finding that I have a lot of these member variables in my Context that are specific to one state transitioning to another. It would be nice if my IdleState above had some way of passing the file_to_save (or the SaveAction) to the SavingState.
Is there a better way for me to handle this situation? Perhaps I could think differently about how the states are structured?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.