Eric Day

Thoughts, code, and other oddments.
Dark | Light

Programming - C

state_stack.c

Download

/*
 
An example state machine using a function stack.
 
Copyright (C) Eric Day - http://oddments.org/
All content licensed under the Creative Commons Attribution 3.0 License.
 
This compares the C and C++ versions of state_stack.
 
> gcc -o state_stack_c state_stack.c
> time ./state_stack_c
88
80
0.976u 0.000s 0:00.97 100.0%    0+0k 0+0io 0pf+0w
 
> g++ -o state_stack_cc state_stack.cc
> time ./state_stack_cc
88
80
1.696u 0.000s 0:01.69 100.0%    0+0k 0+0io 0pf+0w
 
*/
 
#include <assert.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
/* Structs. */
struct connection;
typedef struct connection connection_st;
typedef bool (connection_state_fn)(connection_st *connection);
 
struct result;
typedef struct result result_st;
typedef bool (result_state_fn)(result_st *result);
 
struct connection
{
  connection_state_fn *state_stack[8];
  uint8_t state_current;
  bool is_connected;
  char *query;
  result_st *result;
};
 
struct result
{
  result_state_fn *state_stack[8];
  uint8_t state_current;
  char *result;
};
 
/* Function declarations. */
void connection_init(connection_st *connection);
void connection_deinit(connection_st *connection);
void connection_state_push(connection_st *connection,
                           connection_state_fn *state_fn);
void connection_state_pop(connection_st *connection);
void connection_state_run(connection_st *connection);
void connection_query(connection_st *connection, char *query,
                      result_st *result);
bool connection_connect_state(connection_st *connection);
bool connection_authenticate_state(connection_st *connection);
bool connection_query_state(connection_st *connection);
bool connection_result_state(connection_st *connection);
 
void result_init(result_st *result);
void result_deinit(result_st *result);
void result_state_push(result_st *result, result_state_fn *state_fn);
void result_state_pop(result_st *result);
void result_state_run(result_st *result);
char *result_get_result(result_st *result);
void result_read_result(result_st *result);
bool result_read_state(result_st *result);
 
/* Function definitions. */
void connection_init(connection_st *connection)
{
  connection->state_current= 0;
  connection->is_connected= false;
  connection->query= NULL;
  connection->result= NULL;
}
 
void connection_deinit(connection_st *connection)
{
  if (connection->query != NULL)
    free(connection->query);
}
 
void connection_state_push(connection_st *connection,
                           connection_state_fn *state_fn)
{
  connection->state_stack[connection->state_current]= state_fn;
  connection->state_current++;
}
 
void connection_state_pop(connection_st *connection)
{
  connection->state_current--;
}
 
void connection_state_run(connection_st *connection)
{
  while (connection->state_current > 0 &&
         connection->state_stack[connection->state_current - 1](connection))
  {
  }
}
 
void connection_query(connection_st *connection, char *query, result_st *result)
{
  connection->query= strdup(query);
  connection->result= result;
  connection_state_push(connection, connection_result_state);
  connection_state_push(connection, connection_query_state);
  connection_state_run(connection);
}
 
bool connection_connect_state(connection_st *connection)
{
  connection->is_connected= true;
  connection_state_pop(connection);
  connection_state_push(connection, connection_authenticate_state);
  return true;
}
 
bool connection_authenticate_state(connection_st *connection)
{
  connection_state_pop(connection);
  return true;
}
 
bool connection_query_state(connection_st *connection)
{
  if (!connection->is_connected)
  {
    connection_state_push(connection, connection_connect_state);
    return true;
  }
 
  connection_state_pop(connection);
  return true;
}
 
bool connection_result_state(connection_st *connection)
{
  result_read_result(connection->result);
  connection_state_pop(connection);
  return true;
}
 
void result_init(result_st *result)
{
  result->state_current= 0;
  result->result= NULL;
}
 
void result_deinit(result_st *result)
{
  if (result->result != NULL)
    free(result->result);
}
 
void result_state_push(result_st *result, result_state_fn *state_fn)
{
  result->state_stack[result->state_current]= state_fn;
  result->state_current++;
}
 
void result_state_pop(result_st *result)
{
  result->state_current--;
}
 
void result_state_run(result_st *result)
{
  while (result->state_current > 0 &&
         result->state_stack[result->state_current - 1](result))
  {
  }
}
 
char *result_get_result(result_st *result)
{
  return result->result;
}
 
void result_read_result(result_st *result)
{
  result_state_push(result, result_read_state);
  result_state_run(result);
}
 
bool result_read_state(result_st *result)
{
  result->result= strdup("Moo");
  result_state_pop(result);
  return true;
}
 
/* Test program. */
void test(void)
{
  connection_st connection;
  result_st result;
 
  connection_init(&connection);
  result_init(&result);
  connection_query(&connection, "What does a cow say?", &result);
  connection_deinit(&connection);
  result_deinit(&result);
}
 
int main(void)
{
  int x;
 
  printf("%zu\n", sizeof(connection_st));
  printf("%zu\n", sizeof(result_st));
 
  for (x= 0; x < 5000000; x++)
    test();
 
  return 0;
}
Blog
Wiki
About
Resume
RSS
Comments

E-Mail
Launchpad
LinkedIn
Twitter
identi.ca
Facebook

OpenStack
Scale Stack
Gearman
NW Veg
Veg Food & Fit

Linux On Laptops