Skip to content

Commit

Permalink
Fix #20: Add lock template parameter.
Browse files Browse the repository at this point in the history
  • Loading branch information
tkem committed Feb 24, 2019
1 parent de19ea0 commit 3411698
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 66 deletions.
22 changes: 0 additions & 22 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,17 +56,6 @@ matrix:
- MATRIX_EVAL="CC=gcc-8 CXX=g++-8"
- CXXFLAGS=-std=c++17
- GCOV=gcov-8
- os: linux
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-8
env:
- MATRIX_EVAL="CC=gcc-8 CXX=g++-8"
- CXXFLAGS=-DNDEBUG
- GCOV=gcov-8
- os: linux
addons:
apt:
Expand Down Expand Up @@ -96,17 +85,6 @@ matrix:
- clang-7
env:
- MATRIX_EVAL="CC=clang-7 CXX=clang++-7"
- os: linux
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-7
packages:
- clang-7
env:
- MATRIX_EVAL="CC=clang-7 CXX=clang++-7"
- CXXFLAGS=-DNDEBUG

before_install:
- pip install --user cpp-coveralls
Expand Down
92 changes: 60 additions & 32 deletions src/fsm.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,26 @@ namespace fsmlite {
#else
#error "fsmlite requires C++11 support."
#endif
// C++11 std::lock_guard is in <thread>, which may not be
// present on freestanding implementations
template<class BasicLockable>
class lock_guard {
BasicLockable& ref;

public:
explicit lock_guard(BasicLockable& m) : ref(m) {
m.lock();
}

~lock_guard() {
ref.unlock();
}

private:
lock_guard( const lock_guard& ) = delete;
lock_guard& operator=(const lock_guard&) = delete;
};

// C++11 std::forward() is in <utility>, which may not be
// present on freestanding implementations
template<class T>
Expand Down Expand Up @@ -174,15 +194,49 @@ namespace fsmlite {
};
}

#if !__GNUC__ || __EXCEPTIONS
class logic_lock {
bool locked = false;

public:
void lock() {
if (locked) {
throw std::logic_error("process_event called recursively");
}
locked = true;
}

void unlock() {
locked = false;
}
};
#endif

struct no_lock {
void lock() {}
void unlock() {}
};

#if !__GNUC__ || __EXCEPTIONS
using default_lock = logic_lock;
#else
using default_lock = no_lock;
#endif

/**
* Finite state machine (FSM) base class template.
*
* @tparam Derived the derived state machine class
*
* @tparam State the FSM's state type, defaults to `int`
*
* @tparam Lock the FSM's lock type, defaults to `default_lock`
*/
template<class Derived, class State = int>
template<class Derived, class State = int, class Lock = default_lock>
class fsm {
State state;
Lock lock;

public:
/**
* The FSM's state type.
Expand All @@ -195,7 +249,7 @@ namespace fsmlite {
*
* @param init_state the FSM's initial state
*/
fsm(state_type init_state = state_type()) : m_state(init_state) {}
fsm(state_type init_state = state_type()) : state(init_state) {}

/**
* Process an event.
Expand All @@ -213,16 +267,16 @@ namespace fsmlite {
template<class Event>
void process_event(const Event& event) {
using rows = typename by_event_type<Event, typename Derived::transition_table>::type;
processing_lock lock(*this);
static_assert(std::is_base_of<fsm, Derived>::value, "must derive from fsm");
Derived& self = static_cast<Derived&>(*this);
m_state = handle_event<Event, rows>::execute(self, event, m_state);
detail::lock_guard<Lock> g(lock);
state = handle_event<Event, rows>::execute(self, event, state);
}

/**
* Return the state machine's current state.
*/
state_type current_state() const { return m_state; }
state_type current_state() const { return state; }

protected:
/**
Expand All @@ -240,7 +294,7 @@ namespace fsmlite {
*/
template<class Event>
state_type no_transition(const Event& event) {
return m_state;
return state;
}

private:
Expand Down Expand Up @@ -417,32 +471,6 @@ namespace fsmlite {
return self.no_transition(event);
}
};

private:
state_type m_state;

private:
#if !defined(NDEBUG) && (!__GNUC__ || __EXCEPTIONS)
class processing_lock {
public:
processing_lock(fsm& m) : processing(m.processing) {
if (processing) {
throw std::logic_error("process_event called recursively");
}
processing = true;
}
~processing_lock() {
processing = false;
}
private:
bool& processing;
};
bool processing = false;
#else
struct processing_lock {
processing_lock(fsm&) {}
};
#endif
};
}

Expand Down
18 changes: 6 additions & 12 deletions tests/test_recursive.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#include <iostream>
#include <stdexcept>
#include <type_traits>

Expand All @@ -9,15 +8,11 @@ class state_machine: public fsmlite::fsm<state_machine> {
public:
enum states { Init, Exit };

struct event {};

private:
void process(const int& event) {
std::cout << "Processing event: " << event << "\n";
#ifdef NDEBUG
if (event != 0) {
throw std::logic_error("recursive invocation detected");
}
#endif
process_event(event + 1);
void process(const event& e) {
process_event(e);
}

private:
Expand All @@ -26,7 +21,7 @@ class state_machine: public fsmlite::fsm<state_machine> {
using transition_table = table<
// Start Event Target Action
// -----------+-----+------+------+-----------+-
mem_fn_row< Init, int, Exit, &m::process >
mem_fn_row< Init, event, Exit, &m::process >
// -----------+-----+------+------+-----------+-
>;
};
Expand All @@ -35,9 +30,8 @@ int main()
{
state_machine m;
try {
m.process_event(0);
m.process_event(state_machine::event{});
} catch (std::logic_error& e) {
std::cerr << e.what() << "\n";
return 0;
}
return 1; /* LCOV_EXCL_LINE */
Expand Down

0 comments on commit 3411698

Please sign in to comment.