Skip to content

Instantly share code, notes, and snippets.

@eskil
Created May 13, 2016 21:06
Show Gist options
  • Save eskil/5f4f572da98121bd157e49b6b391ed2a to your computer and use it in GitHub Desktop.
Save eskil/5f4f572da98121bd157e49b6b391ed2a to your computer and use it in GitHub Desktop.
#include "statemachines.h"
#include <fstream>
//*********************************************************************************************
namespace simple_test {
/*
#define TRY_CLASS_PTR_STATES 0
#define TRY_CLASS_STATES 0
#define TRY_INT_STATES 1
#define TRY_CHAR_PTR_STATES 0
*/
#if TRY_CLASS_PTR_STATES || TRY_CLASS_STATES
class _state {
public:
_state () : m_name ("?") {}
_state (std::string n) : m_name (n) {}
friend std::ostream& operator<< (std::ostream& o, const _state *i);
friend std::ostream& operator<< (std::ostream& o, const _state &i);
std::string m_name;
};
class _initial_state : public _state { public: _initial_state () : _state ("initial state") {} };
class _fail_state : public _state { public: _fail_state () : _state ("fail state") {} };
class _one_state : public _state { public: _one_state () : _state ("one state") {} };
class _end_state : public _state { public: _end_state () : _state ("end state") {} };
class _loop_1_state : public _state { public: _loop_1_state () : _state ("loop 1 state") {} };
class _loop_2_state : public _state { public: _loop_2_state () : _state ("loop 2 state") {} };
_state *g_initial_state = new _initial_state;
_state *g_fail_state = new _fail_state;
_state *g_one_state = new _one_state;
_state *g_end_state = new _end_state;
_state *g_loop_1_state = new _loop_1_state;
_state *g_loop_2_state = new _loop_2_state;
std::ostream& operator<< (std::ostream& o, const _state *i) {
return o << i->m_name;
}
std::ostream& operator<< (std::ostream& o, const _state &i) {
return o << i.m_name;
}
#endif
#if TRY_CLASS_PTR_STATES
#define initial_state g_initial_state
#define fail_state g_fail_state
#define one_state g_end_state
#define end_state g_one_state
#define loop_1_state g_loop_1_state
#define loop_2_state g_loop_2_state
typedef const _state* my_state_type;
#endif
#if TRY_CLASS_STATES
#define initial_state _initial_state ()
#define fail_state _fail_state ()
#define one_state _one_state ()
#define end_state _end_state ()
#define loop_1_state _loop_1_state ()
#define loop_2_state _loop_2_state ()
typedef _state my_state_type;
// since the statemachine will have a shitload of instances (one pr. edge end point), we need to be
// able to compare them
bool operator==(const my_state_type &a, const my_state_type &b) { return a.m_name == b.m_name; }
bool operator<(const my_state_type &a, const my_state_type &b) { return a.m_name < b.m_name; }
#endif
#if TRY_INT_STATES
typedef enum {
initial_state, one_state, end_state, loop_1_state, loop_2_state, fail_state
} my_state_type;
std::ostream& operator<< (std::ostream& o, my_state_type i) {
if (i == initial_state) return o << "initial_state";
if (i == fail_state) return o << "fail_state";
if (i == one_state) return o << "one_state";
if (i == end_state) return o << "end_state";
if (i == loop_2_state) return o << "loop_2_state";
if (i == loop_1_state) return o << "loop_1_state";
return o << "?";
}
#endif
#if TRY_CHAR_PTR_STATES
#define initial_state "initial_state"
#define fail_state "fail_state"
#define one_state "one_state"
#define end_state "end_state"
#define loop_1_state "loop_1_state"
#define loop_2_state "loop_2_state"
typedef char* my_state_type;
#endif
class simple;
typedef statemachines::traits<my_state_type, threads::single_threaded> my_traits;
class simple : public statemachines::statemachine<simple, my_traits> {
public:
class generic_event : public event_t {};
class one_event : public event_t {
public:
one_event (std::string msg) : m_message (msg) {}
std::string m_message;
};
class loop_event : public event_t {};
class failure_event : public event_t {};
simple () {
*this << graphviz_t ("test_graph")
<< begin_t (initial_state)
//------------------------+---------------+-------------+---------------------------+---------------------
// Event From-State To-State Action Description
<< edge_t<one_event> (initial_state, one_state, &simple::action, "we got a 1")
<< edge_t<failure_event> (initial_state, fail_state)
<< edge_t<loop_event> (initial_state, loop_1_state, "got a loop event")
<< edge_t<loop_event> (one_state, loop_2_state, &simple::loop_2_action, "got a loop event")
<< edge_t<loop_event> (loop_1_state, loop_2_state, &simple::loop_2_action)
<< edge_t<loop_event> (loop_2_state, loop_1_state, "do a loop")
<< edge_t<generic_event> (fail_state, end_state)
<< edge_t<generic_event> (one_state, end_state, &simple::end_action, "")
<< edge_t<generic_event> (loop_1_state, end_state, &simple::end_action, "generic")
<< edge_t<generic_event> (loop_2_state, end_state, &simple::end_action, "generic");
//------------------------+---------------+-------------+---------------------------+---------------------
}
void action (const one_event &foo) {
printf ("action for one_event : %s\n", foo.m_message.c_str ());
m_count ++;
}
void end_action (const generic_event &foo) {
printf ("reached the end of the line\n");
m_count ++;
}
void loop_2_action (const loop_event &foo) {
printf ("loop\n");
prepost_event (new loop_event);
m_count ++;
}
void run (const std::string &name) {
m_count = 0;
// exercise it a bit
post_event (new one_event ("hello world!"));
post_event (new loop_event);
post_event (new loop_event);
post_event (new generic_event);
while (handle_event ()) { }
assert (m_count == 4);
save_to_postscript (name);
}
void save_to_postscript (std::string name) {
// create ps file showing state machine
name.erase (0, 2);
std::ofstream dotfile;
dotfile.open ((name + ".dot").c_str ());
dotfile << toGraphViz ();
dotfile.close ();
std::string cmd ("dot -Tps -o ");
cmd += (name + ".ps " + name + ".dot ");
std::cout << cmd << std::endl;
system (cmd.c_str ());
}
private:
int m_count;
};
};
//*********************************************************************************************
int main (int argc, char *argv[]) {
printf ("\nstatemachine_test\n--------------------------------------------\n");
simple_test::simple fsm_test;
fsm_test.run (argv[0]);
printf ("--------------------------------------------\n");
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment