From 396ce3992b05f206693a8d50ce669ba4f4bf4068 Mon Sep 17 00:00:00 2001 From: LCBW Date: Fri, 13 May 2022 08:37:27 -0500 Subject: [PATCH 1/8] update type def for StateTransitionMap --- scxml.workspace | 8 ++++++ .../include/scxml_core/scxml_sm_interface.h | 2 +- scxml_core/src/scxml_sm_interface.cpp | 27 ++++++++++++------- 3 files changed, 26 insertions(+), 11 deletions(-) create mode 100644 scxml.workspace diff --git a/scxml.workspace b/scxml.workspace new file mode 100644 index 0000000..bbcb33b --- /dev/null +++ b/scxml.workspace @@ -0,0 +1,8 @@ + + + + + + src + + diff --git a/scxml_core/include/scxml_core/scxml_sm_interface.h b/scxml_core/include/scxml_core/scxml_sm_interface.h index 9e8b49e..4f49d07 100644 --- a/scxml_core/include/scxml_core/scxml_sm_interface.h +++ b/scxml_core/include/scxml_core/scxml_sm_interface.h @@ -7,7 +7,7 @@ namespace scxml_core { /** @brief Container for states and their associated transitions */ -using StateTransitionMap = std::map>; +using StateTransitionMap = std::map>>; /** @brief Creates a map of known states and transition events associated with those states */ StateTransitionMap getStateTransitionMap(const std::string& scxml_file); diff --git a/scxml_core/src/scxml_sm_interface.cpp b/scxml_core/src/scxml_sm_interface.cpp index 63ac0f7..a49c081 100644 --- a/scxml_core/src/scxml_sm_interface.cpp +++ b/scxml_core/src/scxml_sm_interface.cpp @@ -10,6 +10,7 @@ static const char* HISTORY_STATE_ELEMENT = "history"; static const char* HISTORY_STATE_ID_ATTRIBUTE = "id"; static const char* TRANSITION_ELEMENT = "transition"; static const char* EVENT_ATTRIBUTE = "event"; +static const char* TARGET_ATTRIBUTE = "target"; /** * @brief Recursively adds states and transitions to the map @@ -18,7 +19,7 @@ static const char* EVENT_ATTRIBUTE = "event"; */ static void getStateTransitionsRecursive(tinyxml2::XMLElement* state, scxml_core::StateTransitionMap& map, - QSet inherited_events) + std::set> inherited_events) { using namespace tinyxml2; @@ -40,17 +41,23 @@ static void getStateTransitionsRecursive(tinyxml2::XMLElement* state, XMLElement* transition = state->FirstChildElement(TRANSITION_ELEMENT); while (transition) { - // Get the name of the event associated with this transition - const char* event = transition->Attribute(EVENT_ATTRIBUTE); - if (!event) - throw std::runtime_error("'" + std::string(TRANSITION_ELEMENT) + "' element does not have '" + - std::string(EVENT_ATTRIBUTE) + "' attribute"); + // Get the name of the event associated with this transition + const char* event = transition->Attribute(EVENT_ATTRIBUTE); + if (!event) + throw std::runtime_error("'" + std::string(TRANSITION_ELEMENT) + "' element does not have '" + + std::string(EVENT_ATTRIBUTE) + "' attribute"); - // Add the event name to the map - map.at(state_id).insert(event); + const char* name = transition->Attribute(TARGET_ATTRIBUTE); - // Get the next transition element - transition = transition->NextSiblingElement(TRANSITION_ELEMENT); + std::pair list = std::make_pair(event,name); + + inherited_events.insert(list); + + // Add the event name to the map + // map.at(state_id).insert(list); + + // Get the next transition element + transition = transition->NextSiblingElement(TRANSITION_ELEMENT); } // Recurse if this node has nested state elements From 8c5200ec383dca16f63636705875340a59a1ac03 Mon Sep 17 00:00:00 2001 From: LCBW Date: Fri, 13 May 2022 09:53:07 -0500 Subject: [PATCH 2/8] add getNeighbor function --- scxml_core/src/scxml_sm_interface.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/scxml_core/src/scxml_sm_interface.cpp b/scxml_core/src/scxml_sm_interface.cpp index a49c081..8ec3408 100644 --- a/scxml_core/src/scxml_sm_interface.cpp +++ b/scxml_core/src/scxml_sm_interface.cpp @@ -49,7 +49,7 @@ static void getStateTransitionsRecursive(tinyxml2::XMLElement* state, const char* name = transition->Attribute(TARGET_ATTRIBUTE); - std::pair list = std::make_pair(event,name); + std::pair list = std::make_pair (event,name); inherited_events.insert(list); @@ -143,6 +143,18 @@ ScxmlSMInterface::ScxmlSMInterface(const std::string& scxml_file) } } +// use this to determine the next state in the state machine, given the name of the transition you'd like to query +const QString next_state ScxmlSMInterface::getNeighbor(const QString& state, scxml_core::StateTransitionMap& map, std::QString search_text) { + std::map>> = map; + std::pair pair; + + for pair in map.at(state): + if pair.first() == text: + next_state = pair.second(); + return; + next_state = state; +} + void ScxmlSMInterface::addOnEntryCallback(const QString& state, const std::function& callback, bool async) { if (state_transition_map_.find(state) == state_transition_map_.end()) From 9e99abb6794361964739932944320c4808cd16c5 Mon Sep 17 00:00:00 2001 From: LCBW Date: Fri, 13 May 2022 14:11:55 -0500 Subject: [PATCH 3/8] builds --- .../include/scxml_core/scxml_sm_interface.h | 15 +++++ scxml_core/src/demo.cpp | 59 ++++++++++--------- scxml_core/src/scxml_sm_interface.cpp | 46 ++++++++++----- 3 files changed, 77 insertions(+), 43 deletions(-) diff --git a/scxml_core/include/scxml_core/scxml_sm_interface.h b/scxml_core/include/scxml_core/scxml_sm_interface.h index 4f49d07..e05e0d6 100644 --- a/scxml_core/include/scxml_core/scxml_sm_interface.h +++ b/scxml_core/include/scxml_core/scxml_sm_interface.h @@ -3,6 +3,8 @@ #include #include #include +#include +#include namespace scxml_core { @@ -23,11 +25,24 @@ class ScxmlSMInterface public: ScxmlSMInterface(const std::string& scxml_file); + /** + * @brief checks if an event exists + */ + bool eventExists(const QString& event, std::set> events); + + /** + * @brief gets the state to which a desired transition occurs + * @param search_text - insert transition text you'd like to match + * @throws if you don't have that transition, it will return itself as it's neighbor + */ + + const QString getNeighbor(const QString& state, scxml_core::StateTransitionMap& map, const QString& search_text); /** * @brief Adds a callback to the input state that will be invoked on entry to the state * @param async - flag for executing the input callback asynchronously * @throws exception if the state does not exist in the state machine */ + void addOnEntryCallback(const QString& state, const std::function& callback, bool async = false); /** diff --git a/scxml_core/src/demo.cpp b/scxml_core/src/demo.cpp index 7ab4643..75fc7ea 100644 --- a/scxml_core/src/demo.cpp +++ b/scxml_core/src/demo.cpp @@ -38,45 +38,46 @@ int main(int argc, char** argv) // Get the active state and available events QStringList active_states = interface.getSM()->activeStateNames(); const QString& current_state = active_states.at(0); - QSet available_events = map.at(current_state); + std::set> available_events = map.at(current_state); std::stringstream ss; ss << "Available events: [ "; - for (const QString& event : available_events) + for (auto& pair : available_events) { + const QString& event = pair.first; ss << event.toStdString() << " "; } ss << "]"; - // Get user input as to which event to execute - bool done = false; - while (!done) - { - std::cout << ss.str() << std::endl; +// // Get user input as to which event to execute +// bool done = false; +// while (!done) +// { +// std::cout << ss.str() << std::endl; - // Get the character input - auto input = std::cin.get(); - // Throw away the enter input - std::cin.get(); +// // Get the character input +// auto input = std::cin.get(); +// // Throw away the enter input +// std::cin.get(); - if (std::isdigit(input)) - { - int idx = static_cast(input) - 48; - if (idx < available_events.size()) - { - interface.submitEvent(available_events.toList().at(idx)); - done = true; - } - else - { - std::cout << "Index " << idx << " was not in range [0, " << available_events.size() - 1 << "]" << std::endl; - } - } - else - { - std::cout << "Input must be numeric" << std::endl; - } - } +// if (std::isdigit(input)) +// { +// int idx = static_cast(input) - 48; +// if (idx < available_events.size()) +// { +// interface.submitEvent(available_events.toList().at(idx)); +// done = true; +// } +// else +// { +// std::cout << "Index " << idx << " was not in range [0, " << available_events.size() - 1 << "]" << std::endl; +// } +// } +// else +// { +// std::cout << "Input must be numeric" << std::endl; +// } +// } } } catch (const std::exception& ex) diff --git a/scxml_core/src/scxml_sm_interface.cpp b/scxml_core/src/scxml_sm_interface.cpp index 8ec3408..cc88c8d 100644 --- a/scxml_core/src/scxml_sm_interface.cpp +++ b/scxml_core/src/scxml_sm_interface.cpp @@ -49,12 +49,12 @@ static void getStateTransitionsRecursive(tinyxml2::XMLElement* state, const char* name = transition->Attribute(TARGET_ATTRIBUTE); - std::pair list = std::make_pair (event,name); + std::pair list = std::make_pair (QString(event),QString(name)); inherited_events.insert(list); // Add the event name to the map - // map.at(state_id).insert(list); + map[state_id] = inherited_events; // Get the next transition element transition = transition->NextSiblingElement(TRANSITION_ELEMENT); @@ -78,7 +78,7 @@ static void getStateTransitionsRecursive(tinyxml2::XMLElement* state, std::string(HISTORY_STATE_ID_ATTRIBUTE) + "' attribute"); // Add this state to the map - map[QString(id)] = QSet{}; + map[QString(id)] = std::set>{}; // History states do not have transitions or nested states, so no need to recurse into it history = history->NextSiblingElement(HISTORY_STATE_ELEMENT); @@ -109,7 +109,7 @@ StateTransitionMap getStateTransitionMap(const std::string& scxml_file) StateTransitionMap map; while (state) { - getStateTransitionsRecursive(state, map, QSet{}); + getStateTransitionsRecursive(state, map, std::set>{}); state = state->NextSiblingElement(STATE_ELEMENT); } @@ -144,17 +144,35 @@ ScxmlSMInterface::ScxmlSMInterface(const std::string& scxml_file) } // use this to determine the next state in the state machine, given the name of the transition you'd like to query -const QString next_state ScxmlSMInterface::getNeighbor(const QString& state, scxml_core::StateTransitionMap& map, std::QString search_text) { - std::map>> = map; - std::pair pair; +const QString ScxmlSMInterface::getNeighbor(const QString& state, scxml_core::StateTransitionMap& map, const QString& search_text) { + QString next_state; - for pair in map.at(state): - if pair.first() == text: - next_state = pair.second(); - return; - next_state = state; + for (auto& pair : map.at(state)) + { + if (pair.first == search_text) + { +// next_state = pair.second(); + return pair.second; + } + else { + next_state = state; + } + } + return next_state; } +bool ScxmlSMInterface::eventExists(const QString& event, std::set> events) + { + for (auto& pair : events) + { + if (pair.first == event) + { + return true; + } + return false; + } + } + void ScxmlSMInterface::addOnEntryCallback(const QString& state, const std::function& callback, bool async) { if (state_transition_map_.find(state) == state_transition_map_.end()) @@ -184,7 +202,7 @@ bool ScxmlSMInterface::submitEvent(const QString& event, bool force) // Ensure at least one of the active states has the specified transition auto it = std::find_if(active_states.begin(), active_states.end(), [this, event](const QString& state) -> bool { - return this->state_transition_map_.at(state).contains(event); + return eventExists(event,state_transition_map_.at(state)); }); if (it == active_states.end()) @@ -204,7 +222,7 @@ bool ScxmlSMInterface::submitEvent(const QString& event, bool force) { for (const QString& state : active_states) { - if (state_transition_map_.at(state).contains(event)) + if (eventExists(event,state_transition_map_.at(state))) { // Check if the asynchronous callback is finished before submitting the event if (!future_map_.at(state).isFinished()) From 9fc671e4242b1a4ae891d3a01780587e893986f1 Mon Sep 17 00:00:00 2001 From: LCBW Date: Wed, 18 May 2022 11:50:16 -0500 Subject: [PATCH 4/8] ran clang & updated getNeighbor --- .../include/scxml_core/scxml_sm_interface.h | 4 +- scxml_core/src/scxml_sm_interface.cpp | 76 ++++++++++--------- 2 files changed, 41 insertions(+), 39 deletions(-) diff --git a/scxml_core/include/scxml_core/scxml_sm_interface.h b/scxml_core/include/scxml_core/scxml_sm_interface.h index e05e0d6..de408e5 100644 --- a/scxml_core/include/scxml_core/scxml_sm_interface.h +++ b/scxml_core/include/scxml_core/scxml_sm_interface.h @@ -30,13 +30,13 @@ class ScxmlSMInterface */ bool eventExists(const QString& event, std::set> events); - /** + /** * @brief gets the state to which a desired transition occurs * @param search_text - insert transition text you'd like to match * @throws if you don't have that transition, it will return itself as it's neighbor */ - const QString getNeighbor(const QString& state, scxml_core::StateTransitionMap& map, const QString& search_text); + const QString getNeighbor(const QString& state, const QString& search_text); /** * @brief Adds a callback to the input state that will be invoked on entry to the state * @param async - flag for executing the input callback asynchronously diff --git a/scxml_core/src/scxml_sm_interface.cpp b/scxml_core/src/scxml_sm_interface.cpp index cc88c8d..19146bb 100644 --- a/scxml_core/src/scxml_sm_interface.cpp +++ b/scxml_core/src/scxml_sm_interface.cpp @@ -41,23 +41,23 @@ static void getStateTransitionsRecursive(tinyxml2::XMLElement* state, XMLElement* transition = state->FirstChildElement(TRANSITION_ELEMENT); while (transition) { - // Get the name of the event associated with this transition - const char* event = transition->Attribute(EVENT_ATTRIBUTE); - if (!event) - throw std::runtime_error("'" + std::string(TRANSITION_ELEMENT) + "' element does not have '" + - std::string(EVENT_ATTRIBUTE) + "' attribute"); + // Get the name of the event associated with this transition + const char* event = transition->Attribute(EVENT_ATTRIBUTE); + if (!event) + throw std::runtime_error("'" + std::string(TRANSITION_ELEMENT) + "' element does not have '" + + std::string(EVENT_ATTRIBUTE) + "' attribute"); - const char* name = transition->Attribute(TARGET_ATTRIBUTE); + const char* name = transition->Attribute(TARGET_ATTRIBUTE); - std::pair list = std::make_pair (QString(event),QString(name)); - - inherited_events.insert(list); + std::pair list = std::make_pair(QString(event), QString(name)); - // Add the event name to the map - map[state_id] = inherited_events; + inherited_events.insert(list); - // Get the next transition element - transition = transition->NextSiblingElement(TRANSITION_ELEMENT); + // Add the event name to the map + map[state_id] = inherited_events; + + // Get the next transition element + transition = transition->NextSiblingElement(TRANSITION_ELEMENT); } // Recurse if this node has nested state elements @@ -144,34 +144,36 @@ ScxmlSMInterface::ScxmlSMInterface(const std::string& scxml_file) } // use this to determine the next state in the state machine, given the name of the transition you'd like to query -const QString ScxmlSMInterface::getNeighbor(const QString& state, scxml_core::StateTransitionMap& map, const QString& search_text) { +const QString ScxmlSMInterface::getNeighbor(const QString& state, const QString& search_text) +{ QString next_state; - - for (auto& pair : map.at(state)) - { - if (pair.first == search_text) - { -// next_state = pair.second(); - return pair.second; - } - else { - next_state = state; - } - } - return next_state; + + for (auto& pair : state_transition_map_.at(state)) + { + if (pair.first == search_text) + { + // next_state = pair.second(); + return pair.second; + } + else + { + next_state = state; + } + } + return next_state; } bool ScxmlSMInterface::eventExists(const QString& event, std::set> events) +{ + for (auto& pair : events) + { + if (pair.first == event) { - for (auto& pair : events) - { - if (pair.first == event) - { - return true; - } - return false; - } + return true; } + return false; + } +} void ScxmlSMInterface::addOnEntryCallback(const QString& state, const std::function& callback, bool async) { @@ -202,7 +204,7 @@ bool ScxmlSMInterface::submitEvent(const QString& event, bool force) // Ensure at least one of the active states has the specified transition auto it = std::find_if(active_states.begin(), active_states.end(), [this, event](const QString& state) -> bool { - return eventExists(event,state_transition_map_.at(state)); + return eventExists(event, state_transition_map_.at(state)); }); if (it == active_states.end()) @@ -222,7 +224,7 @@ bool ScxmlSMInterface::submitEvent(const QString& event, bool force) { for (const QString& state : active_states) { - if (eventExists(event,state_transition_map_.at(state))) + if (eventExists(event, state_transition_map_.at(state))) { // Check if the asynchronous callback is finished before submitting the event if (!future_map_.at(state).isFinished()) From 0562234844b6d5d24d4ea58d9cffb3f2b479cd94 Mon Sep 17 00:00:00 2001 From: LCBW Date: Wed, 18 May 2022 12:07:15 -0500 Subject: [PATCH 5/8] ran clang --- scxml_core/src/demo.cpp | 55 +++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/scxml_core/src/demo.cpp b/scxml_core/src/demo.cpp index 75fc7ea..102a1c2 100644 --- a/scxml_core/src/demo.cpp +++ b/scxml_core/src/demo.cpp @@ -49,35 +49,36 @@ int main(int argc, char** argv) } ss << "]"; -// // Get user input as to which event to execute -// bool done = false; -// while (!done) -// { -// std::cout << ss.str() << std::endl; + // // Get user input as to which event to execute + // bool done = false; + // while (!done) + // { + // std::cout << ss.str() << std::endl; -// // Get the character input -// auto input = std::cin.get(); -// // Throw away the enter input -// std::cin.get(); + // // Get the character input + // auto input = std::cin.get(); + // // Throw away the enter input + // std::cin.get(); -// if (std::isdigit(input)) -// { -// int idx = static_cast(input) - 48; -// if (idx < available_events.size()) -// { -// interface.submitEvent(available_events.toList().at(idx)); -// done = true; -// } -// else -// { -// std::cout << "Index " << idx << " was not in range [0, " << available_events.size() - 1 << "]" << std::endl; -// } -// } -// else -// { -// std::cout << "Input must be numeric" << std::endl; -// } -// } + // if (std::isdigit(input)) + // { + // int idx = static_cast(input) - 48; + // if (idx < available_events.size()) + // { + // interface.submitEvent(available_events.toList().at(idx)); + // done = true; + // } + // else + // { + // std::cout << "Index " << idx << " was not in range [0, " << available_events.size() - 1 << "]" << + // std::endl; + // } + // } + // else + // { + // std::cout << "Input must be numeric" << std::endl; + // } + // } } } catch (const std::exception& ex) From 460d9efd9b88af7faf01789ea8a5b0c98fa7590b Mon Sep 17 00:00:00 2001 From: LCBW Date: Thu, 26 May 2022 11:22:59 -0500 Subject: [PATCH 6/8] update latest --- scxml_core/src/scxml_sm_interface.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/scxml_core/src/scxml_sm_interface.cpp b/scxml_core/src/scxml_sm_interface.cpp index 19146bb..dbbcf89 100644 --- a/scxml_core/src/scxml_sm_interface.cpp +++ b/scxml_core/src/scxml_sm_interface.cpp @@ -155,10 +155,6 @@ const QString ScxmlSMInterface::getNeighbor(const QString& state, const QString& // next_state = pair.second(); return pair.second; } - else - { - next_state = state; - } } return next_state; } From c4197f9d22c67f76b28f4959b53e403ce7e396af Mon Sep 17 00:00:00 2001 From: LCBW Date: Thu, 2 Jun 2022 14:37:50 -0500 Subject: [PATCH 7/8] update eventExists logic --- scxml_core/src/scxml_sm_interface.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/scxml_core/src/scxml_sm_interface.cpp b/scxml_core/src/scxml_sm_interface.cpp index dbbcf89..392da85 100644 --- a/scxml_core/src/scxml_sm_interface.cpp +++ b/scxml_core/src/scxml_sm_interface.cpp @@ -161,13 +161,23 @@ const QString ScxmlSMInterface::getNeighbor(const QString& state, const QString& bool ScxmlSMInterface::eventExists(const QString& event, std::set> events) { + int i = 0; + const int j = events.size(); for (auto& pair : events) { if (pair.first == event) { return true; } - return false; + else + { + i = i + 1; + } + + if (i == j) + { + return false; + } } } From 70c3aa3df6636722d4d4aa5341e5d87035d23b19 Mon Sep 17 00:00:00 2001 From: LCBW Date: Thu, 2 Jun 2022 14:41:10 -0500 Subject: [PATCH 8/8] ran clang --- scxml_core/src/scxml_sm_interface.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/scxml_core/src/scxml_sm_interface.cpp b/scxml_core/src/scxml_sm_interface.cpp index 392da85..aef81b7 100644 --- a/scxml_core/src/scxml_sm_interface.cpp +++ b/scxml_core/src/scxml_sm_interface.cpp @@ -152,7 +152,6 @@ const QString ScxmlSMInterface::getNeighbor(const QString& state, const QString& { if (pair.first == search_text) { - // next_state = pair.second(); return pair.second; } }