From 83ef70ebc7527240f56e2e601777a613bce6e47e Mon Sep 17 00:00:00 2001 From: Stefan Radomski Date: Mon, 4 Aug 2014 23:39:39 +0200 Subject: Beautified flattened state-machine ids --- CMakeLists.txt | 12 +- src/uscxml/Factory.cpp | 2 +- src/uscxml/debug/SCXMLDotWriter.cpp | 67 +++++++++- src/uscxml/debug/SCXMLDotWriter.h | 2 + src/uscxml/transform/ChartToFSM.cpp | 30 +---- src/uscxml/transform/FlatStateIdentifier.h | 204 +++++++++++++++++------------ test/CMakeLists.txt | 4 + test/src/test-flat-stateid.cpp | 57 ++++++++ 8 files changed, 258 insertions(+), 120 deletions(-) create mode 100644 test/src/test-flat-stateid.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 62bb177..4905554 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -806,17 +806,17 @@ if (NOT DISABLE_ICAL AND NOT DISABLE_ALL) endif() set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES_ORIG}) - set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES_SHARED}) - if (NOT DEFINED ENV{LIBJINGLE_ROOT_DIR}) - set(ENV{LIBJINGLE_ROOT_DIR} "/Users/sradomski/Documents/TK/Code/webrtc-work/trunk") - endif() else() set(LIBICAL_FOUND OFF) endif() OPTION(DISABLE_WEBRTC "Ignore libjingle (WebRTC)" OFF) if (NOT DISABLE_WEBRTC AND NOT DISABLE_ALL) - find_package(LIBJINGLE) + set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES_SHARED}) + if (NOT DEFINED ENV{LIBJINGLE_ROOT_DIR}) + set(ENV{LIBJINGLE_ROOT_DIR} "/Users/sradomski/Documents/TK/Code/webrtc-work/trunk") + endif() + find_package(LibJingle) if (LIBJINGLE_FOUND) include_directories (${LIBJINGLE_INCLUDE_DIRS}) list (APPEND USCXML_OPT_LIBS ${LIBJINGLE_LIBRARIES}) @@ -1097,6 +1097,8 @@ else() add_library(uscxml ${USCXML_FILES}) target_link_libraries(uscxml ${USCXML_OPT_LIBS} ${USCXML_CORE_LIBS}) endif() +INSTALL_LIBRARY(TARGETS uscxml COMPONENT library) + if (NOT CMAKE_CROSSCOMPILING) if (ENABLE_COTIRE) set_target_properties(uscxml PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "src/uscxml/pch.h") diff --git a/src/uscxml/Factory.cpp b/src/uscxml/Factory.cpp index e9b651f..3bad07f 100644 --- a/src/uscxml/Factory.cpp +++ b/src/uscxml/Factory.cpp @@ -228,6 +228,7 @@ void Factory::registerPlugins() { registerInvoker(invoker); } #endif +#endif #ifdef MILES_FOUND { @@ -334,7 +335,6 @@ void Factory::registerPlugins() { // registerIOProcessor(ioProcessor); } #endif -#endif #ifdef CURL_HAS_SMTP { diff --git a/src/uscxml/debug/SCXMLDotWriter.cpp b/src/uscxml/debug/SCXMLDotWriter.cpp index be053d7..1b9555e 100644 --- a/src/uscxml/debug/SCXMLDotWriter.cpp +++ b/src/uscxml/debug/SCXMLDotWriter.cpp @@ -454,6 +454,59 @@ void SCXMLDotWriter::writePerEventPorts(std::ostream& os, const DotState& dotSta } +std::string SCXMLDotWriter::htmlLabelForId(const std::string& stateId, int minRows) { + FlatStateIdentifier flatId(stateId); + + std::list::const_iterator listIter; + std::stringstream labelSS; + std::string seperator; + + labelSS << "active: "; + labelSS << "{"; + for (listIter = flatId.getActive().begin(); listIter != flatId.getActive().end(); listIter++) { + labelSS << seperator << *listIter; + seperator = ", "; + } + labelSS << "}"; + + if (flatId.getVisited().size() > 0) { + minRows--; + + labelSS << "
init: "; + + labelSS << "{"; + seperator = ""; + for (listIter = flatId.getVisited().begin(); listIter != flatId.getVisited().end(); listIter++) { + labelSS << seperator << *listIter; + seperator = ", "; + } + labelSS << "}"; + } + + if (flatId.getHistory().size() > 0) { + minRows--; + + seperator = ""; + std::string histSeperator = "
"; + + labelSS << "
history: "; + + std::map >::const_iterator histIter; + for (histIter = flatId.getHistory().begin(); histIter != flatId.getHistory().end(); histIter++) { + labelSS << histSeperator << histIter->first << ": {"; + + for (listIter = histIter->second.begin(); listIter != histIter->second.end(); listIter++) { + labelSS << seperator << *listIter; + seperator = ", "; + } + labelSS << "}"; + seperator = ""; + } + } + return labelSS.str(); +} + + void SCXMLDotWriter::writePerTargetPorts(std::ostream& os, const DotState& dotState, int stateLines) { // std::multimap > targets; // key is remote node, transition is element @@ -499,7 +552,7 @@ void SCXMLDotWriter::writePerTargetPorts(std::ostream& os, const DotState& dotSt _edges.insert(edge); std::stringstream outPortSS; - outPortSS << (_isFlat ? FlatStateIdentifier::toHTMLLabel(targetId) : "" + targetId + "" ); + outPortSS << (_isFlat ? htmlLabelForId(targetId) : "" + targetId + "" ); if (_isFlat) { outPortSS << "
events: {"; @@ -751,11 +804,11 @@ std::string SCXMLDotWriter::nameForNode(const Node& node) { if (InterpreterImpl::isFinal(elem) && _isFlat) { // ignore visited and history with final elements FlatStateIdentifier flatId(elem.getAttribute("id")); - return "" + flatId.active.front() + ""; + return "" + flatId.getActive().front() + ""; } if (elem.hasAttribute("id") && _isFlat) { - elemName = FlatStateIdentifier::toHTMLLabel(elem.getAttribute("id")); + elemName = htmlLabelForId(elem.getAttribute("id")); if (elemName.size() > 0) return elemName; } else if (elem.getTagName() == "scxml") { @@ -790,7 +843,13 @@ std::string SCXMLDotWriter::idForNode(const Node& node) { if (InterpreterImpl::isFinal(elem) && _isFlat) { // ignore visited and history with final elements FlatStateIdentifier flatId(elem.getAttribute("id")); - return flatId.activeId(); + + std::stringstream activeSS; + activeSS << "active-"; + for (std::list::const_iterator activeIter = flatId.getActive().begin(); activeIter != flatId.getActive().end(); activeIter++) { + activeSS << *activeIter << "-"; + } + return activeSS.str(); } if (elem.hasAttribute("name")) { diff --git a/src/uscxml/debug/SCXMLDotWriter.h b/src/uscxml/debug/SCXMLDotWriter.h index 61fbfad..04cd0fd 100644 --- a/src/uscxml/debug/SCXMLDotWriter.h +++ b/src/uscxml/debug/SCXMLDotWriter.h @@ -130,6 +130,8 @@ public: virtual void beforeTakingTransition(Interpreter interpreter, const Arabica::DOM::Element& transition, bool moreComing); virtual void beforeMicroStep(Interpreter interpreter); + static std::string htmlLabelForId(const std::string& stateId, int minRows = 0); + static void toDot(const std::string& filename, Interpreter interpreter, const Arabica::DOM::Element& transition = Arabica::DOM::Element()) { diff --git a/src/uscxml/transform/ChartToFSM.cpp b/src/uscxml/transform/ChartToFSM.cpp index 83b8195..9665b56 100644 --- a/src/uscxml/transform/ChartToFSM.cpp +++ b/src/uscxml/transform/ChartToFSM.cpp @@ -18,6 +18,7 @@ */ #include "uscxml/transform/ChartToFSM.h" +#include "uscxml/transform/FlatStateIdentifier.h" #include "uscxml/Factory.h" #include @@ -1009,33 +1010,8 @@ GlobalState::GlobalState(const Arabica::XPath::NodeSet& activeState historyIter->second.to_document_order(); } - // create a unique identifier for a global configuration - std::ostringstream idSS; - idSS << "active-"; - for (int i = 0; i < activeStates.size(); i++) { - if (!InterpreterImpl::isFinal(Element(activeStates[i]))) - isFinal = false; - idSS << ATTR_CAST(activeStates[i], "id") << "-"; - } - idSS << ";"; - idSS << "entered-"; - for (int i = 0; i < alreadyEnteredStates.size(); i++) { - idSS << ATTR_CAST(alreadyEnteredStates[i], "id") << "-"; - } - idSS << ";"; - - for(std::map >::const_iterator histIter = historyStates.begin(); - histIter != historyStates.end(); - histIter++) { - const Arabica::XPath::NodeSet& histStates = histIter->second; - idSS << "history--"; - idSS << histIter->first << "-"; - for (int i = 0; i < histStates.size(); i++) { - idSS << ATTR_CAST(histStates[i], "id") << "-"; - } - } - - stateId = idSS.str(); + FlatStateIdentifier flatStateId(activeStates, alreadyEnteredStates, historyStates); + stateId = flatStateId.getStateId(); } GlobalTransition::GlobalTransition(const Arabica::XPath::NodeSet& transitionSet, DataModel dataModel) { diff --git a/src/uscxml/transform/FlatStateIdentifier.h b/src/uscxml/transform/FlatStateIdentifier.h index 2ee0443..3a9ee49 100644 --- a/src/uscxml/transform/FlatStateIdentifier.h +++ b/src/uscxml/transform/FlatStateIdentifier.h @@ -20,134 +20,172 @@ #ifndef FLATSTATEIDENTIFIER_H_E9534AF9 #define FLATSTATEIDENTIFIER_H_E9534AF9 +#include "uscxml/Common.h" +#include "uscxml/DOMUtils.h" + +#include #include #include #include #include +#include + namespace uscxml { class USCXML_API FlatStateIdentifier { public: - FlatStateIdentifier(const std::string& identifier) { + FlatStateIdentifier(const Arabica::XPath::NodeSet& activeStates, + const Arabica::XPath::NodeSet& alreadyEnteredStates, + const std::map >& historyStates) { + for (int i = 0; i < activeStates.size(); i++) { + active.push_back(ATTR_CAST(activeStates[i], "id")); + } + + for (int i = 0; i < alreadyEnteredStates.size(); i++) { + visited.push_back(ATTR_CAST(alreadyEnteredStates[i], "id")); + } + + std::map >::const_iterator histIter; + for (histIter = historyStates.begin(); histIter != historyStates.end(); histIter++) { + for (int i = 0; i < histIter->second.size(); i++) { + histories[histIter->first].push_back(ATTR_CAST(histIter->second[i], "id")); + } + } + + initStateId(); + } + + + FlatStateIdentifier(const std::list& active, + const std::list& visited, + const std::map >& histories) : active(active), visited(visited), histories(histories) { + initStateId(); + } + + FlatStateIdentifier(const std::string& identifier) : stateId(identifier) { std::string parsedName; // parse unique state identifier std::stringstream elemNameSS(identifier); std::string section; while(std::getline(elemNameSS, section, ';')) { - if (boost::starts_with(section, "active-")) { - std::stringstream stateSS(section.substr(7)); + if (boost::starts_with(section, "active:{")) { + // active:{s0,s1,s2} + std::stringstream stateSS(section.substr(8, section.size() - 9)); std::string state; - while(std::getline(stateSS, state, '-')) { + while(std::getline(stateSS, state, ',')) { if (state.length() > 0) { active.push_back(state); } } - } else if (boost::starts_with(section, "entered-")) { - std::stringstream stateSS(section.substr(8)); + } else if (boost::starts_with(section, "entered:{")) { + // entered:{s0,s1,s2} + std::stringstream stateSS(section.substr(9, section.size() - 10)); std::string state; - while(std::getline(stateSS, state, '-')) { + while(std::getline(stateSS, state, ',')) { if (state.length() > 0) { visited.push_back(state); } } - } else if (boost::starts_with(section, "history-")) { - std::stringstream stateSS(section.substr(8)); + } else if (boost::starts_with(section, "history:{")) { + // history:{h0:{s1,s2},h1:{s2,s3}} + std::string histEntries(section.substr(9, section.length() - 10)); + std::string state; - std::string history; - while(std::getline(stateSS, state, '-')) { - if (state.length() > 0) { - if (history.size() == 0) { - history = state; - } else { - histories[history].push_back(state); - } - } else { - history = ""; + size_t start = 0; + size_t history = 0; + + while((history = histEntries.find(":", start)) != std::string::npos) { + std::string histName = histEntries.substr(start, history - start); + history++; + + size_t end = histEntries.find("}", start); + if (end == std::string::npos) + continue; + + std::stringstream stateSS(histEntries.substr(history + 1, end - history - 1)); + std::string state; + while(std::getline(stateSS, state, ',')) { + histories[histName].push_back(state); } + + start = end + 2; } } } } - std::string activeId() { - std::stringstream activeSS; - activeSS << "active-"; - for (std::list::const_iterator activeIter = active.begin(); activeIter != active.end(); activeIter++) { - activeSS << *activeIter << "-"; - } - return activeSS.str(); + const std::string& getStateId() { + return stateId; + } + + const std::list& getActive() { + return active; + } + + const std::list& getVisited() { + return visited; + } + + const std::map > & getHistory() { + return histories; } +protected: std::list active; std::list visited; std::map > histories; + std::string stateId; - static std::string toHTMLLabel(const std::string& identifier, int minRows = 0) { - FlatStateIdentifier flatId(identifier); - - std::list::const_iterator listIter; - std::stringstream labelSS; + void initStateId() { + std::stringstream stateIdSS; + std::string seperator; - -// labelSS << ""; -// labelSS << ""; -// labelSS << ""; // eat up rest of space -// -// labelSS << ""; -// labelSS << ""; -// labelSS << "
"; - - labelSS << "active: "; - labelSS << "{"; - for (listIter = flatId.active.begin(); listIter != flatId.active.end(); listIter++) { - labelSS << seperator << *listIter; - seperator = ", "; + stateIdSS << "active:{"; + for (std::list::const_iterator actIter = active.begin(); actIter != active.end(); actIter++) { + stateIdSS << seperator << *actIter; + seperator = ","; } - labelSS << "}"; - - if (flatId.visited.size() > 0) { - minRows--; - - labelSS << "
init: "; - - labelSS << "{"; - seperator = ""; - for (listIter = flatId.visited.begin(); listIter != flatId.visited.end(); listIter++) { - labelSS << seperator << *listIter; - seperator = ", "; - } - labelSS << "}"; + stateIdSS << "};"; + + seperator = ""; + stateIdSS << "entered:{"; + for (std::list::const_iterator visitIter = visited.begin(); visitIter != visited.end(); visitIter++) { + stateIdSS << seperator << *visitIter; + seperator = ","; } - -#if 1 - if (flatId.histories.size() > 0) { - minRows--; - - seperator = ""; - std::string histSeperator = "
"; - - labelSS << "
history: "; - - std::map >::const_iterator histIter; - for (histIter = flatId.histories.begin(); histIter != flatId.histories.end(); histIter++) { - labelSS << histSeperator << histIter->first << ": {"; - - for (listIter = histIter->second.begin(); listIter != histIter->second.end(); listIter++) { - labelSS << seperator << *listIter; - seperator = ", "; - } - labelSS << "}"; - seperator = ""; + stateIdSS << "};"; + + seperator = ""; + stateIdSS << "history:{"; + for (std::map >::const_iterator histIter = histories.begin(); histIter != histories.end(); histIter++) { + stateIdSS << seperator << histIter->first << ":{"; + seperator = ","; + std::string itemSeperator; + for (std::list::const_iterator histItemIter = histIter->second.begin(); histItemIter != histIter->second.end(); histItemIter++) { + stateIdSS << itemSeperator << *histItemIter; + itemSeperator = ","; } + stateIdSS << "}"; } -#endif -// while(minRows-- > 0) -// labelSS << "
"; - return labelSS.str(); + stateIdSS << "}"; + + stateId = stateIdSS.str(); + } + +#if 0 + std::string activeId() { + std::stringstream activeSS; + activeSS << "active-"; + for (std::list::const_iterator activeIter = active.begin(); activeIter != active.end(); activeIter++) { + activeSS << *activeIter << "-"; + } + return activeSS.str(); } +#endif + }; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b106d87..dc827d3 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -45,6 +45,10 @@ target_link_libraries(test-eventdelay uscxml) add_test(test-eventdelay ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-eventdelay) set_target_properties(test-eventdelay PROPERTIES FOLDER "Tests") +add_executable(test-flat-stateid src/test-flat-stateid.cpp) +add_test(test-flat-stateid ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-flat-stateid) +set_target_properties(test-flat-stateid PROPERTIES FOLDER "Tests") + if (OFF) add_executable(test-dirmon src/test-dirmon.cpp) target_link_libraries(test-dirmon uscxml) diff --git a/test/src/test-flat-stateid.cpp b/test/src/test-flat-stateid.cpp new file mode 100644 index 0000000..7bc826c --- /dev/null +++ b/test/src/test-flat-stateid.cpp @@ -0,0 +1,57 @@ +#include "uscxml/transform/FlatStateIdentifier.h" +#include + +int main(int argc, char** argv) { + std::list::const_iterator listIter; + + { + std::string stateId = "active:{};entered:{};history:{}"; + uscxml::FlatStateIdentifier flat1(stateId); + assert(flat1.getActive().size() == 0); + assert(flat1.getVisited().size() == 0); + assert(flat1.getHistory().size() == 0); + + uscxml::FlatStateIdentifier flat2(flat1.getActive(), flat1.getVisited(), flat1.getHistory()); + assert(flat2.getStateId() == stateId); + } + + { + std::string stateId = "active:{s1};entered:{s1,s2};history:{}"; + uscxml::FlatStateIdentifier flat1(stateId); + assert(flat1.getActive().size() == 1); + assert(flat1.getVisited().size() == 2); + assert(flat1.getHistory().size() == 0); + + uscxml::FlatStateIdentifier flat2(flat1.getActive(), flat1.getVisited(), flat1.getHistory()); + assert(flat2.getStateId() == stateId); + } + + { + + std::string stateId = "active:{s0,s1,s2};entered:{s0,s1,s2};history:{h0:{s1,s2},h1:{s2,s3}}"; + uscxml::FlatStateIdentifier flat1(stateId); + + listIter = flat1.getActive().begin(); + assert(*listIter++ == "s0"); + assert(*listIter++ == "s1"); + assert(*listIter++ == "s2"); + + listIter = flat1.getVisited().begin(); + assert(*listIter++ == "s0"); + assert(*listIter++ == "s1"); + assert(*listIter++ == "s2"); + + assert(flat1.getHistory().find("h0") != flat1.getHistory().end()); + listIter = flat1.getHistory().at("h0").begin(); + assert(*listIter++ == "s1"); + assert(*listIter++ == "s2"); + + assert(flat1.getHistory().find("h1") != flat1.getHistory().end()); + listIter = flat1.getHistory().at("h1").begin(); + assert(*listIter++ == "s2"); + assert(*listIter++ == "s3"); + + uscxml::FlatStateIdentifier flat2(flat1.getActive(), flat1.getVisited(), flat1.getHistory()); + assert(flat2.getStateId() == stateId); + } +} \ No newline at end of file -- cgit v0.12