1 // Copyright (C) 2006-2008 CEA/DEN, EDF R&D
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 #include "ForEachLoop.hxx"
20 #include "TypeCode.hxx"
21 #include "Visitor.hxx"
22 #include "ComposedNode.hxx"
27 #include "YacsTrace.hxx"
29 using namespace YACS::ENGINE;
32 const char FakeNodeForForEachLoop::NAME[]="thisIsAFakeNode";
34 const char SplitterNode::NAME_OF_SEQUENCE_INPUT[]="SmplsCollection";
36 const char ForEachLoop::NAME_OF_SPLITTERNODE[]="splitter";
38 const int ForEachLoop::NOT_RUNNING_BRANCH_ID=-1;
40 InterceptorInputPort::InterceptorInputPort(const std::string& name, Node *node, TypeCode* type):AnyInputPort(name,node,type),
41 DataPort(name,node,type),Port(node),
46 InterceptorInputPort::InterceptorInputPort(const InterceptorInputPort& other, Node *newHelder):AnyInputPort(other,newHelder),DataPort(other,newHelder),
47 Port(other,newHelder),
52 void InterceptorInputPort::getAllRepresentants(std::set<InPort *>& repr) const
54 set<InPort *> ports=_repr->edSetInPort();
55 for(set<InPort *>::iterator iter=ports.begin();iter!=ports.end();iter++)
56 (*iter)->getAllRepresentants(repr);
59 InputPort *InterceptorInputPort::clone(Node *newHelder) const
61 return new InterceptorInputPort(*this,newHelder);
64 void InterceptorInputPort::setRepr(AnySplitOutputPort *repr)
69 bool AnySplitOutputPort::decrRef()
74 void AnySplitOutputPort::incrRef() const
79 AnySplitOutputPort::AnySplitOutputPort(const std::string& name, Node *node, TypeCode *type):OutputPort(name,node,type),
80 DataPort(name,node,type),Port(node),
81 _repr(0),_intercptr(0),_cnt(1)
85 AnySplitOutputPort::AnySplitOutputPort(const AnySplitOutputPort& other, Node *newHelder):OutputPort(other,newHelder),
86 DataPort(other,newHelder),
87 Port(other,newHelder),
88 _repr(0),_intercptr(0),_cnt(1)
92 bool AnySplitOutputPort::addInPort(InPort *inPort) throw(Exception)
94 bool ret=OutputPort::addInPort(inPort);
96 _repr->addInPort(_intercptr);
100 void AnySplitOutputPort::getAllRepresented(std::set<OutPort *>& represented) const
103 OutPort::getAllRepresented(represented);
105 _repr->getAllRepresented(represented);
108 int AnySplitOutputPort::removeInPort(InPort *inPort, bool forward) throw(Exception)
110 bool ret=OutputPort::removeInPort(inPort,forward);
112 if(_setOfInputPort.empty())
113 _repr->removeInPort(_intercptr,forward);
117 void AnySplitOutputPort::addRepr(OutPort *repr, InterceptorInputPort *intercptr)
120 _intercptr=intercptr;
123 OutputPort *AnySplitOutputPort::clone(Node *newHelder) const
125 return new AnySplitOutputPort(*this,newHelder);
128 SeqAnyInputPort::SeqAnyInputPort(const std::string& name, Node *node, TypeCodeSeq* type):AnyInputPort(name,node,type),DataPort(name,node,type),Port(node)
133 SeqAnyInputPort::SeqAnyInputPort(const SeqAnyInputPort& other, Node *newHelder):AnyInputPort(other,newHelder),DataPort(other,newHelder),Port(other,newHelder)
137 InputPort *SeqAnyInputPort::clone(Node *newHelder) const
139 return new SeqAnyInputPort(*this,newHelder);
142 unsigned SeqAnyInputPort::getNumberOfElements() const
144 const SequenceAny * valCsted=(const SequenceAny *) _value;
145 if (valCsted) return valCsted->size();
149 Any *SeqAnyInputPort::getValueAtRank(int i) const
151 const SequenceAny * valCsted=(const SequenceAny *) _value;
152 AnyPtr ret=(*valCsted)[i];
157 std::string SeqAnyInputPort::dump()
159 stringstream xmldump;
160 int nbElem = getNumberOfElements();
161 xmldump << "<value><array><data>" << endl;
162 for (int i = 0; i < nbElem; i++)
164 Any *val = getValueAtRank(i);
165 switch (val->getType()->kind())
168 xmldump << "<value><double>" << val->getDoubleValue() << "</double></value>" << endl;
171 xmldump << "<value><int>" << val->getIntValue() << "</int></value>" << endl;
174 xmldump << "<value><boolean>" << val->getBoolValue() << "</boolean></value>" << endl;
177 xmldump << "<value><string>" << val->getStringValue() << "</string></value>" << endl;
180 xmldump << "<value><objref>" << val->getStringValue() << "</objref></value>" << endl;
183 xmldump << "<value><error> NO_SERIALISATION_AVAILABLE </error></value>" << endl;
187 xmldump << "</data></array></value>" << endl;
188 return xmldump.str();
191 SplitterNode::SplitterNode(const std::string& name, TypeCode *typeOfData,
192 ForEachLoop *father):ElementaryNode(name),
193 _dataPortToDispatch(NAME_OF_SEQUENCE_INPUT,
194 this,(TypeCodeSeq *)TypeCode::sequenceTc("","",typeOfData))
199 SplitterNode::SplitterNode(const SplitterNode& other, ForEachLoop *father):ElementaryNode(other,father),
200 _dataPortToDispatch(other._dataPortToDispatch,this)
204 InputPort *SplitterNode::getInputPort(const std::string& name) const throw(Exception)
206 if(name==NAME_OF_SEQUENCE_INPUT)
207 return (InputPort *)&_dataPortToDispatch;
209 return ElementaryNode::getInputPort(name);
212 Node *SplitterNode::simpleClone(ComposedNode *father, bool editionOnly) const
214 return new SplitterNode(*this,(ForEachLoop *)father);
217 unsigned SplitterNode::getNumberOfElements() const
219 return _dataPortToDispatch.getNumberOfElements();
222 void SplitterNode::execute()
224 //Nothing : should never been called elsewhere big problem...
227 void SplitterNode::init(bool start)
229 ElementaryNode::init(start);
230 _dataPortToDispatch.exInit(start);
233 void SplitterNode::putSplittedValueOnRankTo(int rankInSeq, int branch, bool first)
235 Any *valueToDispatch=_dataPortToDispatch.getValueAtRank(rankInSeq);
236 ForEachLoop *fatherTyped=(ForEachLoop *)_father;
237 fatherTyped->putValueOnBranch(valueToDispatch,branch,first);
238 valueToDispatch->decrRef();
241 FakeNodeForForEachLoop::FakeNodeForForEachLoop(ForEachLoop *loop, bool normalFinish):ElementaryNode(NAME),
243 _normalFinish(normalFinish)
245 _state=YACS::TOACTIVATE;
246 _father=_loop->getFather();
249 FakeNodeForForEachLoop::FakeNodeForForEachLoop(const FakeNodeForForEachLoop& other):ElementaryNode(other),_loop(0),
254 Node *FakeNodeForForEachLoop::simpleClone(ComposedNode *father, bool editionOnly) const
256 return new FakeNodeForForEachLoop(*this);
259 void FakeNodeForForEachLoop::exForwardFailed()
261 _loop->exForwardFailed();
262 FakeNodeForForEachLoop *normallyThis=_loop->_nodeForSpecialCases;
263 _loop->_nodeForSpecialCases=0;
267 void FakeNodeForForEachLoop::exForwardFinished()
269 _loop->exForwardFinished();
270 FakeNodeForForEachLoop *normallyThis=_loop->_nodeForSpecialCases;
271 _loop->_nodeForSpecialCases=0;
275 void FakeNodeForForEachLoop::execute()
278 throw Exception("");//only to trigger ABORT on Executor
280 _loop->pushAllSequenceValues();
283 void FakeNodeForForEachLoop::aborted()
285 _loop->setState(YACS::ERROR);
288 void FakeNodeForForEachLoop::finished()
290 _loop->setState(YACS::DONE);
293 ForEachLoop::ForEachLoop(const std::string& name, TypeCode *typeOfDataSplitted):DynParaLoop(name,typeOfDataSplitted),
294 _splitterNode(NAME_OF_SPLITTERNODE,typeOfDataSplitted,this),
295 _execCurrentId(0),_nodeForSpecialCases(0)
299 ForEachLoop::ForEachLoop(const ForEachLoop& other, ComposedNode *father, bool editionOnly):DynParaLoop(other,father,editionOnly),
300 _splitterNode(other._splitterNode,this),
301 _execCurrentId(0),_nodeForSpecialCases(0)
305 for(vector<AnySplitOutputPort *>::const_iterator iter2=other._outGoingPorts.begin();iter2!=other._outGoingPorts.end();iter2++,i++)
307 AnySplitOutputPort *temp=new AnySplitOutputPort(*(*iter2),this);
308 InterceptorInputPort *interc=new InterceptorInputPort(*other._intecptrsForOutGoingPorts[i],this);
309 temp->addRepr(getOutPort((*iter2)->getName()),interc);
310 interc->setRepr(temp);
311 _outGoingPorts.push_back(temp);
312 _intecptrsForOutGoingPorts.push_back(interc);
316 Node *ForEachLoop::simpleClone(ComposedNode *father, bool editionOnly) const
318 return new ForEachLoop(*this,father,editionOnly);
321 ForEachLoop::~ForEachLoop()
324 for(vector<AnySplitOutputPort *>::iterator iter=_outGoingPorts.begin();iter!=_outGoingPorts.end();iter++)
326 for(vector<InterceptorInputPort *>::iterator iter2=_intecptrsForOutGoingPorts.begin();iter2!=_intecptrsForOutGoingPorts.end();iter2++)
330 void ForEachLoop::init(bool start)
332 DynParaLoop::init(start);
333 _splitterNode.init(start);
338 void ForEachLoop::exUpdateState()
340 if(_state == YACS::DISABLED)
342 if(_inGate.exIsReady())
344 //setState(YACS::TOACTIVATE); // call this method below
345 //internal graph update
347 int nbOfBr=_nbOfBranches.getIntValue();
348 int nbOfElts=_splitterNode.getNumberOfElements();
351 prepareSequenceValues(0);
352 delete _nodeForSpecialCases;
353 _nodeForSpecialCases=new FakeNodeForForEachLoop(this,true);
358 delete _nodeForSpecialCases;
359 _nodeForSpecialCases=new FakeNodeForForEachLoop(this,getAllOutPortsLeavingCurrentScope().empty());
364 _execNodes.resize(nbOfBr);
365 _execIds.resize(nbOfBr);
366 _execOutGoingPorts.resize(nbOfBr);
367 prepareSequenceValues(nbOfElts);
369 _execInitNodes.resize(nbOfBr);
371 //Conversion exceptions can be thrown by createOutputOutOfScopeInterceptors
372 //so catch them to control errors
375 for(i=0;i<nbOfBr;i++)
377 DEBTRACE( "-------------- 1" );
378 _execIds[i]=_execCurrentId;
379 DEBTRACE( "-------------- 2" );
380 _execNodes[i]=_node->clone(this,false);
381 DEBTRACE( "-------------- 3" );
383 _execInitNodes[i]=_initNode->clone(this,false);
384 DEBTRACE( "-------------- 4" );
385 prepareInputsFromOutOfScope(i);
386 DEBTRACE( "-------------- 5" );
387 createOutputOutOfScopeInterceptors(i);
388 DEBTRACE( "-------------- 6" );
389 _splitterNode.putSplittedValueOnRankTo(_execCurrentId++,i,true);
390 DEBTRACE( "-------------- 7" );
393 catch(YACS::Exception& ex)
395 //ForEachLoop must be put in error and the exception rethrown to notify the caller
396 DEBTRACE( "ForEachLoop::exUpdateState: " << ex.what() );
397 setState(YACS::ERROR);
402 setState(YACS::TOACTIVATE); // move the calling of setState method there for adding observers for clone nodes in GUI part
405 for(i=0;i<nbOfBr;i++)
407 _execInitNodes[i]->exUpdateState();
411 _execNodes[i]->exUpdateState();
414 _node->setState(_execNodes[nbOfBr-1]->getState());
415 forwardExecStateToOriginalBody(_execNodes[nbOfBr-1]);
420 void ForEachLoop::getReadyTasks(std::vector<Task *>& tasks)
424 if(_state==YACS::TOACTIVATE || _state==YACS::ACTIVATED)
426 if(_nodeForSpecialCases)
428 _nodeForSpecialCases->getReadyTasks(tasks);
431 for(vector<Node *>::iterator iter=_execNodes.begin();iter!=_execNodes.end();iter++)
432 (*iter)->getReadyTasks(tasks);
433 for(vector<Node *>::iterator iter2=_execInitNodes.begin();iter2!=_execInitNodes.end();iter2++)
434 (*iter2)->getReadyTasks(tasks);
438 int ForEachLoop::getNumberOfInputPorts() const
440 return DynParaLoop::getNumberOfInputPorts()+1;
443 void ForEachLoop::checkNoCyclePassingThrough(Node *node) throw(Exception)
448 void ForEachLoop::selectRunnableTasks(std::vector<Task *>& tasks)
452 std::list<InputPort *> ForEachLoop::getSetOfInputPort() const
454 list<InputPort *> ret=DynParaLoop::getSetOfInputPort();
455 ret.push_back((InputPort *)&_splitterNode._dataPortToDispatch);
459 std::list<InputPort *> ForEachLoop::getLocalInputPorts() const
461 list<InputPort *> ret=DynParaLoop::getLocalInputPorts();
462 ret.push_back((InputPort *)&_splitterNode._dataPortToDispatch);
466 InputPort *ForEachLoop::getInputPort(const std::string& name) const throw(Exception)
468 if(name==SplitterNode::NAME_OF_SEQUENCE_INPUT)
469 return (InputPort *)&_splitterNode._dataPortToDispatch;
471 return DynParaLoop::getInputPort(name);
474 OutputPort *ForEachLoop::getOutputPort(const std::string& name) const throw(Exception)
476 for(vector<AnySplitOutputPort *>::const_iterator iter=_outGoingPorts.begin();iter!=_outGoingPorts.end();iter++)
478 if(name==(*iter)->getName())
479 return (OutputPort *)(*iter);
481 return DynParaLoop::getOutputPort(name);
484 OutPort *ForEachLoop::getOutPort(const std::string& name) const throw(Exception)
486 for(vector<AnySplitOutputPort *>::const_iterator iter=_outGoingPorts.begin();iter!=_outGoingPorts.end();iter++)
488 if(name==(*iter)->getName())
489 return (OutPort *)(*iter);
491 return DynParaLoop::getOutPort(name);
494 Node *ForEachLoop::getChildByShortName(const std::string& name) const throw(Exception)
496 if(name==NAME_OF_SPLITTERNODE)
497 return (Node *)&_splitterNode;
499 return DynParaLoop::getChildByShortName(name);
502 YACS::Event ForEachLoop::updateStateOnFinishedEventFrom(Node *node)
505 switch(getIdentityOfNotifyerNode(node,id))
508 _execNodes[id]->exUpdateState();
512 storeOutValsInSeqForOutOfScopeUse(_execIds[id],id);
513 if(_execCurrentId==_splitterNode.getNumberOfElements())
514 {//No more elements of _dataPortToDispatch to treat
515 _execIds[id]=NOT_RUNNING_BRANCH_ID;
516 //analyzing if some samples are still on treatment on other branches.
517 bool isFinished=true;
518 for(int i=0;i<_execIds.size() and isFinished;i++)
519 isFinished=(_execIds[i]==NOT_RUNNING_BRANCH_ID);
524 pushAllSequenceValues();
525 setState(YACS::DONE);
529 _node->setState(YACS::DONE);
531 ComposedNode* compNode = dynamic_cast<ComposedNode*>(_node);
534 list<Node *> aChldn = compNode->getAllRecursiveConstituents();
535 list<Node *>::iterator iter=aChldn.begin();
536 for(;iter!=aChldn.end();iter++)
537 (*iter)->setState(YACS::DONE);
543 catch(YACS::Exception& ex)
545 DEBTRACE("ForEachLoop::updateStateOnFinishedEventFrom: "<<ex.what());
546 //no way to push results : put following nodes in FAILED state
547 //TODO could be more fine grain : put only concerned nodes in FAILED state
549 setState(YACS::ERROR);
555 {//more elements to do
556 _execIds[id]=_execCurrentId;
558 _splitterNode.putSplittedValueOnRankTo(_execCurrentId++,id,false);
559 node->exUpdateState();
562 _node->setState(node->getState());
563 forwardExecStateToOriginalBody(node);
569 return YACS::NOEVENT;
572 void ForEachLoop::buildDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView)
574 DynParaLoop::buildDelegateOf(port,finalTarget,pointsOfView);
575 string typeOfPortInstance=(port.first)->getNameOfTypeOfCurrentInstance();
576 if(typeOfPortInstance==OutputPort::NAME)
578 vector<AnySplitOutputPort *>::iterator iter=_outGoingPorts.begin();
580 for(;iter!=_outGoingPorts.end();iter++,i++)
581 if((*iter)->getRepr()==port.first)
583 if(iter!=_outGoingPorts.end())
586 (*iter)->addRepr(port.first,_intecptrsForOutGoingPorts[i]);
591 TypeCodeSeq *newTc=(TypeCodeSeq *)TypeCode::sequenceTc("","",port.first->edGetType());
592 AnySplitOutputPort *newPort=new AnySplitOutputPort(getPortName(port.first),this,newTc);
593 InterceptorInputPort *intercptor=new InterceptorInputPort(string("intercptr for ")+getPortName(port.first),this,port.first->edGetType());
594 intercptor->setRepr(newPort);
596 newPort->addRepr(port.first,intercptor);
597 _outGoingPorts.push_back(newPort);
598 _intecptrsForOutGoingPorts.push_back(intercptor);
603 throw Exception("ForEachLoop::buildDelegateOf : not implemented for DS because not specified");
606 void ForEachLoop::getDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView) throw(Exception)
608 string typeOfPortInstance=(port.first)->getNameOfTypeOfCurrentInstance();
609 if(typeOfPortInstance==OutputPort::NAME)
611 vector<AnySplitOutputPort *>::iterator iter=_outGoingPorts.begin();
612 for(;iter!=_outGoingPorts.end();iter++)
613 if((*iter)->getRepr()==port.first)
615 if(iter==_outGoingPorts.end())
617 string what("ForEachLoop::getDelegateOf : Port with name "); what+=port.first->getName(); what+=" not exported by ForEachLoop "; what+=_name;
618 throw Exception(what);
624 throw Exception("ForEachLoop::getDelegateOf : not implemented because not specified");
627 void ForEachLoop::releaseDelegateOf(OutPort *portDwn, OutPort *portUp, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView) throw(Exception)
629 string typeOfPortInstance=portDwn->getNameOfTypeOfCurrentInstance();
630 if(typeOfPortInstance==OutputPort::NAME)
632 vector<AnySplitOutputPort *>::iterator iter=_outGoingPorts.begin();
633 vector<InterceptorInputPort *>::iterator iter2=_intecptrsForOutGoingPorts.begin();
634 for(;iter!=_outGoingPorts.end();iter++,iter2++)
635 if((*iter)->getRepr()==portDwn)
637 //ASSERT(portUp==*iter.second)
638 if((*iter)->decrRef())
640 _outGoingPorts.erase(iter);
642 _intecptrsForOutGoingPorts.erase(iter2);
648 void ForEachLoop::forwardExecStateToOriginalBody(Node *execNode)
650 ComposedNode* compNode = dynamic_cast<ComposedNode*>(_node);
651 ComposedNode* compNodeExe = dynamic_cast<ComposedNode*>(execNode);
652 if (compNode && compNodeExe)
654 list<Node *> aChldn = compNodeExe->getAllRecursiveConstituents();
655 list<Node *>::iterator iter=aChldn.begin();
656 for(;iter!=aChldn.end();iter++)
657 compNode->getChildByName(compNodeExe->getChildName(*iter))->setState((*iter)->getState());
661 OutPort *ForEachLoop::getDynOutPortByAbsName(int branchNb, const std::string& name)
663 string portName, nodeName;
664 splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,false);
665 Node *staticChild = getChildByName(nodeName);
666 return _execNodes[branchNb]->getOutPort(portName);//It's impossible(garanteed by YACS::ENGINE::ForEachLoop::buildDelegateOf)
667 //that a link starting from _initNode goes out of scope of 'this'.
670 void ForEachLoop::cleanDynGraph()
672 DynParaLoop::cleanDynGraph();
673 for(vector< SequenceAny *>::iterator iter3=_execVals.begin();iter3!=_execVals.end();iter3++)
676 for(vector< vector<AnyInputPort *> >::iterator iter4=_execOutGoingPorts.begin();iter4!=_execOutGoingPorts.end();iter4++)
677 for(vector<AnyInputPort *>::iterator iter5=(*iter4).begin();iter5!=(*iter4).end();iter5++)
679 _execOutGoingPorts.clear();
682 void ForEachLoop::storeOutValsInSeqForOutOfScopeUse(int rank, int branchNb)
684 vector<AnyInputPort *>::iterator iter;
686 for(iter=_execOutGoingPorts[branchNb].begin();iter!=_execOutGoingPorts[branchNb].end();iter++,i++)
688 Any *val=(Any *)(*iter)->getValue();
689 _execVals[i]->setEltAtRank(rank,val);
693 void ForEachLoop::prepareSequenceValues(int sizeOfSamples)
695 _execVals.resize(_outGoingPorts.size());
696 vector<AnySplitOutputPort *>::iterator iter=_outGoingPorts.begin();
697 for(int i=0;iter!=_outGoingPorts.end();iter++,i++)
698 _execVals[i]=SequenceAny::New((*iter)->edGetType()->contentType(),sizeOfSamples);
701 void ForEachLoop::pushAllSequenceValues()
703 vector<AnySplitOutputPort *>::iterator iter=_outGoingPorts.begin();
705 for(;iter!=_outGoingPorts.end();iter++,i++)
706 (*iter)->put((const void *)_execVals[i]);
709 void ForEachLoop::createOutputOutOfScopeInterceptors(int branchNb)
711 vector<AnySplitOutputPort *>::iterator iter=_outGoingPorts.begin();
713 for(;iter!=_outGoingPorts.end();iter++,i++)
715 DEBTRACE( (*iter)->getName() << " " << (*iter)->edGetType()->kind() );
716 //AnyInputPort *interceptor=new AnyInputPort((*iter)->getName(),this,(*iter)->edGetType());
717 OutPort *portOut=getDynOutPortByAbsName(branchNb,getOutPortName(((*iter)->getRepr())));
718 DEBTRACE( portOut->getName() );
719 AnyInputPort *interceptor=new AnyInputPort((*iter)->getName(),this,portOut->edGetType());
720 portOut->addInPort(interceptor);
721 _execOutGoingPorts[branchNb].push_back(interceptor);
725 void ForEachLoop::checkLinkPossibility(OutPort *start, const std::list<ComposedNode *>& pointsOfViewStart,
726 InPort *end, const std::list<ComposedNode *>& pointsOfViewEnd) throw(Exception)
728 if(isInMyDescendance(start->getNode())==_node)
729 throw Exception("ForEachLoop::checkLinkPossibility : A link from work node to init node not permitted");
732 std::list<OutputPort *> ForEachLoop::getLocalOutputPorts() const
734 list<OutputPort *> ret;
735 ret.push_back(getOutputPort(NAME_OF_SPLITTED_SEQ_OUT)); // OCC : mkr : add _splittedPort to the list of output ports
736 //ret.push_back(getOutputPort(SplitterNode::NAME_OF_SEQUENCE_INPUT));
740 void ForEachLoop::accept(Visitor *visitor)
742 visitor->visitForEachLoop(this);
745 //! Dump the node state to a stream
747 * \param os : the output stream
749 void ForEachLoop::writeDot(std::ostream &os) const
751 os << " subgraph cluster_" << getId() << " {\n" ;
752 //only one node in a loop
756 os << getId() << " -> " << _node->getId() << ";\n";
759 os << getId() << "[fillcolor=\"" ;
760 YACS::StatesForNode state=getEffectiveState();
761 os << getColorState(state);
762 os << "\" label=\"" << "Loop:" ;
763 os << getName() <<"\"];\n";