diff options
Diffstat (limited to 'src/uscxml/transform/ChartToFSM.cpp')
-rw-r--r-- | src/uscxml/transform/ChartToFSM.cpp | 2035 |
1 files changed, 0 insertions, 2035 deletions
diff --git a/src/uscxml/transform/ChartToFSM.cpp b/src/uscxml/transform/ChartToFSM.cpp deleted file mode 100644 index aa9dda8..0000000 --- a/src/uscxml/transform/ChartToFSM.cpp +++ /dev/null @@ -1,2035 +0,0 @@ -/** - * @file - * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) - * @copyright Simplified BSD - * - * @cond - * This program is free software: you can redistribute it and/or modify - * it under the terms of the FreeBSD license as published by the FreeBSD - * project. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the FreeBSD license along with this - * program. If not, see <http://www.opensource.org/licenses/bsd-license>. - * @endcond - */ - -#include "uscxml/transform/ChartToFSM.h" -#include "uscxml/transform/FlatStateIdentifier.h" -#include "uscxml/Convenience.h" -#include "uscxml/Factory.h" -#include "uscxml/debug/Complexity.h" - -#include <DOM/SAX2DOM/SAX2DOM.hpp> -#include <DOM/io/Stream.hpp> -#include <glog/logging.h> - -#include <iostream> -#include "uscxml/UUID.h" -#include <math.h> -#include <string.h> -#include <algorithm> -#undef max -#include <limits> - -#define UNDECIDABLE 2147483647 -#define MIN(X,Y) ((X) < (Y) ? (X) : (Y)) - -#define DUMP_STATS(nrTrans, disregardTime) \ -uint64_t now = tthread::chrono::system_clock::now(); \ -if (now - _lastTimeStamp > 1000 || disregardTime) { \ - std::cerr << "## Transition: " << _perfTransUsed << " / " << _perfTransTotal << " [" << _perfTransProcessed << "/sec]"; \ - if (nrTrans > 0) { \ - std::cerr << " - 2**" << nrTrans << " = " << pow(2.0, static_cast<double>(nrTrans)); \ - } \ - std::cerr << std::endl; \ - std::cerr << "## State : " << _globalConf.size() << " found / " << _perfStackSize << " stacked / " << _perfStatesTotal << " seen [" << _perfStatesProcessed << "/sec]" << std::endl; \ - std::cerr << "## Microstep : " << _perfMicroStepTotal << " [" << _perfMicroStepProcessed << "/sec]" << std::endl; \ - std::cerr << "## Cached : " << _perfStatesCachedTotal << " [" << _perfStatesCachedProcessed << "/sec]" << std::endl; \ - std::cerr << "## Skipped : " << _perfStatesSkippedTotal << " [" << _perfStatesSkippedProcessed << "/sec]" << std::endl; \ - std::cerr << "## Queues : " << (_maxEventRaisedChain == UNDECIDABLE ? "UNK" : toStr(_maxEventRaisedChain)) << " / " << (_maxEventSentChain == UNDECIDABLE ? "UNK" : toStr(_maxEventSentChain)) << std::endl; \ - std::cerr << "toFSM: "; \ - std::cerr << _perfTransUsed << ", " << _perfTransTotal << ", " << _perfTransProcessed << ", "; \ - std::cerr << _globalConf.size() << ", " << _perfStackSize << ", " << _perfStatesTotal << ", " << _perfStatesProcessed << ", "; \ - std::cerr << _perfMicroStepTotal << ", " << _perfMicroStepProcessed << ", "; \ - std::cerr << _perfStatesCachedTotal << ", " << _perfStatesCachedProcessed << ", " << _perfStatesSkippedTotal << ", " << _perfStatesSkippedProcessed << ", "; \ - std::cerr << (_maxEventRaisedChain == UNDECIDABLE ? "UNK" : toStr(_maxEventRaisedChain)) << ", " << (_maxEventSentChain == UNDECIDABLE ? "UNK" : toStr(_maxEventSentChain)) << std::endl; \ - std::cerr << std::endl; \ - _perfTransProcessed = 0; \ - _perfStatesProcessed = 0; \ - _perfStatesCachedProcessed = 0; \ - _perfStatesSkippedProcessed = 0; \ - _perfMicroStepProcessed = 0; \ - if (!disregardTime)\ - _lastTimeStamp = now; \ -} - -//std::cerr << "Q: " << (_maxEventRaisedChain == UNDECIDABLE ? "UNK" : toStr(_maxEventRaisedChain)) << " / " << (_maxEventSentChain == UNDECIDABLE ? "UNK" : toStr(_maxEventSentChain)) << std::endl; - -#define DUMP_TRANSSET(where) \ -{\ -std::cout << std::endl;\ -std::cout << "** " << transitions.size() << " ** " << where << std::endl;\ - for (size_t m = 0; m < transitions.size(); m++) {\ - std::cout << transitions[m] << std::endl;\ - }\ -} - -namespace uscxml { - - -using namespace Arabica::DOM; -using namespace Arabica::XPath; - - -#define DETAIL_EXEC_CONTENT(field, actPtr) \ -std::cerr << " " << #field << " / " << TAGNAME_CAST(actPtr->field) << " ("; \ -NodeSet<std::string> contents = filterChildType(Node_base::ELEMENT_NODE, actPtr->field, true); \ -for (size_t i = 0; i < contents.size(); i++) { \ - std::cerr << " " << TAGNAME_CAST(contents[i]); \ -} \ -std::cerr << ")"; - - - -ChartToFSM::ChartToFSM(const Interpreter& other) { - - cloneFrom(other.getImpl()); - - _transitionsFromTree = true; - _keepInvalidTransitions = false; - _lastTimeStamp = tthread::chrono::system_clock::now(); - _perfTransProcessed = 0; - _perfTransTotal = 0; - _perfTransUsed = 0; - _perfStatesTotal = 0; - _perfStatesProcessed = 0; - _perfStackSize = 0; - _perfStatesSkippedProcessed = 0; - _perfStatesSkippedTotal = 0; - _perfStatesCachedProcessed = 0; - _perfStatesCachedTotal = 0; - _perfMicroStepProcessed = 0; - _perfMicroStepTotal = 0; - - if (envVarIEquals("USCXML_TRANSFORM_TRANS_FROM", "powerset")) - _transitionsFromTree = false; - - _start = NULL; - _currGlobalTransition = NULL; - _transTree = NULL; - - _lastStateIndex = 0; - _lastActiveIndex = 0; - _lastTransIndex = 0; - - _maxEventSentChain = 0; - _maxEventRaisedChain = 0; - _doneEventRaiseTolerance = 0; - _skipEventChainCalculations = false; - - addMonitor(this); -} - -ChartToFSM::~ChartToFSM() { - std::map<std::string, GlobalState*>::iterator confIter = _globalConf.begin(); - while(confIter != _globalConf.end()) { - std::list<GlobalTransition*>::iterator transIter = confIter->second->sortedOutgoing.begin(); - while (transIter != confIter->second->sortedOutgoing.end()) { - delete *transIter; - transIter++; - } - delete confIter->second; - confIter++; - } - - // tear down caches - Arabica::XPath::NodeSet<std::string> allTransitions = DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "transition", _scxml, true); - for (size_t i = 0; i < allTransitions.size(); i++) { - _transParents.erase(allTransitions[i]); - } -} - -Document<std::string> ChartToFSM::getDocument() const { - if (_flatDoc) - return _flatDoc; - return _document; -} - -InterpreterState ChartToFSM::interpret() { - - init(); - setupIOProcessors(); - - { - std::list<std::set<Element<std::string> > > allConfig = Complexity::getAllConfigurations(_scxml); - for (std::list<std::set<Element<std::string> > >::iterator confIter = allConfig.begin(); confIter != allConfig.end(); confIter++) { - std::string seperator; - NodeSet<std::string> configNodeSet; - std::set<Element<std::string> > config = *confIter; - for (std::set<Element<std::string> >::iterator elemIter = config.begin(); elemIter != config.end(); elemIter++) { -// std::cerr << seperator << ATTR((*elemIter), "id"); - seperator = ","; - configNodeSet.push_back(*elemIter); - } - assert(isLegalConfiguration(configNodeSet)); -// std::cerr << std::endl; - } - } - std::map<size_t, size_t> histoGramm = Complexity::getTransitionHistogramm(_scxml); -// abort(); - - uint64_t complexity = Complexity::stateMachineComplexity(this) + 1; - std::cerr << "Approximate Complexity: " << complexity << std::endl; - std::cerr << "Approximate Active Complexity: " << Complexity::stateMachineComplexity(this, Complexity::IGNORE_HISTORY | Complexity::IGNORE_NESTED_DATA) + 1 << std::endl; - - if (complexity > 1000) { - _skipEventChainCalculations = true; - _maxEventRaisedChain = UNDECIDABLE; - _maxEventSentChain = UNDECIDABLE; - } - // initialize the datamodel - std::string datamodelName; - if (datamodelName.length() == 0 && HAS_ATTR(_scxml, "datamodel")) - datamodelName = ATTR(_scxml, "datamodel"); - if (datamodelName.length() == 0 && HAS_ATTR(_scxml, "profile")) // SCION SCXML uses profile to specify datamodel - datamodelName = ATTR(_scxml, "profile"); - if(datamodelName.length() > 0) { - _dataModel = _factory->createDataModel(datamodelName, this); - if (!_dataModel) { - Event e; - e.data.compound["cause"] = Data("Cannot instantiate datamodel", Data::VERBATIM); - throw e; - } - } else { - _dataModel = _factory->createDataModel("null", this); - } - if(datamodelName.length() > 0 && !_dataModel) { - LOG(ERROR) << "No datamodel for " << datamodelName << " registered"; - } - - // setup caches - { - Arabica::XPath::NodeSet<std::string> allTransitions = DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "transition", _scxml, true); - indexedTransitions.reserve(allTransitions.size()); - for (size_t i = 0; i < allTransitions.size(); i++) { - _transParents[allTransitions[i]] = InterpreterImpl::getParentState(allTransitions[i]); - } - } - - // identify all history elements - NodeSet<std::string> histories = DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "history", _scxml, true); - for (size_t i = 0; i < histories.size(); i++) { - _historyTargets[ATTR_CAST(histories[i], "id")] = Element<std::string>(histories[i]); - } - - _binding = (HAS_ATTR(_scxml, "binding") && iequals(ATTR(_scxml, "binding"), "late") ? LATE : EARLY); - _alreadyFlat = (HAS_ATTR(_scxml, "flat") && stringIsTrue(ATTR(_scxml, "flat"))); - - if (_alreadyFlat) { - reassembleFromFlat(); - return _state; - } - - // set invokeid for all invokers to parent state if none given - NodeSet<std::string> invokers = DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "invoke", _scxml, true); - for (size_t i = 0; i < invokers.size(); i++) { - Element<std::string> invokerElem = Element<std::string>(invokers[i]); - invokerElem.setAttribute("parent", ATTR_CAST(invokerElem.getParentNode(), "id")); - } - // reset - _globalConf.clear(); - _currGlobalTransition = NULL; - - // very first state - _start = new GlobalState(_configuration, _alreadyEntered, _historyValue, _nsInfo.xmlNSPrefix, this); - _globalConf[_start->stateId] = _start; - _globalConf[_start->stateId]->index = _lastStateIndex++; - - NodeSet<std::string> initialTransitions; - - // enter initial configuration - Arabica::XPath::NodeSet<std::string> initialStates; - initialStates = getInitialStates(); - assert(initialStates.size() > 0); - for (size_t i = 0; i < initialStates.size(); i++) { - Element<std::string> initialElem = _document.createElementNS(_nsInfo.nsURL, "initial"); - _nsInfo.setPrefix(initialElem); - initialElem.setAttribute("generated", "true"); - Element<std::string> transitionElem = _document.createElementNS(_nsInfo.nsURL, "transition"); - _nsInfo.setPrefix(transitionElem); - transitionElem.setAttribute("target", ATTR_CAST(initialStates[i], "id")); - initialElem.appendChild(transitionElem); - _scxml.appendChild(initialElem); - initialTransitions.push_back(transitionElem); - } - - if (!_skipEventChainCalculations) - annotateRaiseAndSend(_scxml); - -// std::cout << _scxml << std::endl; - - indexTransitions(); - - // add initial transitions as least prior - for (size_t i = 0; i < initialTransitions.size() ; i++) { - indexedTransitions.push_back(Element<std::string>(initialTransitions[i])); - } - - // set index attribute for transitions - for (size_t i = 0; i < indexedTransitions.size(); i++) { -// std::cerr << toStr(i) << ":" << (HAS_ATTR(indexedTransitions[i], "line_start") ? ATTR(indexedTransitions[i], "line_start") : ""); -// std::cerr << "\t" << DOMUtils::xPathForNode(indexedTransitions[i]) << std::endl; - indexedTransitions[i].setAttribute("index", toStr(i)); - } - -// int lastTransIndex = indexedTransitions.size(); -// for (size_t i = 0; i < initialTransitions.size() ; i++, lastTransIndex++) { -// indexedTransitions[i].setAttribute("index", toStr(indexedTransitions.size() - 1 - i)); -// } - - // gather and set index attribute o states - NodeSet<std::string> allStates = getAllStates(); - allStates.to_document_order(); - - indexedStates.resize(allStates.size()); - for (size_t i = 0; i < allStates.size(); i++) { - Element<std::string> state = Element<std::string>(allStates[i]); - - // while we are iterating, determine deepest nested level - size_t nrAncs = getProperAncestors(state, _scxml).size(); - if (_doneEventRaiseTolerance < nrAncs) - _doneEventRaiseTolerance = nrAncs; - - state.setAttribute("index", toStr(i)); - indexedStates[i] = state; - } - -// std::cerr << _scxml << std::endl; - - // create a _flatDoc for the FSM - DOMImplementation<std::string> domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation(); - _flatDoc = domFactory.createDocument(_document.getNamespaceURI(), "", 0); - - GlobalTransition* globalTransition = new GlobalTransition(initialTransitions, _dataModel, this); - globalTransition->index = _lastTransIndex++; - - _start->sortedOutgoing.push_back(globalTransition); - globalTransition->source = _start->stateId; - _currGlobalTransition = globalTransition; - - enterStates(initialTransitions); - globalTransition->destination = FlatStateIdentifier::toStateId(_configuration); - globalTransition->activeDestination = globalTransition->destination; - - explode(); - - DUMP_STATS(0, true); - -#if 0 - // print set of global configurations - for(std::map<std::string, GlobalState*>::iterator globalConfIter = _globalConf.begin(); - globalConfIter != _globalConf.end(); - globalConfIter++) { - std::cerr << globalConfIter->first << std::endl; - } - std::cerr << _globalConf.size() << std::endl; -#endif - - std::cerr << "Actual Complexity: " << _globalConf.size() << std::endl; - std::cerr << "Actual Active Complexity: " << _activeConf.size() << std::endl; - std::cerr << "Internal Queue: " << _maxEventRaisedChain << std::endl; - std::cerr << "External Queue: " << _maxEventSentChain << std::endl; - -// if (complexity < _globalConf.size()) -// throw std::runtime_error("Upper bound for states exceeded"); - - return _state; -} - -void ChartToFSM::executeContent(const Arabica::DOM::Element<std::string>& content, bool rethrow) { -// std::cerr << content << std::endl; -// std::cerr << TAGNAME(content) << std::endl; - - GlobalTransition::Action action; - - NodeList<std::string> childs = content.getChildNodes(); - for (unsigned int i = 0; i < childs.getLength(); i++) { - Node_base::Type type = childs.item(i).getNodeType(); - if (type == Node_base::ELEMENT_NODE || type == Node_base::COMMENT_NODE || type == Node_base::TEXT_NODE) { - goto HAS_VALID_CHILDREN; - } - } - return; - -HAS_VALID_CHILDREN: - if (false) { - } else if (TAGNAME(content) == "transition") { - action.transition = content; - } else if (TAGNAME(content) == "onexit") { - action.onExit = content; - } else if (TAGNAME(content) == "onentry") { - action.onEntry = content; - } else if (TAGNAME(content) == "history") { - assert(false); - } else { // e.g. global script elements - return; - } - - if (!_skipEventChainCalculations && - (_maxEventRaisedChain != UNDECIDABLE || _maxEventSentChain != UNDECIDABLE)) { - assert(content.hasAttribute("raise") && content.hasAttribute("send")); - - std::string raiseAttr = content.getAttribute("raise"); - std::string sendAttr = content.getAttribute("send"); - - _currGlobalTransition->eventsRaised = (raiseAttr == "-1" ? UNDECIDABLE : _currGlobalTransition->eventsRaised + strTo<uint32_t>(raiseAttr)); - _currGlobalTransition->eventsSent = (sendAttr == "-1" ? UNDECIDABLE : _currGlobalTransition->eventsSent + strTo<uint32_t>(sendAttr)); - - if (_currGlobalTransition->eventsRaised > _maxEventRaisedChain) - _maxEventRaisedChain = _currGlobalTransition->eventsRaised; - if (_currGlobalTransition->eventsSent > _maxEventSentChain) - _maxEventSentChain = _currGlobalTransition->eventsSent; - } - - _currGlobalTransition->actions.push_back(action); - _currGlobalTransition->hasExecutableContent = true; -} - -void ChartToFSM::invoke(const Arabica::DOM::Element<std::string>& element) { - GlobalTransition::Action action; - action.invoke = element; - _currGlobalTransition->actions.push_back(action); - _currGlobalTransition->hasExecutableContent = true; -} - -void ChartToFSM::cancelInvoke(const Arabica::DOM::Element<std::string>& element) { - GlobalTransition::Action action; - action.uninvoke = element; - _currGlobalTransition->actions.push_back(action); - _currGlobalTransition->hasExecutableContent = true; -} - -void ChartToFSM::internalDoneSend(const Arabica::DOM::Element<std::string>& state, const Arabica::DOM::Element<std::string>& doneData) { - if (!isState(state)) - return; - -// if (LOCALNAME(state) == "scxml") -// return; - -// if (parentIsScxmlState(state)) -// return; - -// return; -// std::cerr << "internalDoneSend: " << state << std::endl; - - // create onentry with a raise element - Element<std::string> onentry = _flatDoc.createElementNS(_nsInfo.nsURL, "onentry"); - _nsInfo.setPrefix(onentry); - - Element<std::string> raise = _flatDoc.createElementNS(_nsInfo.nsURL, "raise"); - _nsInfo.setPrefix(raise); - - onentry.appendChild(raise); - - if (doneData) { - Arabica::XPath::NodeSet<std::string> contents = DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "content", doneData); - if (contents.size() > 0) { - Node<std::string> imported = _flatDoc.importNode(contents[0], true); - raise.appendChild(imported); - } - Arabica::XPath::NodeSet<std::string> params = DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "param", doneData); - if (params.size() > 0) { - Node<std::string> imported = _flatDoc.importNode(params[0], true); - raise.appendChild(imported); - } - } - - - raise.setAttribute("event", "done.state." + ATTR_CAST(state, "id")); // parent?! - - GlobalTransition::Action action; - action.raiseDone = onentry; // HERE! - - _currGlobalTransition->actions.push_back(action); - if (!_skipEventChainCalculations && - (_maxEventRaisedChain != UNDECIDABLE || _maxEventSentChain != UNDECIDABLE)) - _currGlobalTransition->eventsRaised++; - _currGlobalTransition->hasExecutableContent = true; - -} - -static bool isSuperset(const GlobalTransition* t1, const GlobalTransition* t2) { - bool isSuperset = true; - - if (t1->transitionRefs.size() >= t2->transitionRefs.size()) - return false; - - NodeSet<std::string> t1Trans = t1->getTransitions(); - NodeSet<std::string> t2Trans = t2->getTransitions(); - - for (size_t i = 0; i < t1Trans.size(); i++) { - if (!InterpreterImpl::isMember(t1Trans[i], t2Trans)) { - isSuperset = false; - } - } - return isSuperset; -} - -// return false if two transitions have the same source -std::map<Arabica::DOM::Node<std::string>, Arabica::DOM::Node<std::string> > ChartToFSM::_transParents; -bool ChartToFSM::filterSameState(const NodeSet<std::string>& transitions) { - - for (unsigned int i = 0; i < transitions.size(); i++) { - Node<std::string> p1 = _transParents[transitions[i]]; - - for (unsigned int j = i + 1; j < transitions.size(); j++) { -// if (i == j) -// continue; - Node<std::string> p2 = _transParents[transitions[j]]; - - if (p1 == p2) - return false; - } - } - return true; -} - -static bool filterSameHierarchy(const NodeSet<std::string>& transitions) { - for (unsigned int i = 0; i < transitions.size(); i++) { - Node<std::string> t1 = transitions[i]; - Node<std::string> p1 = InterpreterImpl::getParentState(t1); - for (unsigned int j = i + 1; j < transitions.size(); j++) { - Node<std::string> t2 = transitions[j]; - Node<std::string> p2 = InterpreterImpl::getParentState(t2); - while(p2) { - if (p1 == p2) { - return false; - } - p2 = p2.getParentNode(); - } - } - } - return true; -} - - -static bool filterChildEnabled(const NodeSet<std::string>& transitions) { - // drop any transition that is already enabled by a child - NodeSet<std::string> filteredTransitions; - for (unsigned int i = 0; i < transitions.size(); i++) { - Node<std::string> t1 = transitions[i]; - Node<std::string> p1 = InterpreterImpl::getParentState(t1); - for (unsigned int j = 0; j < transitions.size(); j++) { - if (i == j) - continue; - Node<std::string> t2 = transitions[j]; - Node<std::string> p2 = InterpreterImpl::getParentState(t2); - p2 = p2.getParentNode(); // TODO: think about again! - while(p2) { - if (p1 == p2) { - std::string eventDesc1 = ATTR_CAST(t1, "event"); - std::string eventDesc2 = ATTR_CAST(t2, "event"); - if (nameMatch(eventDesc1, eventDesc2)) { - return false; - } - } - p2 = p2.getParentNode(); - } - } - filteredTransitions.push_back(t1); - ; - } - return true; -} - -bool ChartToFSM::hasForeachInBetween(const Arabica::DOM::Node<std::string>& ancestor, const Arabica::DOM::Node<std::string>& child) { - if (!ancestor || !child) - return false; - - Node<std::string> currChild = child; - while(currChild != ancestor) { - if (!currChild.getParentNode()) - return false; - if (TAGNAME_CAST(currChild) == "foreach") - return true; - currChild = currChild.getParentNode(); - } - return false; -} - -void ChartToFSM::annotateRaiseAndSend(const Arabica::DOM::Element<std::string>& root) { - NodeSet<std::string> execContent; - execContent.push_back(DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "transition", _scxml, true)); - execContent.push_back(DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "onentry", _scxml, true)); - execContent.push_back(DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "onexit", _scxml, true)); - for (size_t i = 0; i < execContent.size(); i++) { - Element<std::string> execContentElem(execContent[i]); - - int nrRaise = 0; - NodeSet<std::string> raise = DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "raise", execContent[i], true); - for (size_t j = 0; j < raise.size(); j++) { - if (hasForeachInBetween(execContent[i], raise[j])) { - execContentElem.setAttribute("raise", "-1"); - goto DONE_COUNT_RAISE; - } else { - nrRaise++; - } - } - execContentElem.setAttribute("raise", toStr(nrRaise)); - -DONE_COUNT_RAISE: - - int nrSend = 0; - NodeSet<std::string> sends = DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "send", execContent[i], true); - for (size_t j = 0; j < sends.size(); j++) { - if (hasForeachInBetween(execContent[i], sends[j])) { - execContentElem.setAttribute("send", "-1"); - goto DONE_COUNT_SEND; - } else { - nrSend++; - } - } - execContentElem.setAttribute("send", toStr(nrSend)); - -DONE_COUNT_SEND: - ; - } -} - -void ChartToFSM::annotateDomain() { - Arabica::XPath::NodeSet<std::string> allTransitions = DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "transition", _scxml, true); - for (size_t i = 0; i < allTransitions.size(); i++) { - Element<std::string> transition(allTransitions[i]); - Arabica::DOM::Node<std::string> domain = getTransitionDomain(transition); - if (domain) { - transition.setAttribute("domain", (HAS_ATTR_CAST(domain, "id") ? ATTR_CAST(domain, "id") : DOMUtils::xPathForNode(domain))); - } else { - transition.setAttribute("domain", "#UNDEF"); - } - } -} - -void ChartToFSM::annotateExitSet() { - Arabica::XPath::NodeSet<std::string> allTransitions = DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "transition", _scxml, true); - for (size_t i = 0; i < allTransitions.size(); i++) { - Element<std::string> transition(allTransitions[i]); - Arabica::DOM::Node<std::string> domain = getTransitionDomain(transition); - - Arabica::XPath::NodeSet<std::string> allStates = getAllStates(); - std::ostringstream exitSetStr; - std::string seperator = ""; - for (size_t j = 0; j < allStates.size(); j++) { - Element<std::string> state(allStates[j]); - if (state.getParentNode() == domain) { - exitSetStr << seperator << (HAS_ATTR(state, "id") ? ATTR(state, "id") : DOMUtils::xPathForNode(state)); - seperator = ", "; - } - } - transition.setAttribute("exitset", exitSetStr.str()); - } -} - -void ChartToFSM::annotateEntrySet() { - Arabica::XPath::NodeSet<std::string> allTransitions = DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "transition", _scxml, true); - for (size_t i = 0; i < allTransitions.size(); i++) { - Element<std::string> transition(allTransitions[i]); - - NodeSet<std::string> tmpTransitions; - NodeSet<std::string> tmpStatesToEnter; - NodeSet<std::string> tmpStatesForDefaultEntry; - std::map<std::string, Arabica::DOM::Node<std::string> > tmpDefaultHistoryContent; - - tmpTransitions.push_back(transition); - computeEntrySet(tmpTransitions, tmpStatesToEnter, tmpStatesForDefaultEntry, tmpDefaultHistoryContent); - - std::ostringstream entrySetStr; - std::string seperator = ""; - - for (size_t j = 0; j < tmpStatesToEnter.size(); j++) { - Element<std::string> state(tmpStatesToEnter[j]); - entrySetStr << seperator << (HAS_ATTR(state, "id") ? ATTR(state, "id") : DOMUtils::xPathForNode(state)); - seperator = ", "; - } - for (size_t j = 0; j < tmpStatesForDefaultEntry.size(); j++) { - Element<std::string> state(tmpStatesForDefaultEntry[j]); - entrySetStr << seperator << (HAS_ATTR(state, "id") ? ATTR(state, "id") : DOMUtils::xPathForNode(state)); - seperator = ", "; - } - transition.setAttribute("entryset", entrySetStr.str()); - - } -} - -void ChartToFSM::annotateConflicts() { - Arabica::XPath::NodeSet<std::string> allTransitions = DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "transition", _scxml, true); - Arabica::XPath::NodeSet<std::string> allStates = getAllStates(); - - for (size_t i = 0; i < allTransitions.size(); i++) { - Element<std::string> t1(allTransitions[i]); - if (!isState(Element<std::string>(t1.getParentNode()))) - continue; - - Arabica::DOM::Node<std::string> d1 = getTransitionDomain(t1); - - Arabica::XPath::NodeSet<std::string> exitSet1; - for (size_t k = 0; k < allStates.size(); k++) { - Element<std::string> state(allStates[k]); - if (isDescendant(state, d1)) { - exitSet1.push_back(state); - } - } - - std::ostringstream preemptionStr; - std::string seperator = ""; - - for (size_t j = 0; j < allTransitions.size(); j++) { - if ( i == j) - continue; - - Element<std::string> t2(allTransitions[j]); - if (!isState(Element<std::string>(t2.getParentNode()))) - continue; - - Arabica::DOM::Node<std::string> d2 = getTransitionDomain(t2); - - Arabica::XPath::NodeSet<std::string> exitSet2; - for (size_t k = 0; k < allStates.size(); k++) { - Element<std::string> state(allStates[k]); - if (isDescendant(state, d2)) { - exitSet2.push_back(state); - } - } - - if (hasIntersection(exitSet1, exitSet2)) { - preemptionStr << seperator << (HAS_ATTR(t2, "priority") ? ATTR(t2, "priority") : DOMUtils::xPathForNode(t2)); - seperator = ", "; - } - -// if (isDescendant(d1, d2) || isDescendant(d2, d1) || d1 == d2) { -// preemptionStr << seperator << ATTR(t2, "priority"); -// seperator = ", "; -// } - - } - if (preemptionStr.str().size() > 0) - t1.setAttribute("conflicts", preemptionStr.str()); - - } -} - -void ChartToFSM::indexTransitions() { - indexedTransitions.clear(); - indexTransitions(_scxml); - -#if 1 - size_t index = indexedTransitions.size() - 1; - for (std::vector<Arabica::DOM::Element<std::string> >::iterator transIter = indexedTransitions.begin(); transIter != indexedTransitions.end(); transIter++) { - transIter->setAttribute("priority", toStr(index)); - index--; - } -#else - size_t index = 0; - for (std::vector<Arabica::DOM::Element<std::string> >::iterator transIter = indexedTransitions.begin(); transIter != indexedTransitions.end(); transIter++) { - transIter->setAttribute("priority", toStr(index)); - index++; - } -#endif - // reverse indices for most prior to be in front - //std::reverse(indexedTransitions.begin(), indexedTransitions.end()); -} - -#if 0 -void ChartToFSM::indexTransitions(const Arabica::DOM::Element<std::string>& root) { - // breadth first traversal of transitions - Arabica::XPath::NodeSet<std::string> levelTransitions = DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "transition", root); - for (int i = levelTransitions.size() - 1; i >= 0; i--) { - // push into index starting with least prior - indexedTransitions.push_back(Element<std::string>(levelTransitions[i])); - } - - Arabica::XPath::NodeSet<std::string> nextLevel = filterChildType(Arabica::DOM::Node_base::ELEMENT_NODE, root); - for (int i = nextLevel.size() - 1; i >= 0; i--) { - Element<std::string> stateElem = Element<std::string>(nextLevel[i]); - if (isState(stateElem)) - indexTransitions(stateElem); - } -} - -#else - -void ChartToFSM::indexTransitions(const Arabica::DOM::Element<std::string>& root) { - // Post-order traversal of transitions - Arabica::XPath::NodeSet<std::string> childStates = getChildStates(root); - for (size_t i = 0; i < childStates.size(); i++) { - Element<std::string> childElem(childStates[i]); - indexTransitions(childElem); - } - - Arabica::XPath::NodeSet<std::string> levelTransitions = DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "transition", root); - for (size_t i = 0; i < levelTransitions.size(); i++) { - // push into index starting with least prior - indexedTransitions.push_back(Element<std::string>(levelTransitions[i])); - } - -} - -#endif -bool GlobalTransition::operator< (const GlobalTransition& other) const { - const std::vector<Arabica::DOM::Element<std::string> >& indexedTransitions = interpreter->indexedTransitions; - NodeSet<std::string> transitions = getTransitions(); - - for (std::vector<Element<std::string> >::const_iterator transIter = indexedTransitions.begin(); transIter != indexedTransitions.end(); transIter++) { - const Element<std::string>& refTrans = *transIter; - NodeSet<std::string> otherTransitions = other.getTransitions(); - - if (InterpreterImpl::isMember(refTrans, transitions) && !InterpreterImpl::isMember(refTrans, otherTransitions)) { - return true; - } - if (!InterpreterImpl::isMember(refTrans, transitions) && InterpreterImpl::isMember(refTrans, otherTransitions)) { - return false; - } - } - return true; // actually, they are equal -} - -template <typename T> bool PtrComp(const T * const & a, const T * const & b) { - return *a < *b; -} - - -/** - * subset only removes transitions without cond -> superset will always be enabled - */ -bool hasUnconditionalSuperset(GlobalTransition* first, GlobalTransition* second) { - - NodeSet<std::string> firstTransitions = first->getTransitions(); - NodeSet<std::string> secondTransitions = second->getTransitions(); - -// if (first->condition.size() > 0) -// return false; - - if (isSuperset(second, first)) { - for (size_t i = 0; i < firstTransitions.size(); i++) { - if (!InterpreterImpl::isMember(firstTransitions[i], secondTransitions)) { - if (HAS_ATTR_CAST(firstTransitions[i], "cond")) { - return false; // second can't be removed - } - } - } - return true; // remove second - } - return false; //second can't be removed -} - -/** - * earlier transition is conditionless for same event - */ -bool hasEarlierUnconditionalMatch(GlobalTransition* first, GlobalTransition* second) { - if (first->eventDesc == second->eventDesc) { - if (first->condition.size() == 0) - return true; - } - return false; -} - -std::list<GlobalTransition*> redundantRemove(std::list<GlobalTransition*> list) { -#if 1 - std::list<GlobalTransition*>::iterator outerIter; - std::list<GlobalTransition*>::iterator innerIter; - - outerIter = list.begin(); - while(outerIter != list.end()) { - innerIter = outerIter; - - while(innerIter != list.end()) { - if (innerIter == outerIter) { - innerIter++; - continue; - } - - GlobalTransition* t1 = *outerIter; - GlobalTransition* t2 = *innerIter; - - if (hasUnconditionalSuperset(t1, t2)) { - list.erase(innerIter++); - continue; - } else if (hasUnconditionalSuperset(t2, t1)) { - list.erase(outerIter++); - break; - } - if (hasEarlierUnconditionalMatch(t1, t2)) { - list.erase(innerIter++); - continue; - } - innerIter++; - } - - outerIter++; - } - -#else - - for (std::list<GlobalTransition*>::iterator outerIter = list.begin(); - outerIter != list.end(); - outerIter++) { - for (std::list<GlobalTransition*>::iterator innerIter = outerIter; - innerIter != list.end(); - innerIter++) { - - if (innerIter == outerIter) - continue; - - GlobalTransition* t1 = *outerIter; - GlobalTransition* t2 = *innerIter; - - if (hasUnconditionalSuperset(t1, t2)) { - innerIter = list.erase(innerIter); - continue; - } else if (hasUnconditionalSuperset(t2, t1)) { - outerIter = list.erase(outerIter); - continue; - } - if (hasEarlierUnconditionalMatch(t1, t2)) { - innerIter = list.erase(innerIter); - continue; - } - } - } -#endif - return list; -} - -std::list<GlobalTransition*> redundantMark(std::list<GlobalTransition*> list) { -#if 1 - std::list<GlobalTransition*>::iterator outerIter; - std::list<GlobalTransition*>::iterator innerIter; - - outerIter = list.begin(); - while(outerIter != list.end()) { - innerIter = outerIter; - - while(innerIter != list.end()) { - if (innerIter == outerIter) { - innerIter++; - continue; - } - - GlobalTransition* t1 = *outerIter; - GlobalTransition* t2 = *innerIter; - - if (!t1->isValid || !t2->isValid) { - innerIter++; - continue; - } - - if (hasUnconditionalSuperset(t1, t2)) { - t2->isValid = false; - t2->invalidMsg = "Unconditional superset"; - t2->invalidReason = GlobalTransition::UNCONDITIONAL_SUPERSET; - innerIter++; - continue; - } else if (hasUnconditionalSuperset(t2, t1)) { - t1->isValid = false; - t1->invalidMsg = "Unconditional superset"; - t1->invalidReason = GlobalTransition::UNCONDITIONAL_SUPERSET; - outerIter++; - break; - } - if (hasEarlierUnconditionalMatch(t1, t2)) { - t2->isValid = false; - t2->invalidMsg = "Earlier unconditional match"; - t2->invalidReason = GlobalTransition::UNCONDITIONAL_MATCH; - innerIter++; - continue; - } - innerIter++; - } - - outerIter++; - } - -#else - - for (std::list<GlobalTransition*>::iterator outerIter = list.begin(); - outerIter != list.end(); - outerIter++) { - for (std::list<GlobalTransition*>::iterator innerIter = outerIter; - innerIter != list.end(); - innerIter++) { - - if (innerIter == outerIter) - continue; - - GlobalTransition* t1 = *outerIter; - GlobalTransition* t2 = *innerIter; - - if (!t1->isValid || !t2->isValid) - continue; - - if (hasUnconditionalSuperset(t1, t2)) { - t2->isValid = false; - t2->invalidMsg = "Unconditional superset"; - t2->invalidReason = GlobalTransition::UNCONDITIONAL_SUPERSET; - continue; - } else if (hasUnconditionalSuperset(t2, t1)) { - t1->isValid = false; - t1->invalidMsg = "Unconditional superset"; - t1->invalidReason = GlobalTransition::UNCONDITIONAL_SUPERSET; - continue; - } - if (hasEarlierUnconditionalMatch(t1, t2)) { - t2->isValid = false; - t2->invalidMsg = "Earlier unconditional match"; - t2->invalidReason = GlobalTransition::UNCONDITIONAL_MATCH; - continue; - } - } - } -#endif - return list; -} - - -void TransitionTreeNode::dump(int indent) { - std::string padding; - for (size_t i = 0; i + 1 < indent; i++) { - padding += "| "; - } - if (indent > 0) - padding += "|-"; - - std::string typeString; - switch (type) { - case TYPE_NESTED: - typeString = "NESTED"; - break; - case TYPE_PARALLEL: - typeString = "PARALLEL"; - break; - case TYPE_TRANSITION: - typeString = "TRANSITION"; - break; - case TYPE_UNDEFINED: - typeString = "UNDEFINED"; - break; - break; - default: - break; - } - - - if (transition) { - std::cerr << padding << "t" << ATTR(transition, "index") << " " << typeString << ": "; -// std::cerr << (prevTransition != NULL ? " (" + prevTransition->nodeId + ") <-" : ""); - std::cerr << "[" << nodeId << "]"; -// std::cerr << (nextTransition != NULL ? " -> (" + nextTransition->nodeId + ")" : ""); - std::cerr << std::endl; - } else { - std::cerr << padding << ATTR(state, "id") << " " << typeString << ": " << "[" << nodeId << "]"; -// std::cerr << (firstTransition != NULL ? " -> " + firstTransition->nodeId : ""); - std::cerr << std::endl; - } - - for (std::list<TransitionTreeNode*>::iterator childIter = children.begin(); childIter != children.end(); childIter++) { - (*childIter)->dump(indent + 1); - } -} - -void ChartToFSM::getPotentialTransitionsForConfFromTree(const Arabica::XPath::NodeSet<std::string>& conf, std::map<std::string, GlobalTransition*>& outMap) { - if (_transTree == NULL) { - _transTree = buildTransTree(_scxml, "0"); -// _transTree->dump(); - } - std::string seperator; - - -// std::cerr << "--- "; - - // recursion start - std::set<TransitionTreeNode*> transLeafs; - - for (size_t i = 0; i < conf.size(); i++) { - DUMP_STATS(conf.size(), false); - - Element<std::string> confElem(conf[i]); - assert(_stateToTransTreeNode.find(confElem) != _stateToTransTreeNode.end()); - TransitionTreeNode* node = _stateToTransTreeNode[confElem]; - if (node->firstState == NULL) { // a leaf - ignore intermediates - // ascend to the first parent with transitions but stop at parallel nodes - while(node != NULL && node->firstTransition == NULL) { - if (node->parent && node->parent->type == TransitionTreeNode::TYPE_PARALLEL) - break; - node = node->parent; - } - if (node != NULL) { - transLeafs.insert(node); - } else { - //std::cerr << ATTR(confElem, "id") << " does not cause transitions" << std::endl; - } - } - } - - std::list<std::set<TransitionTreeNode*> > stack; - stack.push_back(transLeafs); // push follow-up configurations onto stack - - while (stack.size() > 0) { - // pop from front of stack - std::set<TransitionTreeNode*> stateList = stack.front(); - stack.pop_front(); - - DUMP_STATS(conf.size(), false); - -#if 0 - seperator = ""; - std::cerr << "Current set: "; - for (std::set<TransitionTreeNode*>::iterator transIter = stateList.begin(); transIter != stateList.end(); transIter++) { - std::cerr << seperator << (*transIter)->nodeId; - seperator = ", "; - } - std::cerr << std::endl; -#endif - - /* - * TransNodes contains a set of lists of transitions. - * In the inner stack we build every possible combination - * of picking at-most one from each list. - */ - - /* create global transitions for every n-tuple in current set of lists */ - std::list<std::pair<std::set<TransitionTreeNode*>, std::set<TransitionTreeNode*> > > innerStack; - innerStack.push_back(std::make_pair(std::set<TransitionTreeNode*>(), stateList)); - - while(innerStack.size() > 0) { - - // picking at-most one from each list - std::set<TransitionTreeNode*> remainingStates = innerStack.front().second; - std::set<TransitionTreeNode*> fixedTransitions = innerStack.front().first; - innerStack.pop_front(); - - if (remainingStates.size() > 0) { - // iterate for each first element fixed - TransitionTreeNode* firstRemainingState = *remainingStates.begin(); - remainingStates.erase(remainingStates.begin()); - - if (firstRemainingState->firstTransition == NULL) { - // no transitions at this state - reenqueue with NULL selection from this - innerStack.push_back(std::make_pair(fixedTransitions, remainingStates)); - continue; - } - - TransitionTreeNode* currTrans = firstRemainingState->firstTransition; - - // choose none from firstList - innerStack.push_back(std::make_pair(fixedTransitions, remainingStates)); - - while(currTrans != NULL) { - std::set<TransitionTreeNode*> fixedAndThis(fixedTransitions); - fixedAndThis.insert(currTrans); - innerStack.push_back(std::make_pair(fixedAndThis, remainingStates)); - currTrans = currTrans->nextTransition; - } - } else { - DUMP_STATS(conf.size(), false); - - if (fixedTransitions.size() > 0) { - - _perfTransTotal++; - _perfTransProcessed++; - - NodeSet<std::string> fixed; - -#if 0 - seperator = ""; - for (std::set<TransitionTreeNode*>::iterator itemIter = fixedTransitions.begin(); itemIter != fixedTransitions.end(); itemIter++) { - TransitionTreeNode* currItem = *itemIter; - std::cerr << seperator << currItem->nodeId; - seperator = ", "; - } - std::cerr << " ## "; -#endif - - seperator = ""; - for (std::set<TransitionTreeNode*>::iterator itemIter = fixedTransitions.begin(); itemIter != fixedTransitions.end(); itemIter++) { - TransitionTreeNode* currItem = *itemIter; - fixed.push_back(currItem->transition); -// std::cerr << seperator << ATTR(currItem->transition, "index"); - seperator = ", "; - } -// std::cerr << std::endl; - - // fixed contains a transiton set! - assert(filterSameState(fixed)); -// assert(filterChildEnabled(fixed)); - assert(filterSameHierarchy(fixed)); - // do not add if they preempt - if (fixed.size() != removeConflictingTransitions(fixed).size()) { -// std::cerr << " - PREEMPTS" << std::endl; - continue; - } - - GlobalTransition* transition = new GlobalTransition(fixed, _dataModel, this); - transition->index = _lastTransIndex++; - -// assert(outMap.find(transition->transitionId) == outMap.end()); - - if (!transition->isValid && !_keepInvalidTransitions) { - delete(transition); -// std::cerr << " - INVALID" << std::endl; - continue; - } - - _perfTransUsed++; - - outMap[transition->transitionId] = transition; -// std::cerr << " - GOOD" << std::endl; - } - } - } - - // create new set of transition lists by moving to parent states - for (std::set<TransitionTreeNode*>::iterator stateIter = stateList.begin(); stateIter != stateList.end(); stateIter++) { - TransitionTreeNode* origState = *stateIter; - TransitionTreeNode* currState = origState; - TransitionTreeNode* parentState = currState->parent; - - /** - * We ascend the current state via its parent and add the parent with transitions. - * However, we break if we reached the top or if we passed a parallel state for - * wich we are not the first child - */ - - while(parentState != NULL) { - if (parentState->type == TransitionTreeNode::TYPE_PARALLEL && parentState->firstState != currState) { - // the first child of the parallel state will continue this transition - we made sure to keep them - break; - } - - if (parentState->firstTransition != NULL) { -// std::cerr << "#### Adding new parent lists for " << origState->nodeId << std::endl; - - std::set<TransitionTreeNode*> newStateList; - newStateList.insert(parentState); - - // add all other states that are not a child of the parent state - for (std::set<TransitionTreeNode*>::iterator newlistIter = stateList.begin(); newlistIter != stateList.end(); newlistIter++) { - TransitionTreeNode* otherState = *newlistIter; - while(otherState != NULL && otherState != parentState) { - otherState = otherState->parent; - } - if (otherState == NULL) - newStateList.insert(*newlistIter); - } - if (newStateList.size() > 0) - stack.push_back(newStateList); - break; - } - - currState = currState->parent; - parentState = currState->parent; - } - } - } -} - -TransitionTreeNode* ChartToFSM::buildTransTree(const Arabica::DOM::Element<std::string>& root, const std::string& nodeId) { - TransitionTreeNode* stateNode = new TransitionTreeNode(); - stateNode->nodeId = nodeId; - stateNode->state = root; - - if (TAGNAME(root) == _nsInfo.xmlNSPrefix + "parallel") { - stateNode->type = TransitionTreeNode::TYPE_PARALLEL; - } else { - stateNode->type = TransitionTreeNode::TYPE_NESTED; - } - - // get all transitions and states from root without recursing - NodeSet<std::string> nested; - nested.push_back(DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "transition", root)); - nested.push_back(DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "state", root)); - nested.push_back(DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "final", root)); - nested.push_back(DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "parallel", root)); - nested.to_document_order(); - - TransitionTreeNode* lastNode = NULL; - - for (size_t i = 0; i < nested.size(); i++) { - Element<std::string> nestedElem(nested[i]); - if (TAGNAME(nestedElem) == _nsInfo.xmlNSPrefix + "transition") { - TransitionTreeNode* transNode = new TransitionTreeNode(); - transNode->transition = nestedElem; - transNode->parent = stateNode; - transNode->nodeId = nodeId + "-" + toStr(i); - transNode->type = TransitionTreeNode::TYPE_TRANSITION; - - if (stateNode->firstTransition == NULL) { - stateNode->firstTransition = transNode; - } - stateNode->children.push_back(transNode); - stateNode->lastTransition = transNode; - - if (lastNode != NULL) { - lastNode->nextTransition = transNode; - transNode->prevTransition = lastNode; - } - lastNode = transNode; - - - } else { - TransitionTreeNode* deeperNode = buildTransTree(nestedElem, nodeId + "-" + toStr(i)); - if (stateNode->firstState == NULL) { - stateNode->firstState = deeperNode; - } - - deeperNode->parent = stateNode; - stateNode->children.push_back(deeperNode); - } - } - - _stateToTransTreeNode[root] = stateNode; - - return stateNode; -} - -void ChartToFSM::getPotentialTransitionsForConfFromPowerSet(const Arabica::XPath::NodeSet<std::string>& conf, std::map<std::string, GlobalTransition*>& outMap) { - // get all transition elements from states in the current configuration - NodeSet<std::string> allTransitions = DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "transition", conf); - - { - std::string seperator = ""; - for (size_t i = 0; i < allTransitions.size(); i++) { - std::cerr << seperator << ATTR_CAST(allTransitions[i], "index"); - seperator=", "; - } - std::cerr << std::endl; - } - -// if (true) { -// outMap = _confToTransitions[""]; -// } - - if (allTransitions.size() == 0) - return; // no transitions - - int nrElements = allTransitions.size(); - int k = 0; - int* stack = (int*)malloc((nrElements + 1) * sizeof(int)); - memset(stack, 0, (nrElements + 1) * sizeof(int)); - - /** - * Powerset is too naive and takes too long! - * We have it up to 500k checks/sec and still 2**30 is - * 1G+ for 30minutes in a single state out of 50k+! - */ - - while(1) { - // create the power set of all potential transitions - this is expensive! - // see: http://www.programminglogic.com/powerset-algorithm-in-c/ - - if (stack[k] < nrElements) { - stack[k+1] = stack[k] + 1; - k++; - } - - else { - stack[k-1]++; - k--; - } - - if (k==0) - break; - - NodeSet<std::string> transitions; -// std::cerr << globalState->stateId << " [" << nrElements << "]: " << std::endl; - for (size_t i = 1; i <= k; i++) { - // std::cerr << stack[i] - 1 << ", "; - transitions.push_back(allTransitions[stack[i] - 1]); - } - // std::cerr << std::endl; - - // transitions.push_back(allTransitions[0]); - // transitions.push_back(allTransitions[4]); - // transitions.push_back(allTransitions[5]); - // transitions.push_back(allTransitions[7]); - - bool dump = false; - - // if (k == 4 && stack[1] == 1 && stack[2] == 5 && stack[3] == 6 && stack[4] == 8) { - // dump = true; - // } - - if (dump) DUMP_TRANSSET("at start"); - - _perfTransTotal++; - _perfTransProcessed++; - - DUMP_STATS(nrElements, false); - - GlobalTransition* transition = NULL; - - // reduce to conflict-free subset - // transitions.to_document_order(); - if (!_keepInvalidTransitions) { - // remove transitions in the same state - if(!filterSameState(transitions)) - continue; - if (dump) DUMP_TRANSSET("after same state filtered"); - - // remove those transitions with a child transition -// if(!filterChildEnabled(transitions)) - if(!filterSameHierarchy(transitions)) - continue; - if (dump) DUMP_TRANSSET("after child enabled filtered"); - - transitions = removeConflictingTransitions(transitions); - if (dump) DUMP_TRANSSET("after conflicting filtered"); - // algorithm can never reduce to empty set - assert(transitions.size() > 0); - - // create a GlobalTransition object from the set - transition = new GlobalTransition(transitions, _dataModel, this); - if (!transition->isValid) { - // this set of transitions can not be enabled together - delete transition; - continue; - } - } else { - transition = new GlobalTransition(transitions, _dataModel, this); - - // remove transitions in the same state - if(!filterSameState(transitions)) { - transition->isValid = false; - transition->invalidReason = GlobalTransition::SAME_SOURCE_STATE; - transition->invalidMsg = "Same source state"; - -// } else if(!filterChildEnabled(transitions)) { - } else if(!filterSameHierarchy(transitions)) { - transition->isValid = false; - transition->invalidReason = GlobalTransition::CHILD_ENABLED; - transition->invalidMsg = "Nested transitions"; - } else { - NodeSet<std::string> nonPreemptingTransitions = removeConflictingTransitions(transitions); - if (nonPreemptingTransitions.size() != transitions.size()) { - transition->isValid = false; - transition->invalidReason = GlobalTransition::PREEMPTING_MEMBERS; - transition->invalidMsg = "Preempting members"; - } - } - - } - - // two combinations might have projected onto the same conflict-free set - if (outMap.find(transition->transitionId) != outMap.end()) { - // std::cerr << "skipping as projected onto existing conflict-free subset" << std::endl; - delete transition; - continue; - } - - transition->index = _lastTransIndex++; - _perfTransUsed++; - - // remember this conflict-free set - // std::cerr << "New conflict-free subset: " << transition->transitionId << ":" << transition->eventDesc << std::endl; - outMap[transition->transitionId] = transition; - } -// _confToTransitions[""] = outMap; - return; -} - -void ChartToFSM::explode() { - - std::list<std::pair<GlobalTransition*, GlobalState*> > statesRemaining; - statesRemaining.push_back(std::make_pair(_currGlobalTransition, new GlobalState(_configuration, _alreadyEntered, _historyValue, _nsInfo.xmlNSPrefix, this))); - - // add all invokers for initial transition - for (unsigned int i = 0; i < _statesToInvoke.size(); i++) { - NodeSet<std::string> invokes = DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "invoke", _statesToInvoke[i]); - for (unsigned int j = 0; j < invokes.size(); j++) { - invoke(Element<std::string>(invokes[j])); - } - } - _statesToInvoke = NodeSet<std::string>(); - - /** - We need this to be a recursion in order not to exhaust the stack - */ - - // append new global states and pop from front - while(statesRemaining.size() > 0) { - _perfStackSize = statesRemaining.size(); - _perfStatesTotal++; - _perfStatesProcessed++; - - DUMP_STATS(0, false); - - GlobalState* globalState = statesRemaining.front().second; - _currGlobalTransition = statesRemaining.front().first; - statesRemaining.pop_front(); - - // used to be conditionalized, we will just assume - assert(_currGlobalTransition); - - if (_globalConf.find(globalState->stateId) != _globalConf.end()) { - if (_currGlobalTransition->isEventless && - !_skipEventChainCalculations && - (_maxEventRaisedChain != UNDECIDABLE || _maxEventSentChain != UNDECIDABLE)) { - // we arrived via a spontaneaous transition, do we need to update? - updateRaisedAndSendChains(_globalConf[globalState->stateId], _currGlobalTransition, std::set<GlobalTransition*>()); - } - delete globalState; - _perfStatesSkippedTotal++; - _perfStatesSkippedProcessed++; - continue; // we have already been here - } - - _configuration = globalState->getActiveStates(); - _alreadyEntered = globalState->getAlreadyEnteredStates(); - _historyValue = globalState->getHistoryStates(); - - // remember as global configuration - _globalConf[globalState->stateId] = globalState; - _globalConf[globalState->stateId]->index = _lastStateIndex++; - - if(_globalConf[globalState->stateId]->isFinal) { - if (_activeConf.find(globalState->activeId) == _activeConf.end()) { - assert(globalState->activeIndex == -1); - globalState->activeIndex = _lastActiveIndex++; - _activeConf[globalState->activeId] = globalState; // remember as active configuration - exitInterpreter(); - } - continue; // done in this branch - } - - if (_activeConf.find(globalState->activeId) != _activeConf.end()) { - // we already know these transition sets, just copy over - std::list<GlobalTransition*>::iterator sortTransIter = _activeConf[globalState->activeId]->sortedOutgoing.begin(); - while(sortTransIter != _activeConf[globalState->activeId]->sortedOutgoing.end()) { - globalState->sortedOutgoing.push_back(GlobalTransition::copyWithoutExecContent(*sortTransIter)); - globalState->sortedOutgoing.back()->index = _lastTransIndex++; - _perfTransUsed++; - sortTransIter++; - } - _perfStatesCachedTotal++; - _perfStatesCachedProcessed++; - - } else { - // we need to calculate the potential optimal transition sets - std::map<std::string, GlobalTransition*> transitionSets; - // std::cerr << globalState->stateId << std::endl; - if (_transitionsFromTree) { - getPotentialTransitionsForConfFromTree(refsToStates(globalState->activeStatesRefs), transitionSets); - } else { - getPotentialTransitionsForConfFromPowerSet(refsToStates(globalState->activeStatesRefs), transitionSets); - } - - // reduce and sort transition sets - for(std::map<std::string, GlobalTransition*>::iterator transSetIter = transitionSets.begin(); - transSetIter != transitionSets.end(); - transSetIter++) { - globalState->sortedOutgoing.push_back(transSetIter->second); - } - - globalState->sortedOutgoing.sort(PtrComp<GlobalTransition>); -// globalState->sortedOutgoing.unique(hasUnconditionalSuperset); -// globalState->sortedOutgoing.unique(hasEarlierUnconditionalMatch); - // unique is not quite like what we need, but it was a start - if (_keepInvalidTransitions) { - globalState->sortedOutgoing = redundantMark(globalState->sortedOutgoing); - } else { -// globalState->sortedOutgoing.unique(hasUnconditionalSuperset); -// globalState->sortedOutgoing.unique(hasEarlierUnconditionalMatch); - globalState->sortedOutgoing = redundantRemove(globalState->sortedOutgoing); - } -// globalState->sortedOutgoing = redundantRemove(globalState->sortedOutgoing); -// globalState->sortedOutgoing = redundantRemove(globalState->sortedOutgoing); -// -// std::cout << globalState->sortedOutgoing.size() << std::endl; - - assert(_activeConf.find(globalState->activeId) == _activeConf.end()); - assert(globalState->activeIndex == -1); - globalState->activeIndex = _lastActiveIndex++; - _activeConf[globalState->activeId] = globalState; - } - - // take every transition set and append resulting new state - for(std::list<GlobalTransition*>::iterator transIter = globalState->sortedOutgoing.begin(); - transIter != globalState->sortedOutgoing.end(); - transIter++) { - - GlobalTransition* incomingTrans = _currGlobalTransition; - GlobalTransition* outgoingTrans = *transIter; - - outgoingTrans->source = globalState->stateId; - - if (_keepInvalidTransitions && !outgoingTrans->isValid) - continue; - - _currGlobalTransition = outgoingTrans; - - microstep(refsToTransitions(outgoingTrans->transitionRefs)); -// assert(isLegalConfiguration(_configuration)); - - _perfMicroStepProcessed++; - _perfMicroStepTotal++; - - // if outgoing transition is spontaneous, add number of events to chain - if (outgoingTrans->isEventless && - !_skipEventChainCalculations && - (_maxEventRaisedChain != UNDECIDABLE || _maxEventSentChain != UNDECIDABLE)) { - outgoingTrans->eventsChainRaised = MIN(incomingTrans->eventsChainRaised + outgoingTrans->eventsRaised, UNDECIDABLE); - outgoingTrans->eventsChainSent = MIN(incomingTrans->eventsChainSent + outgoingTrans->eventsSent, UNDECIDABLE); - - if (outgoingTrans->eventsChainRaised > _maxEventRaisedChain) - _maxEventRaisedChain = outgoingTrans->eventsChainRaised; - if (outgoingTrans->eventsChainSent > _maxEventSentChain) - _maxEventSentChain = outgoingTrans->eventsChainSent; - - } - - statesRemaining.push_back(std::make_pair(outgoingTrans, new GlobalState(_configuration, _alreadyEntered, _historyValue, _nsInfo.xmlNSPrefix, this))); - - // add all invokers - for (unsigned int i = 0; i < _statesToInvoke.size(); i++) { - NodeSet<std::string> invokes = DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "invoke", _statesToInvoke[i]); - for (unsigned int j = 0; j < invokes.size(); j++) { - invoke(Element<std::string>(invokes[j])); - } - } - _statesToInvoke = NodeSet<std::string>(); - - // remember that the last transition lead here - outgoingTrans->destination = statesRemaining.back().second->stateId; - outgoingTrans->activeDestination = statesRemaining.back().second->activeId; - // reset state for next transition set - _configuration = globalState->getActiveStates(); - _alreadyEntered = globalState->getAlreadyEnteredStates(); - _historyValue = globalState->getHistoryStates(); - } - } - -} - -void ChartToFSM::updateRaisedAndSendChains(GlobalState* state, GlobalTransition* source, std::set<GlobalTransition*> visited) { - for (std::list<GlobalTransition*>::iterator transIter = state->sortedOutgoing.begin(); transIter != state->sortedOutgoing.end(); transIter++) { - GlobalTransition* transition = *transIter; - - if (!transition->isEventless) - continue; // we do not care for eventful transitions - - // source leads to spontaneous transition -> update event chains - bool eventChainsNeedUpdated = false; - - if (visited.find(transition) != visited.end()) { - // potential spontaneous transition cycle! - if (transition->eventsChainRaised > 0) - _maxEventRaisedChain = UNDECIDABLE; - if (transition->eventsChainSent > 0) - _maxEventSentChain = UNDECIDABLE; - return; - } - - // UNDECIDABLE means "undecidable / endless" - - // will source increase our event chain? - if (transition->eventsChainRaised != UNDECIDABLE && - transition->eventsChainRaised < source->eventsChainRaised + transition->eventsRaised) { - // taking transition after source causes more events in chain - transition->eventsChainRaised = MIN(source->eventsChainRaised + transition->eventsRaised, UNDECIDABLE); - eventChainsNeedUpdated = true; - } - if (transition->eventsChainSent != UNDECIDABLE && - transition->eventsChainSent < source->eventsChainSent + transition->eventsSent) { - // taking transition after source causes more events in chain - transition->eventsChainSent = MIN(source->eventsChainSent + transition->eventsSent, UNDECIDABLE); - eventChainsNeedUpdated = true; - } - - if (eventChainsNeedUpdated && - transition->destination.length() > 0 && - _globalConf.find(transition->destination) != _globalConf.end()) { - - visited.insert(transition); - // iterate all spontaneous transitions in destination and update event chains - updateRaisedAndSendChains(_globalConf[transition->destination], transition, visited); - } - - if (transition->eventsChainRaised > _maxEventRaisedChain) - _maxEventRaisedChain = transition->eventsChainRaised; - if (transition->eventsChainSent > _maxEventSentChain) - _maxEventSentChain = transition->eventsChainSent; - } -} - -uint32_t ChartToFSM::getMinInternalQueueLength(uint32_t defaultVal) { - if (_maxEventRaisedChain != UNDECIDABLE) - return _maxEventRaisedChain + _doneEventRaiseTolerance; - return defaultVal; -} - -uint32_t ChartToFSM::getMinExternalQueueLength(uint32_t defaultVal) { - if (_maxEventSentChain != UNDECIDABLE) - return _maxEventSentChain; - return defaultVal; -} - -void ChartToFSM::reassembleFromFlat() { - LOG(ERROR) << "Cannot flatten flat SCXML document"; - abort(); -} - -Arabica::XPath::NodeSet<std::string> ChartToFSM::refsToStates(const std::set<int>& stateRefs) { - NodeSet<std::string> states; - for (std::set<int>::const_iterator stateIter = stateRefs.begin(); stateIter != stateRefs.end(); stateIter++) { - states.push_back(indexedStates[*stateIter]); - } - return states; -} - -Arabica::XPath::NodeSet<std::string> ChartToFSM::refsToTransitions(const std::set<int>& transRefs) { - NodeSet<std::string> transitions; - for (std::set<int>::const_iterator transIter = transRefs.begin(); transIter != transRefs.end(); transIter++) { - transitions.push_back(indexedTransitions[*transIter]); - } - return transitions; -} - -void ChartToFSM::beforeMicroStep(Interpreter interpreter) { -} -void ChartToFSM::onStableConfiguration(Interpreter interpreter) { -} -void ChartToFSM::beforeExitingState(Interpreter interpreter, const Arabica::DOM::Element<std::string>& state, bool moreComing) { - GlobalTransition::Action action; - action.exited = state; - _currGlobalTransition->actions.push_back(action); -} -void ChartToFSM::beforeEnteringState(Interpreter interpreter, const Arabica::DOM::Element<std::string>& state, bool moreComing) { - GlobalTransition::Action action; - action.entered = state; - _currGlobalTransition->actions.push_back(action); -} -void ChartToFSM::beforeTakingTransition(Interpreter interpreter, const Arabica::DOM::Element<std::string>& transition, bool moreComing) { -} - -std::ostream& operator<< (std::ostream& os, const GlobalTransition::Action& action) { - if (action.onEntry) - os << "onEntry: " << action.onEntry; - if (action.onExit) - os << "onExit: " << action.onExit; - if (action.transition) - os << "transition: " << action.transition; - if (action.entered) - os << "entered: " << action.entered; - if (action.exited) - os << "exited: " << action.exited; - if (action.invoke) - os << "invoke: " << action.invoke; - if (action.uninvoke) - os << "uninvoke: " << action.uninvoke; - if (action.raiseDone) - os << "raiseDone: " << action.raiseDone; - return os; -} - -GlobalState::GlobalState(const Arabica::XPath::NodeSet<std::string>& activeStates_, - const Arabica::XPath::NodeSet<std::string>& alreadyEnteredStates_, // we need to remember for binding=late - const std::map<std::string, Arabica::XPath::NodeSet<std::string> >& historyStates_, - const std::string& xmlNSPrefix, - ChartToFSM* flattener) { - interpreter = flattener; - activeIndex = -1; - - // take references - for (size_t i = 0; i < activeStates_.size(); i++) { - activeStatesRefs.insert(strTo<int>(ATTR_CAST(activeStates_[i], "index"))); - } - - for (size_t i = 0; i < alreadyEnteredStates_.size(); i++) { - alreadyEnteredStatesRefs.insert(strTo<int>(ATTR_CAST(alreadyEnteredStates_[i], "index"))); - } - - for (std::map<std::string, Arabica::XPath::NodeSet<std::string> >::const_iterator histIter = historyStates_.begin(); histIter != historyStates_.end(); histIter++) { - for (size_t i = 0; i < histIter->second.size(); i++) { - historyStatesRefs[histIter->first].insert(strTo<int>(ATTR_CAST(histIter->second[i], "index"))); - } - } - - isFinal = false; - - // is state this final? - for(int i = 0; i < activeStates_.size(); i++) { - Arabica::DOM::Element<std::string> state = Arabica::DOM::Element<std::string>(activeStates_[i]); - Arabica::DOM::Element<std::string> parentElem = (Arabica::DOM::Element<std::string>)state.getParentNode(); - if(InterpreterImpl::isFinal(state) && iequals(parentElem.getTagName(), xmlNSPrefix + "scxml")) { - isFinal = true; - break; - } - } - - FlatStateIdentifier flatStateId(getActiveStates(), getAlreadyEnteredStates(), getHistoryStates()); - stateId = flatStateId.getStateId(); - activeId = flatStateId.getFlatActive(); -} - -GlobalTransition* GlobalTransition::copyWithoutExecContent(GlobalTransition* other) { - GlobalTransition* newTrans = new GlobalTransition(*other); - newTrans->actions.clear(); - newTrans->historyBase = other; - other->historyTrans.push_back(newTrans); - return newTrans; -} - -GlobalTransition::GlobalTransition(const Arabica::XPath::NodeSet<std::string>& transitionSet, DataModel dataModel, ChartToFSM* flattener) { - interpreter = flattener; - - eventsRaised = 0; - eventsSent = 0; - eventsChainRaised = 0; - eventsChainSent = 0; - historyBase = NULL; - - for (size_t i = 0; i < transitionSet.size(); i++) { - transitionRefs.insert(strTo<int>(ATTR_CAST(transitionSet[i], "index"))); - } - - std::ostringstream setId; // also build id for subset - std::string seperator = ""; - for (std::set<int>::iterator transIter = transitionRefs.begin(); transIter != transitionRefs.end(); transIter++) { - setId << seperator << *transIter; - seperator = "-"; - } - transitionId = setId.str(); - - hasExecutableContent = false; - isValid = true; - isEventless = true; - -#if 0 - std::cerr << "################" << std::endl; - for (size_t i = 0; i < transitions.size(); i++) { - std::cerr << transitions[i] << std::endl; - } - std::cerr << "################" << std::endl; -#endif - - // first establish whether this is a valid set - - /** - * Can these events event occur together? They can't if: - * 1. event / eventless is mixed - * 2. target / targetless is mixed (?) - * 3. there is no common prefix for their event attribute - */ - - bool foundWithEvent = false; - bool foundEventLess = false; - bool foundWithTarget = false; - bool foundTargetLess = false; - - Arabica::DOM::Element<std::string> withEvent; - Arabica::DOM::Element<std::string> noneEvent; - Arabica::DOM::Element<std::string> withTarget; - Arabica::DOM::Element<std::string> noneTarget; - - for (size_t i = 0; i < transitionSet.size(); i++) { - Arabica::DOM::Element<std::string> transElem = Arabica::DOM::Element<std::string>(transitionSet[i]); - if (HAS_ATTR(transElem, "eventexpr")) { - ERROR_EXECUTION_THROW("Cannot flatten document with eventexpr attributes"); - } - if (HAS_ATTR(transElem, "event")) { - foundWithEvent = true; - withEvent = transElem; - if (foundEventLess) - break; - } else { - foundEventLess = true; - noneEvent = transElem; - if (foundWithEvent) - break; - } - if (HAS_ATTR(transElem, "target")) { - foundWithTarget = true; - withTarget = transElem; - if (foundTargetLess) - break; - } else { - foundTargetLess = true; - noneTarget = transElem; - if (foundWithTarget) - break; - } - - } - - // do not mix eventless and event transitions - if (foundEventLess && foundWithEvent) { - if (flattener->_keepInvalidTransitions) { - invalidReason = MIXES_EVENT_SPONTANEOUS; - invalidMsg = "Mixes (non-)spontaneous"; - } - isValid = false; - return; - } - - // 403c vs 229 / 403b - solved via filterChildEnabled - if (foundTargetLess && foundWithTarget) { -// isValid = false; -// return; - } - - isEventless = foundEventLess; - isTargetless = !foundWithTarget; - - // is there a set of event names that would enable this conflict-free transition set? - if (foundWithEvent) { - // get the set of longest event descriptors that will enable this transition set - eventNames = getCommonEvents(transitionSet); - if (eventNames.size() == 0) { -// LOG(INFO) << "No event will activate this conflict-free subset" << std::endl; - if (flattener->_keepInvalidTransitions) { - invalidReason = NO_COMMON_EVENT; - invalidMsg = "No common event"; - } - isValid = false; - return; - } else { - std::string seperator = ""; - for (std::list<std::string>::iterator eventIter = eventNames.begin(); - eventIter != eventNames.end(); - eventIter++) { - eventDesc += seperator + *eventIter; - seperator = " "; - } - } - if (eventDesc.size() == 0) - eventDesc = "*"; - } - - // extract conditions and history targets - std::list<std::string> conditions; - for (size_t i = 0; i < transitionSet.size(); i++) { - Arabica::DOM::Element<std::string> transElem = Arabica::DOM::Element<std::string>(transitionSet[i]); - // gather conditions while we are iterating anyway - if (HAS_ATTR(transElem, "cond")) { - conditions.push_back(boost::trim_copy(ATTR(transElem, "cond"))); - } - - std::list<std::string> targets = tokenize(ATTR(transElem, "target")); - std::list<std::string>::iterator targetIter = targets.begin(); - while(targetIter != targets.end()) { -// std::cout << "// " << *targetIter << std::endl; - if (flattener->_historyTargets.find(*targetIter) != flattener->_historyTargets.end()) { - histTargets.insert(*targetIter); - } - targetIter++; - } -// std::cout << std::endl << std::endl; - } - - seperator = ""; - for (std::vector<Element<std::string> >::iterator transIter = interpreter->indexedTransitions.begin(); transIter != interpreter->indexedTransitions.end(); transIter++) { - const Element<std::string>& refTrans = *transIter; - if (!HAS_ATTR(refTrans, "priority")) - continue; - if (InterpreterImpl::isMember(refTrans, transitionSet)) { - members += seperator + ATTR(refTrans, "priority"); - } else { - members += seperator; - for (size_t i = 0; i < ATTR(refTrans, "priority").size(); i++) { - members += " "; - } - } - seperator = " "; - } - - // if (members == " 4 6 7 ") - // std::cout << "asdfadf"; - - if (conditions.size() > 1) { - condition = dataModel.andExpressions(conditions); - if (condition.size() == 0) { - LOG(ERROR) << "Datamodel does not support to conjungate expressions!" << std::endl; - } - } else if (conditions.size() == 1) { - condition = conditions.front(); - } -} - -Arabica::XPath::NodeSet<std::string> GlobalState::getActiveStates() { - return interpreter->refsToStates(activeStatesRefs); -} - -Arabica::XPath::NodeSet<std::string> GlobalState::getAlreadyEnteredStates() { - return interpreter->refsToStates(alreadyEnteredStatesRefs); -} - -std::map<std::string, Arabica::XPath::NodeSet<std::string> > GlobalState::getHistoryStates() { - std::map<std::string, Arabica::XPath::NodeSet<std::string> > historyValue; - for (std::map<std::string, std::set<int> >::iterator histIter = historyStatesRefs.begin(); histIter != historyStatesRefs.end(); histIter++) { - historyValue[histIter->first] = interpreter->refsToStates(histIter->second); - } - return historyValue; -} - - -Arabica::XPath::NodeSet<std::string> GlobalTransition::getTransitions() const { - return interpreter->refsToTransitions(transitionRefs); -} - -std::list<std::string> GlobalTransition::getCommonEvents(const NodeSet<std::string>& transitions) { - std::list<std::string> prefixes; - std::list<std::string> longestPrefixes; - - for (size_t i = 0; i < transitions.size(); i++) { - // for every transition - std::list<std::string> eventNames = tokenize(ATTR_CAST(transitions[i], "event")); - - for (std::list<std::string>::iterator eventNameIter = eventNames.begin(); - eventNameIter != eventNames.end(); - eventNameIter++) { - // for every event descriptor - std::string eventName = *eventNameIter; - - // remove trailing .* - if (eventName.find("*", eventName.size() - 1) != std::string::npos) - eventName = eventName.substr(0, eventName.size() - 1); - if (eventName.find(".", eventName.size() - 1) != std::string::npos) - eventName = eventName.substr(0, eventName.size() - 1); - - bool isMatching = true; - for (size_t j = 0; j < transitions.size(); j++) { - // check if token would activate all other transitions - if (i == j) - continue; - if (!nameMatch(ATTR_CAST(transitions[j], "event"), eventName)) { - isMatching = false; - break; - } - } - if (isMatching) { - prefixes.push_back(eventName); - } - } - } - - // from the set of event names, remove those that are prefixes - for (std::list<std::string>::iterator outerEventNameIter = prefixes.begin(); - outerEventNameIter != prefixes.end(); - outerEventNameIter++) { - for (std::list<std::string>::iterator innerEventNameIter = prefixes.begin(); - innerEventNameIter != prefixes.end(); - innerEventNameIter++) { - if (!iequals(*outerEventNameIter, *innerEventNameIter) && nameMatch(*outerEventNameIter, *innerEventNameIter)) { - goto IS_PREFIX; - } - } - longestPrefixes.push_back(*outerEventNameIter); -IS_PREFIX: - ; - } - return longestPrefixes; -} - -} |