-
-
Notifications
You must be signed in to change notification settings - Fork 393
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature request: support for moving the FSM #884
Comments
the state list is dynamically build in runtime. Can we not just call |
@jwellbelove I suppose we can do that, given that we have a move constructor. Actually, it would be enough to support the usecase to have a direct way of setting a state (example -> make With that primitive, to move the FSM I could:
// I can see the horror on your face! I promise it's not that bad... While I can't go into details, imagine making a tool to generate a custom interpreter, effectively building a state machine. Multiply that that with limited memory in deeply embedded device. |
Do you actually need a 'fresh' FSM if you are just moving it anyway? A move implies that the old FSM is not going to be used any more (I may be missing a fundamental aspect of what you want to do). Is there a reason you can't just replace the state list in the current FSM + adjustments or does the old FSM continue to be actively in use? It's getting close to 9pm here, so I'm off to eat dinner and watch the telly. |
I'm trying to do a simple move, exactly as you describred.
Well, move construction kind of implies that you have a fresh FSM that you move old state into
Yes, correct
Currently - there is no way for me to directly set the previous state after replacing the state list Note, that I am trying to both move the FSM and the state list. Think of an object like that: class werid : public etl::fsm {
etl::vector<etl::ifsm_state *, 8192U> m_states;
public:
weird() : etl::fsm{0U}, m_states{} {
build_state_vector();
set_states(m_states.begin(), m_states.size());
start(true);
}
weird(const weird&) = delete;
weird& operator=(const weird&) = delete;
weird(weird&& other) : etl::fsm{0U}, m_states{etl::move(other.m_states)} {
// TODO: What goes here ?
}
weird& operator=(weird&& other) {
m_states = etl::move(other.m_states);
// TODO: What goes here ?
return *this;
}
}; |
I just want to make sure I understand correctly. Do you just want to be able to move the FSM along with the pointer to the state list and the current state, leaving the old FSM in a 'not started' 'no state list' condition?
This change may also be applicable to the |
Ah, I see I forgotten an important detail in my example - the addresses of the states change. I'm sorry for that, I must have been distracted. class werid : public etl::fsm {
etl::vector<ThingsThatInheritFrom_etl_ifsm_state, 8192U> m_state_values;
etl::vector<etl::ifsm_state *, 8192U> m_states;
public:
weird(weird&& other) : etl::fsm{0U}, m_state_values{etl::move(other.m_state_values)}, m_states{} {
rebuild_states_vector();
// TODO: What goes here ?
}
weird& operator=(weird&& other) {
m_state_values = etl::move(other.m_state_values);
m_states.clear();
rebuild_states_vector();
// TODO: What goes here ?
return *this;
}
// Rest can be the same/similar I guess
private:
void rebuild_states_vector() {
for (etl::ifsm_state& state : m_state_values) {
m_states.push_back(&state);
}
}
}; The addresses of the state values are changing, however their effective value is staying constant. Coming to your snippet: weird fsm1;
weird.set_states(<some state list>);
weird.start();
weird fsm2(etl::move(fsm1));
/// I don't care about the state of fsm1 after the move as it is UB to use it anyway based on move-semantics
/// Also, the destructor of fsm doesn't do anything special.
// fsm1 has no state list defined.
// fsm1 is not started.
/// That would be sensible state after the move
// fsm2 is using fsm1's state list.
// fsm2 is started and is in the state that fsm1 was in.
/// Now the tricky part is, changing the state list to account for the fact that the addresses of the concrete states have changed As I said, being able to specify the start state would be enough I think, given this example it would properly move the fsm1 to fsm2, right? weird(weird&& other) : etl::fsm{0U}, m_state_values{}, m_states{} {
const auto state_id = other.get_state_id();
// Note moving after calling the state ID, because get_state_id uses the old pointer to one of the states, which may be UB after moving it
m_state_values = etl::move(other.m_state_values);
rebuild_states_vector();
start(false, state_id);
// now we are in the same state as the other
// the other is considered moved-out-of so using it is UB, although in this scenario we have effectively made a copy of it
// (if moving m_state_values is equivalent to copying it)
} It might not be enough for hfsm, I'm not sure - I'm not using that here. // Moving the storage of an ext container would be quite problematic, unless the types are trivially copiable/movable. Also, I don't think it's quite as useful to move the storage data of an |
Moving the storage of a I'm out today (looking for a new(er) car), but I'll have a look at the other points when I get back later. |
What you're describing is moving the _ext container itself, not the storage.
Good luck with that! |
Yes, I was talking about 'move' as in
|
@jwellbelove are you awaiting some feedback from me here? I think we're currently waiting on you, but I might be wrong.
|
Sorry, I got side tracked into looking at move constructors for other containers. You said Now the tricky part is, changing the state list to account for the fact that the addresses of the concrete states have changed The state list for |
Sorry, got sidetracked as well.
Yes, the concrete states are also moving. Coming back to my example, the class that is getting moved is: class werid : public etl::fsm {
etl::vector<ThingsThatInheritFrom_etl_ifsm_state, 8192U> m_state_values;
etl::vector<etl::ifsm_state *, 8192U> m_states;
/* ... */
}; |
Hi @jwellbelove, did you get sidetracked again? 😄 As I said originally, I'm fine with doing the actual implementation, but let's agree first on what that implementation should entail. |
I didn't get sidetracked this time, well I did, sort of. I've been on holiday in Cumbria and Scotland for the last 10 days. |
First of all - thanks for this project and your work here!
For my use case I would need to have the FSM instance be movable and have its state list also movable (i.e. replacing with a different address that contains the same information). The reasons are quite complex, but boiling down to me trying to (ab)use the framework in ways that were probably not quite intended - the state list is dynamically build in runtime.
Currently fsm is not movable, I suppose because it could allow for dangerous behavior when people move the FSM and the location of the state array. Though that can probably be acceptable with proper documentation, or by making a non-standard copy constructor that takes in something like
i_know_this_is_dangerours_t
as a token.Moving of state list is more difficult, but could be achieved if during the transition we can still access the old list (as as in dependent-class move constructor). For that usecase you could provide a
move_states
function that will:set_states
p_state
to new address of saved state idMaybe it could even be part of the new copy constructor?
I know this sounds convoluted, there probably is a better way of doing it - I'm open for ideas.
I can implement this, once we reach an understanding of what would be acceptable way for you of achieving the goal.
The text was updated successfully, but these errors were encountered: