infinite_state_machine 1.0.0
Infinite State Machine Library
Loading...
Searching...
No Matches
infinite_state_machine.c
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2025, Roy Ratcliffe, Northumberland, United Kingdom
3 * SPDX-License-Identifier: MIT
4 */
24
25#include <string.h>
26#include <errno.h>
27
35static int infinite_state_machine_enter(struct infinite_state_machine *machine, struct infinite_state *state);
36
43static int infinite_state_machine_exit(struct infinite_state_machine *machine);
44
51static int infinite_state_machine_push(struct infinite_state_machine *machine, struct infinite_state *state);
52
58static struct infinite_state *infinite_state_machine_pop(struct infinite_state_machine *machine);
59
61{
62 machine->depth = 0;
63 (void)memset(machine->states, 0, sizeof(machine->states));
64}
65
67{
68 /*
69 * If the target state is the same as the current top state, do nothing.
70 * This is a quick optimisation to avoid unnecessary state topology computation.
71 */
72 if (state == infinite_state_machine_top(machine))
73 {
74 return;
75 }
76 struct infinite_state_machine jump;
77 infinite_state_machine_jump(&jump, state);
78 int depth = 0;
80 {
81 depth++;
82 }
83 while (machine->depth > depth)
84 {
85 infinite_state_machine_exit(machine);
86 }
87 while (jump.depth > depth)
88 {
89 infinite_state_machine_enter(machine, jump.states[depth++]);
90 }
91}
92
98
100{
101 if (machine == NULL || state == NULL)
102 {
103 return -EINVAL;
104 }
105 for (int depth = 0; depth < machine->depth; depth++)
106 {
107 if (machine->states[depth] == state)
108 {
109 return 1;
110 }
111 }
112 return 0;
113}
114
115int infinite_state_machine_enter(struct infinite_state_machine *machine, struct infinite_state *state)
116{
117 int err;
118 if ((err = infinite_state_machine_push(machine, state)) < 0)
119 {
120 return err;
121 }
122 /*
123 * Run the enter actions *after* the machine stack adds the state.
124 * Technically, nothing prevents the action from applying yet another
125 * state transition, although higher-level code must be designed for
126 * reentrancy.
127 */
128 if (state->enter != NULL)
129 {
130 state->enter(state, machine);
131 }
132 return 0;
133}
134
135int infinite_state_machine_exit(struct infinite_state_machine *machine)
136{
137 struct infinite_state *state = infinite_state_machine_pop(machine);
138 if (state == NULL)
139 {
140 return -EINVAL;
141 }
142 /*
143 * Run the exit actions *after* the machine stack removes the state. This is
144 * by design, as it allows the exit actions to mutate the state of the
145 * machine after the state is removed. It might seem counterintuitive, but
146 * it allows for more flexible state management. The argument to the exit
147 * function is the state being exited, and the machine itself, allowing for
148 * context-aware exit actions.
149 */
150 if (state->exit != NULL)
151 {
152 state->exit(state, machine);
153 }
154 return 0;
155}
156
158{
159 return machine->depth == 0 ? NULL : machine->states[machine->depth - 1];
160}
161
162int infinite_state_machine_push(struct infinite_state_machine *machine, struct infinite_state *state)
163{
165 {
166 return -ENOMEM;
167 }
168 machine->states[machine->depth++] = state;
169 return 0;
170}
171
172struct infinite_state *infinite_state_machine_pop(struct infinite_state_machine *machine)
173{
174 if (machine->depth == 0)
175 {
176 return NULL;
177 }
178 struct infinite_state *pop = machine->states[--machine->depth];
179 /*
180 * Clear the popped state from the stack. This is not strictly necessary,
181 * but it can help catch use-after-free bugs.
182 */
183 machine->states[machine->depth] = NULL;
184 return pop;
185}
struct infinite_state ** infinite_state_topology(struct infinite_state *state, int depth, struct infinite_state **topology)
Get the topology of the infinite state machine.
void infinite_state_machine_jump(struct infinite_state_machine *machine, struct infinite_state *state)
Jumps to a state in the infinite state machine.
void infinite_state_machine_init(struct infinite_state_machine *machine)
Initialises the infinite state machine. The machine is reset to its initial state....
int infinite_state_machine_in(struct infinite_state_machine *machine, struct infinite_state *state)
Checks if a state is currently active in the infinite state machine.
void infinite_state_machine_goto(struct infinite_state_machine *machine, struct infinite_state *state)
Goes to a state in the infinite state machine.
struct infinite_state * infinite_state_machine_top(const struct infinite_state_machine *machine)
Gets the top state of the infinite state machine.
Public API for the infinite state machine. Provides functions to initialise, perform hierarchical tra...
#define INFINITE_STATE_MACHINE_MAX_DEPTH
Maximum depth of any infinite state machine. Defaults to 7 unless already defined before the inclusio...
Represents an infinite state machine. This structure holds the current state hierarchy and allows for...
int depth
The current depth of the infinite state machine.
struct infinite_state * states[INFINITE_STATE_MACHINE_MAX_DEPTH]
The states in the infinite state machine.
The state structure for the infinite state. This structure represents a state in the infinite state m...
void(* exit)(struct infinite_state *state, struct infinite_state_machine *machine)
The exit action for this state.
void(* enter)(struct infinite_state *state, struct infinite_state_machine *machine)
The enter action for this state.