Skip to content
This repository has been archived by the owner on May 17, 2020. It is now read-only.

Commit

Permalink
Make state machines statically allocable
Browse files Browse the repository at this point in the history
Since we really want to avoid dynamic allocation, it was needed to make
the state machines statically allocable.
  • Loading branch information
antoinealb committed Oct 12, 2014
1 parent 6701621 commit e66241d
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 55 deletions.
26 changes: 0 additions & 26 deletions state_machine.c
Original file line number Diff line number Diff line change
@@ -1,32 +1,6 @@
#include <stdlib.h>
#include "state_machine.h"

struct state_machine_s {
void (*current_state)(state_machine_t *);

/** The context of a state machine is some user-provided pointer which can
* be used to store information about the state machine instance, such as
* the current connection if the state machine is used to implement a server
* for example. */
void *context;
};

state_machine_t *state_machine_create(void)
{
state_machine_t *machine;
machine = malloc(sizeof(state_machine_t));

state_machine_set_current_state(machine, NULL);
state_machine_set_context(machine, NULL);

return machine;
}

void state_machine_delete(state_machine_t *machine)
{
free(machine);
}

void state_machine_set_current_state(state_machine_t *machine, state_func state)
{
machine->current_state = state;
Expand Down
12 changes: 10 additions & 2 deletions state_machine.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
#ifndef STATE_MACHINE_H_
#define STATE_MACHINE_H_

typedef struct state_machine_s state_machine_t;
typedef void (*state_func)(state_machine_t *);

typedef struct state_machine_s {
void (*current_state)(struct state_machine_s *);

/** The context of a state machine is some user-provided pointer which can
* be used to store information about the state machine instance, such as
* the current connection if the state machine is used to implement a server
* for example. */
void *context;
} state_machine_t;

typedef void (*state_func)(state_machine_t *);

/** Allocates memory for a new state machine. */
state_machine_t *state_machine_create(void);
Expand Down
46 changes: 19 additions & 27 deletions tests/state_machine_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,32 +13,25 @@ void simple_state_1(state_machine_t *machine)
// General purpose call counter used in various tests
static int call_counter;


TEST_GROUP(StateMachineTestGroup)
{
state_machine_t *machine;
state_machine_t machine;

void setup(void)
{
machine = state_machine_create();
call_counter = 0;
}

void teardown(void)
{
state_machine_delete(machine);
}
};

TEST(StateMachineTestGroup, CanInitMachine)
{
POINTERS_EQUAL(NULL, state_machine_get_current_state(machine));
POINTERS_EQUAL(NULL, state_machine_get_current_state(&machine));
}

TEST(StateMachineTestGroup, CanSetState)
{
state_machine_set_current_state(machine, (state_func)0x1234);
POINTERS_EQUAL(0x1234, state_machine_get_current_state(machine));
state_machine_set_current_state(&machine, (state_func)0x1234);
POINTERS_EQUAL(0x1234, state_machine_get_current_state(&machine));
}

TEST(StateMachineTestGroup, EmptyStateExits)
Expand All @@ -48,17 +41,17 @@ TEST(StateMachineTestGroup, EmptyStateExits)
// This test does not have any test macros, because the test app will crash
// if it tries to execute the NULL pointer.

state_machine_set_current_state(machine, NULL);
state_machine_run(machine);
state_machine_set_current_state(&machine, NULL);
state_machine_run(&machine);
}

TEST(StateMachineTestGroup, NULLStateIsNotValid)
{
state_machine_set_current_state(machine, NULL);
CHECK_EQUAL(0, state_machine_state_is_valid(machine));
state_machine_set_current_state(&machine, NULL);
CHECK_EQUAL(0, state_machine_state_is_valid(&machine));

state_machine_set_current_state(machine, simple_state_1);
CHECK_EQUAL(1, state_machine_state_is_valid(machine));
state_machine_set_current_state(&machine, simple_state_1);
CHECK_EQUAL(1, state_machine_state_is_valid(&machine));
}

void simple_exiting_state(state_machine_t *machine)
Expand All @@ -69,15 +62,15 @@ void simple_exiting_state(state_machine_t *machine)

TEST(StateMachineTestGroup, CanExitStateMachine)
{
state_machine_set_current_state(machine, simple_exiting_state);
state_machine_run(machine);
state_machine_set_current_state(&machine, simple_exiting_state);
state_machine_run(&machine);

// Check that we really entered the state machine
CHECK_EQUAL(1, call_counter);

// At this point we should have exited the state machine and be in invalid
// state
CHECK_EQUAL(0, state_machine_state_is_valid(machine));
CHECK_EQUAL(0, state_machine_state_is_valid(&machine));
}


Expand All @@ -88,7 +81,6 @@ void chaining_state_1(state_machine_t *machine)
{
call_counter ++;


state_machine_set_current_state(machine, chaining_state_2);
}

Expand All @@ -106,19 +98,19 @@ void chaining_state_2(state_machine_t *machine)

TEST(StateMachineTestGroup, CanTransitionBetweenStates)
{
state_machine_set_current_state(machine, chaining_state_1);
state_machine_set_current_state(&machine, chaining_state_1);

while (state_machine_state_is_valid(machine)) {
state_machine_run(machine);
while (state_machine_state_is_valid(&machine)) {
state_machine_run(&machine);
}

CHECK_EQUAL(20, call_counter);
}

TEST(StateMachineTestGroup, CanGetContext)
{
POINTERS_EQUAL(NULL, state_machine_get_context(machine));
state_machine_set_context(machine, (void *)1234);
POINTERS_EQUAL(1234, state_machine_get_context(machine));
POINTERS_EQUAL(NULL, state_machine_get_context(&machine));
state_machine_set_context(&machine, (void *)1234);
POINTERS_EQUAL(1234, state_machine_get_context(&machine));
}

0 comments on commit e66241d

Please sign in to comment.