+// Copyright (C) 2006-2015 CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library 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. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
#include "Switch.hxx"
#include "Visitor.hxx"
+#include "LinkInfo.hxx"
#include <iostream>
#include <sstream>
#include <cassert>
+//#define _DEVDEBUG_
+#include "YacsTrace.hxx"
+
using namespace YACS::ENGINE;
using namespace std;
const char Switch::DEFAULT_NODE_NAME[]="default";
-const int Switch::ID_FOR_DEFAULT_NODE=-1979020617;
+const int Switch::ID_FOR_DEFAULT_NODE=-1973012217;
const char Switch::SELECTOR_INPUTPORT_NAME[]="select";
int CollectorSwOutPort::edGetNumberOfOutLinks() const
return _className;
}
-void CollectorSwOutPort::edRemoveAllLinksLinkedWithMe() throw(Exception)
+void CollectorSwOutPort::edRemoveAllLinksLinkedWithMe() throw(YACS::Exception)
{
map<int, OutPort *>::iterator pt;
if(_consumer)
((*pt).second)->removeInPort(_consumer,true);
}
-bool CollectorSwOutPort::isDifferentTypeOf(const DataPort *other) const
+TypeOfChannel CollectorSwOutPort::getTypeOfChannel() const
{
- return (*(_potentialProducers.begin())).second->isDifferentTypeOf(other);
+ return (*(_potentialProducers.begin())).second->getTypeOfChannel();
}
void CollectorSwOutPort::getAllRepresented(std::set<OutPort *>& represented) const
((*pt).second)->getAllRepresented(represented);
}
-bool CollectorSwOutPort::addInPort(InPort *inPort) throw(Exception)
+bool CollectorSwOutPort::addInPort(InPort *inPort) throw(YACS::Exception)
{
if(_currentProducer)
{//a specific link is beeing done
(*iter).second->addInPort(inPort);
}
-int CollectorSwOutPort::removeInPort(InPort *inPort, bool forward) throw(Exception)
+int CollectorSwOutPort::removeInPort(InPort *inPort, bool forward) throw(YACS::Exception)
{
if(_currentProducer)
{
return _potentialProducers.empty();
}
-bool CollectorSwOutPort::checkManagementOfPort(OutPort *port) throw(Exception)
+bool CollectorSwOutPort::checkManagementOfPort(OutPort *port) throw(YACS::Exception)
{
for(map<int, OutPort *>::iterator iter=_potentialProducers.begin();iter!=_potentialProducers.end();iter++)
if((*iter).second==port)
throw Exception("CollectorSwOutPort::checkManagementOfPort : unexported port");
}
-void CollectorSwOutPort::checkCompletenessOfCases() const throw(Exception)
+/*!
+ * Called by Switch::checkCFLinks.
+ */
+void CollectorSwOutPort::checkConsistency(LinkInfo& info) const
+{
+ if(((Switch *)_node)->getNbOfCases()!=_potentialProducers.size())
+ info.pushErrSwitch((CollectorSwOutPort *)this);
+ for(map<int, OutPort *>::const_iterator iter=_potentialProducers.begin();iter!=_potentialProducers.end();iter++)
+ (*iter).second->checkConsistency(info);
+}
+
+/*!
+ * Called by LinkInfo::getErrRepr to have a comprehensible message on throw.
+ * When called, typically checkCompletenessOfCases has detected that some potential producers were laking...
+ */
+void CollectorSwOutPort::getHumanReprOfIncompleteCases(std::ostream& stream) const
{
- if(((Switch *)_node)->getNbOfCases()==_potentialProducers.size())
- return ;//Ok all of cases treats _consumer.
set<int> lackingCases;
for(map< int ,Node * >::const_iterator iter=((Switch *)_node)->_mapOfNode.begin();iter!=((Switch *)_node)->_mapOfNode.end();iter++)
{
lackingCases.insert((*iter).first);
}
ostringstream streamForExc;
- streamForExc << "CollectorSwOutPort::checkCompletenessOfCases : For link to " << _consumer->getName() << " of node " << _consumer->getNode()->getName()
- << " the cases of switch node named " << _node->getName()
- << " do not define links for following cases ids :";
+ stream << "For link to " << _consumer->getName() << " of node " << _consumer->getNode()->getName()
+ << " the cases of switch node named " << _node->getName()
+ << " do not define links for following cases ids :";
for(set<int>::iterator iter=lackingCases.begin();iter!=lackingCases.end();iter++)
- streamForExc << Switch::getRepresentationOfCase(*iter) << " ";
- throw Exception(streamForExc.str());
+ stream << Switch::getRepresentationOfCase(*iter) << " ";
+ stream << endl;
}
FakeNodeForSwitch::FakeNodeForSwitch(Switch *sw, bool normalFinish, bool internalError):ElementaryNode("thisIsAFakeNode"),
void FakeNodeForSwitch::exForwardFailed()
{
_sw->exForwardFailed();
- FakeNodeForSwitch *normallyThis=_sw->_undispatchableNotificationNode;
- _sw->_undispatchableNotificationNode=0;
- delete normallyThis;
}
void FakeNodeForSwitch::exForwardFinished()
{
_sw->exForwardFinished();
- FakeNodeForSwitch *normallyThis=_sw->_undispatchableNotificationNode;
- _sw->_undispatchableNotificationNode=0;
- delete normallyThis;
}
void FakeNodeForSwitch::execute()
_sw->setState(YACS::DONE);
}
+/*! \class YACS::ENGINE::Switch
+ * \brief Control node that emulates the C switch
+ *
+ * \ingroup Nodes
+ */
+
Switch::Switch(const Switch& other, ComposedNode *father, bool editionOnly):StaticDefinedComposedNode(other,father),_condition(other._condition,this),
_undispatchableNotificationNode(0)
{
Switch::~Switch()
{
+ if(_undispatchableNotificationNode)delete _undispatchableNotificationNode;
+
for(map< int , Node * >::iterator iter=_mapOfNode.begin();iter!=_mapOfNode.end();iter++)
delete (*iter).second;
for(map<InPort *, CollectorSwOutPort * >::iterator iter2=_outPortsCollector.begin();iter2!=_outPortsCollector.end();iter2++)
void Switch::exUpdateState()
{
+ DEBTRACE("Switch::exUpdateState " << _state);
if(_state == YACS::DISABLED)
return;
if(_inGate.exIsReady())
{
- setState(YACS::TOACTIVATE);
+ setState(YACS::ACTIVATED);
if(_condition.isEmpty())
_undispatchableNotificationNode=new FakeNodeForSwitch(this,false,true);
else
void Switch::init(bool start)
{
+ DEBTRACE("Switch::init " << start);
StaticDefinedComposedNode::init(start);
int i=0;
for(map< int , Node * >::iterator iter=_mapOfNode.begin();iter!=_mapOfNode.end();iter++, i++)
(*iter).second->getReadyTasks(tasks);//Default Node is returned
else
if(_undispatchableNotificationNode)
- _undispatchableNotificationNode->getReadyTasks(tasks);
+ _undispatchableNotificationNode->getReadyTasks(tasks);
else
throw Exception("Switch::getReadyTasks : internal error");
}
}
}
-void Switch::selectRunnableTasks(std::vector<Task *>& tasks)
-{
-}
-
-set<Node *> Switch::edGetDirectDescendants() const
+list<Node *> Switch::edGetDirectDescendants() const
{
- set<Node *> ret;
+ list<Node *> ret;
for(map< int , Node * >::const_iterator iter=_mapOfNode.begin();iter!=_mapOfNode.end();iter++)
if((*iter).second)
- ret.insert((*iter).second);
+ ret.push_back((*iter).second);
return ret;
}
return StaticDefinedComposedNode::getNumberOfInputPorts()+1;
}
-void Switch::edRemoveChild(Node *node) throw(Exception)
+int Switch::getMaxLevelOfParallelism() const
+{
+ int ret(0);
+ for(std::map< int , Node * >::const_iterator it=_mapOfNode.begin();it!=_mapOfNode.end();it++)
+ ret=std::max(ret,((*it).second)->getMaxLevelOfParallelism());
+ return ret;
+}
+
+void Switch::edRemoveChild(Node *node) throw(YACS::Exception)
{
map< int , Node * >::iterator iter=_mapOfNode.begin();
for(;iter!=_mapOfNode.end();iter++)
return ret;
}
-OutPort *Switch::getOutPort(const std::string& name) const throw(Exception)
+
+std::list<InputPort *> Switch::getLocalInputPorts() const
+{
+ list<InputPort *> ret=StaticDefinedComposedNode::getLocalInputPorts();
+ ret.push_back((InputPort *)&_condition);
+ return ret;
+}
+OutPort *Switch::getOutPort(const std::string& name) const throw(YACS::Exception)
{
for(map<InPort *, CollectorSwOutPort * >::const_iterator iter=_outPortsCollector.begin();iter!=_outPortsCollector.end();iter++)
if(name==(*iter).second->getName())
return StaticDefinedComposedNode::getOutPort(name);
}
-InputPort *Switch::getInputPort(const std::string& name) const throw(Exception)
+InputPort *Switch::getInputPort(const std::string& name) const throw(YACS::Exception)
{
if(name==SELECTOR_INPUTPORT_NAME)
return (InputPort *)&_condition;
return StaticDefinedComposedNode::getInputPort(name);
}
-void Switch::checkConsistency(ComposedNode *pointOfView) const throw(Exception)
-{
- for(map<InPort *, CollectorSwOutPort * >::const_iterator iter=_outPortsCollector.begin();iter!=_outPortsCollector.end();iter++)
- (*iter).second->checkCompletenessOfCases();
-}
-
-Node *Switch::getChildByShortName(const std::string& name) const throw(Exception)
+Node *Switch::getChildByShortName(const std::string& name) const throw(YACS::Exception)
{
if(name==DEFAULT_NODE_NAME)
{
return edSetNode(ID_FOR_DEFAULT_NODE,node);
}
-Node *Switch::edReleaseDefaultNode() throw(Exception)
+Node *Switch::edReleaseDefaultNode() throw(YACS::Exception)
{
return edReleaseCase(ID_FOR_DEFAULT_NODE);
}
-Node *Switch::edReleaseCase(int caseId) throw(Exception)
+Node *Switch::edReleaseCase(int caseId) throw(YACS::Exception)
{
map< int , Node * >::iterator iter=_mapOfNode.find(caseId);
if(iter==_mapOfNode.end())
Node *ret=(*iter).second;
StaticDefinedComposedNode::edRemoveChild(ret);
_mapOfNode.erase(iter);
+ modified();
return ret;
}
}
+Node *Switch::edGetNode(int caseId)
+{
+ if (!_mapOfNode.count(caseId)) return 0;
+ return _mapOfNode[caseId];
+}
+
+
/*!
* \param caseId : the case ID chosen to place 'node'
* \param node : the node for the specified 'caseId'
* 0 is returned if caseId is a new ID.
* \b WARNING : 'node' is held by 'this' after call, whereas returned node is no more held.
*/
-Node *Switch::edSetNode(int caseId, Node *node) throw(Exception)
+Node *Switch::edSetNode(int caseId, Node *node) throw(YACS::Exception)
{
if(!node)
throw Exception("Switch::edSetNode : null node cannot be set as a case in switch node");
if(node->_father!=0)
throw Exception("Switch::edSetNode : node already held by another father");
+ checkNoCrossHierachyWith(node);
node->_father=this;
map< int , Node * >::iterator iter=_mapOfNode.find(caseId);
if(iter==_mapOfNode.end())
{
_mapOfNode[caseId]=node;
+ modified();
return 0;
}
else
{
Node *ret=(*iter).second;
(*iter).second=node;
+ modified();
return ret;
}
}
}
+//! Change the case of a node
+/*!
+ * \param oldCase : the case value to change
+ * \param newCase : the new value to set
+ * raise an exception if the old case does not exist or if the new case already exists
+ */
+void Switch::edChangeCase(int oldCase, int newCase)
+{
+ std::map< int , Node * >::iterator iter=_mapOfNode.find(oldCase);
+ if(iter==_mapOfNode.end())
+ {
+ //the case does not exists
+ throw Exception("Switch::edChangeCase : case does not exist");
+ }
+ iter=_mapOfNode.find(newCase);
+ if(iter != _mapOfNode.end())
+ {
+ //the new case exists
+ throw Exception("Switch::edChangeCase : new case exists");
+ }
+ Node* node=_mapOfNode[oldCase];
+ _mapOfNode.erase(oldCase);
+ _mapOfNode[newCase]=node;
+ modified();
+}
+
+int Switch::getMaxCase()
+{
+ int aCase = 0;
+ map<int, Node*>::const_iterator it = _mapOfNode.begin();
+ for(; it != _mapOfNode.end(); ++it)
+ if ((*it).first > aCase)
+ aCase = (*it).first;
+ return aCase;
+}
+
+//! Get the progress weight of the graph
+/*!
+ * Only elementary nodes have weight. If the switch node is not done, we add the weight of all his descendants,
+ * otherwise only the weight of the used case count.
+ */
+list<ProgressWeight> Switch::getProgressWeight() const
+{
+ list<ProgressWeight> ret;
+ list<Node *> setOfNode=edGetDirectDescendants();
+ if (getState() == YACS::DONE)
+ {
+ for(list<Node *>::const_iterator iter=setOfNode.begin();iter!=setOfNode.end();iter++)
+ {
+ if (getEffectiveState(*iter) == YACS::DONE)
+ ret=(*iter)->getProgressWeight();
+ }
+ }
+ else
+ {
+ for(list<Node *>::const_iterator iter=setOfNode.begin();iter!=setOfNode.end();iter++)
+ {
+ list<ProgressWeight> myCurrentSet=(*iter)->getProgressWeight();
+ ret.insert(ret.end(),myCurrentSet.begin(),myCurrentSet.end());
+ }
+ }
+ return ret;
+}
+
+bool Switch::edAddChild(Node *node) throw(YACS::Exception)
+{
+ int aCase = getMaxCase() + 1;
+ DEBTRACE(aCase);
+ bool ret = edSetNode(aCase, node);
+ DEBTRACE(ret);
+ return ret;
+}
+
YACS::Event Switch::updateStateOnFinishedEventFrom(Node *node)
{
setState(YACS::DONE);
return ret;
}
-std::vector< std::pair<InPort *, OutPort *> > Switch::getSetOfLinksComingInCurrentScope() const
+void Switch::checkCFLinks(const std::list<OutPort *>& starts, InputPort *end, unsigned char& alreadyFed, bool direction, LinkInfo& info) const
{
- vector< std::pair<InPort *, OutPort *> > ret=StaticDefinedComposedNode::getSetOfLinksComingInCurrentScope();
- set<OutPort *> temp2=_condition.edSetOutPort();
- for(set<OutPort *>::iterator iter3=temp2.begin();iter3!=temp2.end();iter3++)
- if(!isInMyDescendance((*iter3)->getNode()))
- ret.push_back(pair<InPort *, OutPort *>((InPort *)&_condition,*iter3));
- return ret;
+ map<InPort *, CollectorSwOutPort * >::const_iterator iter=_outPortsCollector.find(end);
+ if(iter!=_outPortsCollector.end())
+ {
+ set<OutPort *> represented;
+ (*iter).second->getAllRepresented(represented);
+ list<OutPort *> others;
+ for(list<OutPort *>::const_iterator iter2=starts.begin();iter2!=starts.end();iter2++)
+ if(represented.find(*iter2)==represented.end())
+ others.push_back(*iter2);
+ if(others.empty())
+ alreadyFed=FED_ST;
+ else
+ StaticDefinedComposedNode::checkCFLinks(others,end,alreadyFed,direction,info);//should never happend;
+ }
+ else
+ StaticDefinedComposedNode::checkCFLinks(starts,end,alreadyFed,direction,info);
+}
+
+void Switch::checkControlDependancy(OutPort *start, InPort *end, bool cross,
+ std::map < ComposedNode *, std::list < OutPort * > >& fw,
+ std::vector<OutPort *>& fwCross,
+ std::map< ComposedNode *, std::list < OutPort *> >& bw,
+ LinkInfo& info) const
+{
+ throw Exception("Switch::checkControlDependancy : a link was dectected between 2 cases of a switch. Impossible !");
}
-void Switch::checkNoCyclePassingThrough(Node *node) throw(Exception)
+void Switch::checkNoCyclePassingThrough(Node *node) throw(YACS::Exception)
{
throw Exception("Switch::checkNoCyclePassingThrough : uncorrect control flow link relative to switch");
}
-void Switch::checkLinkPossibility(OutPort *start, const std::set<ComposedNode *>& pointsOfViewStart,
- InPort *end, const std::set<ComposedNode *>& pointsOfViewEnd) throw(Exception)
+void Switch::checkLinkPossibility(OutPort *start, const std::list<ComposedNode *>& pointsOfViewStart,
+ InPort *end, const std::list<ComposedNode *>& pointsOfViewEnd) throw(YACS::Exception)
{
throw Exception("Switch::checkLinkPossibility : A link between 2 different cases of a same Switch requested -> Impossible");
}
-void Switch::buildDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, const std::set<ComposedNode *>& pointsOfView)
+void Switch::buildDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView)
{
map<InPort *, CollectorSwOutPort * >::iterator result=_outPortsCollector.find(finalTarget);
CollectorSwOutPort *newCollector;
port.first=newCollector;
}
-void Switch::getDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, const std::set<ComposedNode *>& pointsOfView) throw(Exception)
+void Switch::getDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView) throw(YACS::Exception)
{
map<InPort *, CollectorSwOutPort * >::iterator iter=_outPortsCollector.find(finalTarget);
if(iter==_outPortsCollector.end())
port.first=(*iter).second;
}
-void Switch::releaseDelegateOf(OutPort *portDwn, OutPort *portUp, InPort *finalTarget, const std::set<ComposedNode *>& pointsOfView) throw(Exception)
+void Switch::releaseDelegateOf(OutPort *portDwn, OutPort *portUp, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView) throw(YACS::Exception)
{
set<OutPort *> repr;
portDwn->getAllRepresented(repr);
* \param node: the node which effective state is queried
* \return the effective node state
*/
-YACS::StatesForNode Switch::getEffectiveState(Node* node)
+YACS::StatesForNode Switch::getEffectiveState(const Node* node) const
{
YACS::StatesForNode effectiveState=Node::getEffectiveState();
- if(effectiveState==YACS::INITED)
- return YACS::INITED;
+ if(effectiveState==YACS::READY)
+ return YACS::READY;
if(effectiveState==YACS::TOACTIVATE)
- return YACS::INITED;
+ return YACS::READY;
if(effectiveState==YACS::DISABLED)
return YACS::DISABLED;
- map< int , Node * >::iterator iter=_mapOfNode.find(_condition.getIntValue());
- if(iter!=_mapOfNode.end() && (*iter).second==node)
- return node->getState();
- else
- return YACS::INITED;
+
+ return node->getState();
+}
+YACS::StatesForNode Switch::getEffectiveState() const
+{
+ return Node::getEffectiveState();
}
-void Switch::writeDot(std::ostream &os)
+void Switch::writeDot(std::ostream &os) const
{
os << " subgraph cluster_" << getId() << " {\n" ;
for(map<int,Node*>::const_iterator iter=_mapOfNode.begin();iter!=_mapOfNode.end();iter++)
return id;
}
-std::string Switch::getCaseId(const Node *node) const throw(Exception)
+std::string Switch::getCaseId(const Node *node) const throw(YACS::Exception)
{
const char sep='_';
map<int, Node*>::const_iterator iter;