Go to the source code of this file.
Data Structures | |
struct | state |
C++ version of state machine. More... | |
Defines | |
#define | state_auto(state) state state = { _state_begin, _state_begin };\ |
Declare a state machine as static or global data May appear in global scope or in structure body. | |
#define | state_init(state) { state.line = state.loop = _state_begin; } |
Initialize or reset a state machine. | |
#define | state_destroy(state) { state.line = state.loop = _state_end; } |
Finish a state machine off. | |
#define | state_signal(state, signal) { state.line = _state_signal(signal); } |
Wake up state machine, if it was 'finished', and jump to a signal for its next cycle. | |
#define | state_begin(state) |
The beginning of a state machine block in cycle. | |
#define | state_end(state, onbadstate) |
This is the end state, matching the state_begin(). | |
#define | state_yield(state) |
This will yield to main loop and start on the next piece of state when we get back. | |
#define | state_repeat(state) return |
This will yield and repeat the present state from the beginning. | |
#define | state_wait(state, condition) |
This will poll and not proceed to next state until 'condition' returns non-zero. | |
#define | state_sleep(state) |
This will sit and wait until some signal occurs to wake it. | |
#define | state_setloop(state) |
This set a loop point for loop to reach. | |
#define | state_loop(state) |
This will loop back to last executed state_setloop position. | |
#define | state_handle(state, signal) |
This is state to accept a signal. | |
#define | state_signal_yield(state, signal) |
Signal to a given state, and yield for that state to take place. | |
#define | state_restart_yield(state) |
Restart state machine from beginning, and end this state. | |
#define | state_finish_yield(state) |
End state machine, and end this state. | |
#define | state_restart(state) |
Restart state machine from beginning. | |
#define | state_finish(state) |
End state machine. |
These macros define a 'state machine' handler.
What this provides is a trivial way to perform a sequence of high-level operations over time. For instance, there is handling defined for moving or animating things. If you want something to go from XY to XY, that's easy. This makes it easy to tell it to go from XY to XY, wait for an event, then go visit three other points at various speeds.
Another example is a login script, where you would want to send a challenge, wait for a response, and then send a response back, or even building a packet from an incoming stream of data.
Basically, each time the state machine is invoked in the cycle handler, it steps to a state in its state machine. If a state machine 'finishes', it is more or less a failed 'if'.
If you want something to perform operations over time and react to stimulus like a thread, but be a wholly synchronous entity, this is your baby. It takes two ints, as opposed to a thread's overhead. Provides something like cooperative multitasking in a lightweight package.
As implemented, the line of state a state machine is on is the negated line of the source code it's on, and signals are the same as signalled values.
Generators are stateerally higher-level functions, but if it's low level, you might want to consider keeping it short (or doing something else), as the switch it makes is essentially a string of if/else if/else if/else if...
Definition in file state.h.
#define state_begin | ( | state | ) |
Value:
switch( state.line ) \ { \ case _state_begin:
It should have one or more yield states, and be terminated with an 'state_end()' Entire state machine may be wrapped by a conditional Code preceding this statement will be executed each time any state is executed Implementation of a state machine in the cycler is optional
May only appear at beginning of state machine
#define state_destroy | ( | state | ) | { state.line = state.loop = _state_end; } |
#define state_end | ( | state, | |||
onbadstate | ) |
Value:
{} \ state.line = _state_end;\ /* Fall-through */\ case _state_end:\ /* Code following state machine is executed */\ break;\ default: \ {\ /* onbadstate may optionally branch with state_signal or state_restart to recover harmlessly */\ onbadstate; \ state.line = _state_end;\ }\ return; \ }
onbadstate | Something to do when cued to unknown state; may do nothing, throw an assert on debug, a macro that harvests local state and reports, a 'catch all' subroutine handler for certain kinds of signal handlers, etc. |
Can not be part of a conditional.
On bad state, finishes the state machine, by default
#define state_finish | ( | state | ) |
#define state_finish_yield | ( | state | ) |
#define state_handle | ( | state, | |||
signal | ) |
Value:
state_sleep(state)\ case _state_signal(signal):
signal | The enumerated signal this handles May only appear in state machine body between state_begin and state_end If state falls through to this, it will through to the end (state machine is skipped in cycle until state is set) |
Can not be part of a conditional.
#define state_init | ( | state | ) | { state.line = state.loop = _state_begin; } |
Initialize or reset a state machine.
state | What to call it; in other invocations it should have whatever indirection is required to reach it; i.e. struct->state |
Definition at line 90 of file state.h.
Referenced by GUI_BlibInit().
#define state_loop | ( | state | ) |
#define state_repeat | ( | state | ) | return |
#define state_restart | ( | state | ) |
#define state_restart_yield | ( | state | ) |
Value:
{\ state.line = _state_begin;\ return;\ }
May only appear in state machine body between state_begin and state_end
May be part of a conditional
#define state_setloop | ( | state | ) |
#define state_signal | ( | state, | |||
signal | ) | { state.line = _state_signal(signal); } |
Wake up state machine, if it was 'finished', and jump to a signal for its next cycle.
May appear internal or external to state function, and be conditional
Keep in mind that if the signal was not defined, we'll invoke the 'onbadstate' in state_end later over it
#define state_signal_yield | ( | state, | |||
signal | ) |
Value:
{\ state.line = _state_signal(signal);\ return;\ }
May only appear in state machine body between state_begin and state_end
May be part of a conditional
Keep in mind that if the signal was not defined, we'll invoke the 'onbadstate' in state_end later over it
#define state_sleep | ( | state | ) |
Value:
state_yield(state)\ return;
May only appear in state machine body between state_begin and state_end
Can not be part of a conditional.
#define state_wait | ( | state, | |||
condition | ) |
Value:
state_yield(state)\ { if( !(condition) ) return; }
May only appear in state machine body between state_begin and state_end
Can not be part of a conditional.
#define state_yield | ( | state | ) |
Value:
{} \ state.line = _line; \ return; \ case _line:
May only appear in state machine body between state_begin and state_end
Can not be part of a conditional.