Salome HOME
updated copyright message
[modules/yacs.git] / src / engine / Loop.cxx
1 // Copyright (C) 2006-2023  CEA, EDF
2 //
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, or (at your option) any later version.
7 //
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.
12 //
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
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "Loop.hxx"
21 #include "InputPort.hxx"
22 #include "OutputPort.hxx"
23 #include "InputDataStreamPort.hxx"
24 #include "OutputDataStreamPort.hxx"
25 #include "LinkInfo.hxx"
26 #include "Runtime.hxx"
27 #include "Visitor.hxx"
28 #include <cassert>
29 #include <iostream>
30
31 //#define _DEVDEBUG_
32 #include "YacsTrace.hxx"
33
34 using namespace YACS::ENGINE;
35 using namespace std;
36
37 InputPort4DF2DS::InputPort4DF2DS(DFToDSForLoop *node, TypeCode* type):
38   InputPort("", node, type),
39   DataPort("", node, type),
40   Port(node),_data(0)
41 {
42 }
43
44 void InputPort4DF2DS::getAllRepresentants(std::set<InPort *>& repr) const
45 {
46   set<InPort *> s=_node->getOutputDataStreamPort("")->edSetInPort();
47   repr.insert(s.begin(),s.end());
48 }
49
50 void *InputPort4DF2DS::get() const
51 {
52   if(!_data)
53     {
54       std::string what="InputPort4DF2DS::get : no value currently in input whith name \""; what+=_name; what+="\"";
55       throw Exception(what);
56     }
57   return (void *)_data;
58 }
59
60 void InputPort4DF2DS::exRestoreInit()
61 {
62   if(!_initValue)
63     return;
64   if(_data)
65     _data->decrRef();
66   _data=_initValue;
67   _data->incrRef();
68 }
69
70 void InputPort4DF2DS::exSaveInit()
71 {
72   if(_initValue)
73     _initValue->decrRef();
74   _initValue=_data;
75   _initValue->incrRef();
76 }
77
78 void InputPort4DF2DS::put(const void *data)
79 {
80   put((Any *)data);
81 }
82
83 InputPort *InputPort4DF2DS::clone(Node *newHelder) const
84 {
85   throw Exception("InputPort4DF2DS::clone : internal error");
86 }
87
88 void InputPort4DF2DS::releaseData()
89 {
90   if(_data)
91     _data->decrRef();
92   _data = nullptr;
93 }
94
95 void InputPort4DF2DS::put(Any *data)
96 {
97   InputPort4DF2DS::releaseData();
98   _data=data;
99   _data->incrRef();
100 }
101
102 InputPort4DF2DS::~InputPort4DF2DS()
103 {
104   if(_data)
105     _data->decrRef();
106 }
107
108 DFToDSForLoop::DFToDSForLoop(Loop *loop, const std::string& name, TypeCode* type):ElementaryNode(""),_nbOfTimeUsed(1)
109 {
110   _name="DF2DS For "; _name+=loop->getName(); _name+=" representing port "; _name+=name;
111   _father=loop;
112   _setOfInputPort.push_back(new InputPort4DF2DS(this,type));
113   _setOfOutputDataStreamPort.push_back(new OutputDataStreamPort("",this,Loop::MappingDF2DS(type)));
114 }
115
116 DFToDSForLoop::~DFToDSForLoop()
117 {
118   edDisconnectAllLinksWithMe();
119 }
120
121 void DFToDSForLoop::getReadyTasks(std::vector<Task *>& tasks)
122 {
123 }
124
125 InputPort *DFToDSForLoop::getInputPort(const std::string& name) const
126 {
127   try {
128     return Node::getInputPort(name);
129   }
130   catch(Exception& e) {}
131
132   list<InputPort *>::const_iterator it =_setOfInputPort.begin();
133   return (*it);
134 }
135
136 OutputDataStreamPort *DFToDSForLoop::getOutputDataStreamPort(const std::string& name) const
137 {
138   list<OutputDataStreamPort *>::const_iterator it =_setOfOutputDataStreamPort.begin();
139   return (*it);
140 }
141
142 void DFToDSForLoop::load()
143 {
144 }
145
146 void DFToDSForLoop::execute()
147 {
148   //TO IMPLEMENT
149 }
150
151 Node *DFToDSForLoop::simpleClone(ComposedNode *father, bool editionOnly) const
152 {
153   throw Exception("DFToDSForLoop::simpleClone : Internal error");
154 }
155
156 OutputPort4DS2DF::OutputPort4DS2DF(DSToDFForLoop *node, TypeCode *type):
157   OutputPort("", node, type),
158   DataPort("", node, type),
159   Port(node),_data(0)
160 {
161 }
162
163 void OutputPort4DS2DF::getAllRepresented(std::set<OutPort *>& represented) const
164 {
165   set<OutPort *> setO=_node->getInputDataStreamPort("")->edSetOutPort();
166   for(set<OutPort *>::iterator iter=setO.begin();iter!=setO.end();iter++)
167     (*iter)->getAllRepresented(represented);
168 }
169
170 void OutputPort4DS2DF::put(const void *data)
171 {
172   put((Any *)data);
173   OutputPort::put(data);
174 }
175
176 OutputPort *OutputPort4DS2DF::clone(Node *newHelder) const
177 {
178   throw Exception("OutputPort4DS2DF::clone : Internal error");
179 }
180
181 void OutputPort4DS2DF::put(Any *data)
182 {
183   if(_data)
184     _data->decrRef();
185   _data=data;
186   _data->incrRef();
187 }
188
189 OutputPort4DS2DF::~OutputPort4DS2DF()
190 {
191   if(_data)
192     _data->decrRef();
193 }
194
195 InputDataStreamPort4DS2DF::InputDataStreamPort4DS2DF(DSToDFForLoop *node, TypeCode* type):
196   InputDataStreamPort("", node, type),
197   DataPort("", node, type),
198   Port(node)
199 {
200 }
201
202 void InputDataStreamPort4DS2DF::getAllRepresentants(std::set<InPort *>& repr) const
203 {
204   set<InPort *> s=_node->getOutputPort("")->edSetInPort();
205   repr.insert(s.begin(),s.end());
206 }
207
208 DSToDFForLoop::DSToDFForLoop(Loop *loop, const std::string& name, TypeCode* type):ElementaryNode(""),_nbOfTimeUsed(1)
209 {
210   _name="DS2DF For "; _name+=loop->getName(); _name+=" representing port "; _name+=name;
211   _father=loop;
212   _setOfOutputPort.push_back(new OutputPort4DS2DF(this,type));
213   _setOfInputDataStreamPort.push_back(new InputDataStreamPort4DS2DF(this,type));
214 }
215
216 Node *DSToDFForLoop::simpleClone(ComposedNode *father, bool editionOnly) const
217 {
218   throw Exception("DSToDFForLoop::simpleClone : Internal error");
219 }
220
221 DSToDFForLoop::~DSToDFForLoop()
222 {
223   edDisconnectAllLinksWithMe();
224 }
225
226 void DSToDFForLoop::getReadyTasks(std::vector<Task *>& tasks)
227 {
228 }
229
230 OutputPort *DSToDFForLoop::getOutputPort(const std::string& name) const
231 {
232   list<OutputPort *>::const_iterator it = _setOfOutputPort.begin();
233   return (*it);
234 }
235
236 InputDataStreamPort *DSToDFForLoop::getInputDataStreamPort(const std::string& name) const
237 {
238   list<InputDataStreamPort *>::const_iterator it = _setOfInputDataStreamPort.begin();
239   return (*it);
240 }
241
242 void DSToDFForLoop::load()
243 {
244 }
245
246 void DSToDFForLoop::execute()
247 {
248   //TO IMPLEMENT
249 }
250
251 FakeNodeForLoop::FakeNodeForLoop(Loop *loop, bool normalFinish, bool internalError):ElementaryNode("thisIsAFakeNode"),
252                                                                                     _loop(loop),
253                                                                                     _normalFinish(normalFinish),
254                                                                                     _internalError(internalError)
255 {
256   setState(YACS::TOACTIVATE);
257   _father=_loop->getFather();
258 }
259
260 FakeNodeForLoop::FakeNodeForLoop(const FakeNodeForLoop& other):ElementaryNode(other),_loop(0),
261                                                                _normalFinish(false),_internalError(true)
262 {
263 }
264
265 Node *FakeNodeForLoop::simpleClone(ComposedNode *father, bool editionOnly) const
266 {
267   return new FakeNodeForLoop(*this);
268 }
269
270 void FakeNodeForLoop::exForwardFailed()
271 {
272   _loop->exForwardFailed();
273 }
274
275 void FakeNodeForLoop::exForwardFinished()
276
277   _loop->exForwardFinished();
278 }
279
280 void FakeNodeForLoop::execute()
281 {
282   if(!_normalFinish)
283     throw Exception("");//only to trigger ABORT on Executor
284 }
285
286 void FakeNodeForLoop::aborted()
287 {
288   if(_internalError)
289     _loop->setState(YACS::INTERNALERR);
290   else
291     _loop->setState(YACS::ERROR);
292 }
293
294 void FakeNodeForLoop::finished()
295 {
296   _loop->setState(YACS::DONE);
297 }
298
299 Loop::Loop(const Loop& other, ComposedNode *father, bool editionOnly):StaticDefinedComposedNode(other,father),_nbOfTurns(0),_nodeForNullTurnOfLoops(0),_node(0)
300 {
301   if(other._node)
302     _node=other._node->simpleClone(this,editionOnly);
303 }
304
305 Loop::Loop(const std::string& name):StaticDefinedComposedNode(name),_node(0),_nbOfTurns(0),_nodeForNullTurnOfLoops(0)
306 {
307 }
308
309 Loop::~Loop()
310 {
311   delete _node;
312   if(_nodeForNullTurnOfLoops)delete _nodeForNullTurnOfLoops;
313   for(set<DSToDFForLoop *>::iterator iter1=_inputsTraducer.begin();iter1!=_inputsTraducer.end();iter1++)
314     delete (*iter1);
315   for(set<DFToDSForLoop *>::iterator iter2=_outputsTraducer.begin();iter2!=_outputsTraducer.end();iter2++)
316     delete (*iter2);
317 }
318
319 void Loop::init(bool start)
320 {
321   StaticDefinedComposedNode::init(start);
322   _nbOfTurns=0;
323   if(_node)
324     _node->init(start); // if start is true, refresh the internal node
325   else
326     throw Exception("Loop::initLoop : no nodes specifies to be repeated ");
327   delete _nodeForNullTurnOfLoops;
328   _nodeForNullTurnOfLoops=0;
329 }
330
331 Node *Loop::edSetNode(Node *node)
332 {
333   if(_node==node)
334     return 0;
335   if(node)
336     {
337       if(node->_father)
338         {
339           string what = "Loop::edSetNode: node "; what += node->getName(); what += " is not orphan ! "; 
340           throw Exception(what);
341         }
342     }
343   checkNoCrossHierachyWith(node);
344   StaticDefinedComposedNode::edRemoveChild(_node);
345   Node *ret=_node;
346   _node=node;
347   _node->_father=this;
348   //set _modified flag so that edUpdateState() can refresh state
349   modified();
350   return ret;
351 }
352
353 bool Loop::edAddChild(Node *node) 
354 {
355   return edSetNode(node);
356 }
357
358 Node *Loop::edRemoveNode()
359 {
360   StaticDefinedComposedNode::edRemoveChild(_node);
361   Node *ret=_node;
362   _node=0;
363   modified();
364   return ret;
365 }
366
367 //! Collect all the child nodes that are ready
368 /*!
369  * \param tasks : vector of tasks to collect ready nodes
370  */
371 void Loop::getReadyTasks(std::vector<Task *>& tasks)
372 {
373   if(!_node)
374     return;
375   /*
376    * To change the way ComposedNode state is handled, uncomment the following line
377    * see Bloc::getReadyTasks
378    */
379   if(_state==YACS::TOACTIVATE) setState(YACS::ACTIVATED);
380   if(_state==YACS::TOACTIVATE || _state==YACS::ACTIVATED)
381     if(_nodeForNullTurnOfLoops)
382       _nodeForNullTurnOfLoops->getReadyTasks(tasks);
383     else
384       {
385         _node->getReadyTasks(tasks);
386         for(set<DSToDFForLoop *>::iterator iter1=_inputsTraducer.begin();iter1!=_inputsTraducer.end();iter1++)
387           (*iter1)->getReadyTasks(tasks);
388         for(set<DFToDSForLoop *>::iterator iter2=_outputsTraducer.begin();iter2!=_outputsTraducer.end();iter2++)
389           (*iter2)->getReadyTasks(tasks);
390       }
391 }
392
393 void Loop::edRemoveChild(Node *node)
394 {
395   StaticDefinedComposedNode::edRemoveChild(node);
396   if(_node==node)
397     _node=0;
398   modified();
399 }
400
401 std::list<Node *> Loop::edGetDirectDescendants() const
402 {
403   list<Node *> ret;
404   if(_node)
405     ret.push_back(_node);
406   return ret;
407 }
408
409 std::list<InputPort *> Loop::getSetOfInputPort() const
410 {
411   list<InputPort *> ret=StaticDefinedComposedNode::getSetOfInputPort();
412   ret.push_back(getDecisionPort());
413   return ret;
414 }
415
416 int Loop::getNumberOfInputPorts() const
417 {
418   return StaticDefinedComposedNode::getNumberOfInputPorts()+1;
419 }
420
421 int Loop::getMaxLevelOfParallelism() const
422 {
423   if(!_node)
424     return 0;
425   return _node->getMaxLevelOfParallelism();
426 }
427
428 void Loop::getWeightRegardingDPL(ComplexWeight *weight)
429 {
430   if(_node)
431     _node->getWeightRegardingDPL(weight);
432 }
433
434 void Loop::partitionRegardingDPL(const PartDefinition *pd, std::map<ComposedNode *, YACS::BASES::AutoRefCnt<PartDefinition> >& zeMap)
435 {
436   if(_node)
437     _node->partitionRegardingDPL(pd,zeMap);
438 }
439
440 Node *Loop::getChildByShortName(const std::string& name) const
441 {
442   if (_node)
443     if(name==_node->getName())
444       return _node;
445   string what("node "); what+= name ; what+=" is not a child of loop node "; what += getName();
446   throw Exception(what);
447 }
448
449 TypeCode* Loop::MappingDF2DS(TypeCode* type)
450 {
451   return type;
452 }
453
454 TypeCode* Loop::MappingDS2DF(TypeCode* type)
455 {
456   return type;
457 }
458
459 void Loop::buildDelegateOf(InPort * & port, OutPort *initialStart, const std::list<ComposedNode *>& pointsOfView)
460 {
461   string typeOfPortInstance=port->getNameOfTypeOfCurrentInstance();
462   if(typeOfPortInstance!=InputPort::NAME ||
463      (typeOfPortInstance == InputPort::NAME && 
464       initialStart->getNameOfTypeOfCurrentInstance()== OutputPort::NAME && 
465       !isNecessaryToBuildSpecificDelegateDF2DS(pointsOfView)) )
466     return ;
467   InputPort *portCasted=(InputPort *)port;
468   set<DSToDFForLoop*>::iterator iter;
469   //Determinig if a DSToDFForLoop node has already been created for delegation of 'port'
470   for(iter=_inputsTraducer.begin();iter!=_inputsTraducer.end();iter++)
471     if((*iter)->getOutputPort("")->isAlreadyInSet(portCasted))
472       break;
473   if(iter==_inputsTraducer.end())
474     {//first time that 'port' is delegated on higher level
475       pair<set<DSToDFForLoop*>::iterator, bool> iter2=_inputsTraducer.insert(new DSToDFForLoop(this,portCasted->getName(),Loop::MappingDF2DS(portCasted->edGetType())));
476       iter=iter2.first;
477       (*iter)->getOutputPort("")->addInPort(portCasted);
478     }
479   else
480     (*iter)->loopHasOneMoreRef();
481   port=(*iter)->getInputDataStreamPort("");
482 }
483
484 void Loop::buildDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView)
485 {
486   string typeOfPortInstance=(port.first)->getNameOfTypeOfCurrentInstance();
487   if(typeOfPortInstance!=OutputPort::NAME ||
488     ( typeOfPortInstance == OutputPort::NAME && 
489       finalTarget->getNameOfTypeOfCurrentInstance()== InputPort::NAME && 
490       !isNecessaryToBuildSpecificDelegateDF2DS(pointsOfView)) )
491     return ;
492   OutPort *portCasted=port.first;
493   set<DFToDSForLoop*>::iterator iter;
494   //Determinig if a DFToDSForLoop node has already been created for delegation of 'port'
495   for(iter=_outputsTraducer.begin();iter!=_outputsTraducer.end();iter++)
496     if(portCasted->isAlreadyLinkedWith((*iter)->getInputPort("")))
497       break;
498   DFToDSForLoop *kl;
499   if(iter==_outputsTraducer.end())
500     {//first time that 'port' is delegated on higher level
501       //_outputsTraducer.insert(new DFToDSForLoop(this,portCasted->getName(),portCasted->edGetType()));
502       kl=new DFToDSForLoop(this,portCasted->getName(),portCasted->edGetType());
503       pair<set<DFToDSForLoop*>::iterator, bool> iter2=_outputsTraducer.insert(kl);
504       iter=iter2.first;
505       portCasted->addInPort((*iter)->getInputPort(""));
506     }
507   else
508     {
509       kl=*iter;
510       kl->loopHasOneMoreRef();
511     }
512   edAddLink(isInMyDescendance((port.first)->getNode())->getOutGate(),kl->getInGate());
513   port.first=(*iter)->getOutputDataStreamPort("");
514 }
515
516 void Loop::getDelegateOf(InPort * & port, OutPort *initialStart, const std::list<ComposedNode *>& pointsOfView)
517 {
518   string typeOfPortInstance=port->getNameOfTypeOfCurrentInstance();
519   if(typeOfPortInstance!=InputPort::NAME ||
520      (typeOfPortInstance == InputPort::NAME && 
521       initialStart->getNameOfTypeOfCurrentInstance()== OutputPort::NAME && 
522       !isNecessaryToBuildSpecificDelegateDF2DS(pointsOfView)) )
523     return ;
524   InputPort *portCasted=(InputPort *)port;
525   set<DSToDFForLoop*>::iterator iter;
526   for(iter=_inputsTraducer.begin();iter!=_inputsTraducer.end();iter++)
527     if((*iter)->getOutputPort("")->isAlreadyInSet(portCasted))
528       break;
529   if(iter==_inputsTraducer.end())
530     {
531       string what("Loop::getDelegateOf : Port with name "); what+=portCasted->getName(); what+=" not exported by loop "; what+=_name; 
532       throw Exception(what);
533     }
534   else
535     port=(*iter)->getInputDataStreamPort("");
536 }
537
538 void Loop::getDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, 
539                          const std::list<ComposedNode *>& pointsOfView)
540 {
541   string typeOfPortInstance=(port.first)->getNameOfTypeOfCurrentInstance();
542   if(typeOfPortInstance!=OutputPort::NAME ||
543     ( typeOfPortInstance == OutputPort::NAME && 
544       finalTarget->getNameOfTypeOfCurrentInstance()== InputPort::NAME && 
545       !isNecessaryToBuildSpecificDelegateDF2DS(pointsOfView)) )
546     return ;
547   OutPort *portCasted=port.first;
548   set<DFToDSForLoop*>::iterator iter;
549   for(iter=_outputsTraducer.begin();iter!=_outputsTraducer.end();iter++)
550     if(portCasted->isAlreadyLinkedWith((*iter)->getInputPort("")))
551       break;
552   if(iter==_outputsTraducer.end())
553     {
554       string what("Loop::getDelegateOf : Port with name "); what+=portCasted->getName(); what+=" not exported by loop "; what+=_name; 
555       throw Exception(what);
556     }
557   else
558     port.first=(*iter)->getOutputDataStreamPort("");
559 }
560
561 void Loop::releaseDelegateOf(InPort * & port, OutPort *initialStart, const std::list<ComposedNode *>& pointsOfView)
562 {
563   string typeOfPortInstance=port->getNameOfTypeOfCurrentInstance();
564   if(typeOfPortInstance!=InputPort::NAME ||
565     ( typeOfPortInstance == InputPort::NAME && 
566       initialStart->getNameOfTypeOfCurrentInstance()== OutputPort::NAME && 
567       !isNecessaryToBuildSpecificDelegateDF2DS(pointsOfView)) )
568     return ;
569   InputPort *portCasted=(InputPort *)port;
570   set<DSToDFForLoop*>::iterator iter;
571   for(iter=_inputsTraducer.begin();iter!=_inputsTraducer.end();iter++)
572     if((*iter)->getOutputPort("")->isAlreadyInSet(portCasted))
573       break;
574   if(iter==_inputsTraducer.end())
575     {
576       string what("Loop::releaseDelegateOf Port with name "); what+=portCasted->getName(); what+=" not exported by loop "; what+=_name; 
577       throw Exception(what);
578     }
579   else
580     {
581       port=(*iter)->getInputDataStreamPort("");
582       if((*iter)->loopHasOneLessRef())
583         {
584           (*iter)->getOutputPort("")->removeInPort(portCasted,false);
585           delete (*iter);
586           _inputsTraducer.erase(iter);
587         }
588     }
589 }
590
591 void Loop::releaseDelegateOf(OutPort *portDwn, OutPort *portUp, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView)
592 {
593   if(portDwn==portUp)
594     return ;
595   set<DFToDSForLoop*>::iterator iter;
596   for(iter=_outputsTraducer.begin();iter!=_outputsTraducer.end();iter++)
597     if((*iter)->getOutputDataStreamPort("")==portUp)
598       break;
599   if((*iter)->loopHasOneLessRef())
600     {
601       portDwn->removeInPort((*iter)->getInputPort(""),false);
602       delete (*iter);
603       _outputsTraducer.erase(iter);
604     }
605 }
606
607 void Loop::checkNoCyclePassingThrough(Node *node)
608 {
609   //throw Exception("Loop::checkNoCyclePassingThrough : Internal error occured");
610 }
611
612 void Loop::checkCFLinks(const std::list<OutPort *>& starts, InputPort *end, unsigned char& alreadyFed, bool direction, LinkInfo& info) const
613 {
614   Node *nodeEnd=end->getNode();
615   if(nodeEnd==this)
616     {//In this case 'end' port is a special port of this (for exemple ForLoop::_nbOfTimesPort)
617       //ASSERT(!direction) see Loop::checkControlDependancy (bw only)
618       solveObviousOrDelegateCFLinks(starts,end,alreadyFed,direction,info);
619     }
620   else
621     StaticDefinedComposedNode::checkCFLinks(starts,end,alreadyFed,direction,info);
622 }
623
624 /*!
625  * \note : States if a DF port must be considered on an upper level in hierarchy as a DS port or not from 'pointsOfView' observers.
626  * \return : 
627  *            - True : a traduction DF->DS has to be done
628  *            - False : no traduction needed
629  */
630 bool Loop::isNecessaryToBuildSpecificDelegateDF2DS(const std::list<ComposedNode *>& pointsOfView)
631 {
632   bool ret=false;
633   for(list<ComposedNode *>::const_iterator iter=pointsOfView.begin();iter!=pointsOfView.end() && !ret;iter++)
634     ret=(*iter)->isRepeatedUnpredictablySeveralTimes();
635   return ret;
636 }
637
638 //! Connect an OutPort to an InPort and add control link if necessary
639 /*!
640  * Connect the ports with a data link (edAddLink) 
641  * In a Loop don't add control flow link : use this only to add data back links
642  *
643  * \param start : the OutPort to connect
644  * \param end : the InPort to connect
645  * \return  true if a new link has been created, false otherwise.
646  */
647 bool Loop::edAddDFLink(OutPort *start, InPort *end)
648 {
649   return edAddLink(start,end);
650 }
651
652 //! Dump the node state to a stream
653 /*!
654  * \param os : the output stream
655  */
656 void Loop::writeDot(std::ostream &os) const
657 {
658   os << "  subgraph cluster_" << getId() << "  {\n" ;
659   //only one node in a loop
660   if(_node)
661     {
662       _node->writeDot(os);
663       os << getId() << " -> " << _node->getId() << ";\n";
664     }
665   os << "}\n" ;
666   os << getId() << "[fillcolor=\"" ;
667   YACS::StatesForNode state=getEffectiveState();
668   os << getColorState(state);
669   os << "\" label=\"" << "Loop:" ;
670   os << getQualifiedName() <<"\"];\n";
671 }
672
673
674 void Loop::accept(Visitor *visitor)
675 {
676   visitor->visitLoop(this);
677 }
678
679 void Loop::checkControlDependancy(OutPort *start, InPort *end, bool cross,
680                                   std::map < ComposedNode *,  std::list < OutPort * >, SortHierarc >& fw,
681                                   std::vector<OutPort *>& fwCross,
682                                   std::map< ComposedNode *, std::list < OutPort *>, SortHierarc >& bw,
683                                   LinkInfo& info) const
684 {
685   //First testing if end==getDecisionPort. This is the only case possible in theory.
686   if(end!=getDecisionPort())
687     return StaticDefinedComposedNode::checkControlDependancy(start,end,cross,fw,fwCross,bw,info);
688   if(cross)
689     throw Exception("Internal error occured - cross type link detected on decision port of a loop. Forbidden !");
690   fw[(ComposedNode *)this].push_back(start);
691 }
692
693 void Loop::checkBasicConsistency() const
694 {
695   DEBTRACE("Loop::checkBasicConsistency");
696   ComposedNode::checkBasicConsistency();
697   if(!_node)
698     throw Exception("For a loop, internal node is mandatory");
699 }
700
701 /*!
702  *  For use only when loading a previously saved execution
703  */
704
705 void YACS::ENGINE::NbDoneLoader(Loop* node, int val)
706 {
707   node->_nbOfTurns = val;
708 }