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