Salome HOME
Before virtualization of SalomeContainerTools
[modules/yacs.git] / src / engine / ForEachLoop.cxx
1 // Copyright (C) 2006-2019  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 "ForEachLoop.hxx"
21 #include "TypeCode.hxx"
22 #include "Visitor.hxx"
23 #include "ComposedNode.hxx"
24 #include "Executor.hxx"
25 #include "AutoLocker.hxx"
26
27 #include <iostream>
28 #include <iomanip>
29 #include <sstream>
30 #include <algorithm>    // std::replace_if
31
32 //#define _DEVDEBUG_
33 #include "YacsTrace.hxx"
34
35 #ifdef WIN32
36 #include <functional>
37 #endif
38
39 using namespace YACS::ENGINE;
40 using namespace std;
41
42 /*! \class YACS::ENGINE::ForEachLoop
43  *  \brief Loop node for parametric calculation
44  *
45  *  \ingroup Nodes
46  */
47
48 const char FakeNodeForForEachLoop::NAME[]="thisIsAFakeNode";
49
50 const char SplitterNode::NAME_OF_SEQUENCE_INPUT[]="SmplsCollection";
51
52 const char ForEachLoopGen::NAME_OF_SPLITTERNODE[]="splitter";
53
54 const int ForEachLoopGen::NOT_RUNNING_BRANCH_ID=-1;
55
56 const char ForEachLoopGen::INTERCEPTOR_STR[]="_interceptor";
57
58 InterceptorInputPort::InterceptorInputPort(const std::string& name, Node *node, TypeCode* type):AnyInputPort(name,node,type),
59                                                                                                 DataPort(name,node,type),Port(node),
60                                                                                                 _repr(0)
61 {
62 }
63
64 InterceptorInputPort::InterceptorInputPort(const  InterceptorInputPort& other, Node *newHelder):AnyInputPort(other,newHelder),DataPort(other,newHelder),
65                                                                                                 Port(other,newHelder),
66                                                                                                 _repr(0)
67 {
68 }
69
70 void InterceptorInputPort::getAllRepresentants(std::set<InPort *>& repr) const
71 {
72   set<InPort *> ports=_repr->edSetInPort();
73   for(set<InPort *>::iterator iter=ports.begin();iter!=ports.end();iter++)
74     (*iter)->getAllRepresentants(repr);
75 }
76
77 InputPort *InterceptorInputPort::clone(Node *newHelder) const
78 {
79   return new InterceptorInputPort(*this,newHelder);
80 }
81
82 void InterceptorInputPort::setRepr(AnySplitOutputPort *repr)
83 {
84   _repr=repr;
85 }
86
87 bool AnySplitOutputPort::decrRef()
88 {
89   return (--_cnt==0);
90 }
91
92 void AnySplitOutputPort::incrRef() const
93 {
94   _cnt++;
95 }
96
97 AnySplitOutputPort::AnySplitOutputPort(const std::string& name, Node *node, TypeCode *type):OutputPort(name,node,type),
98                                                                                             DataPort(name,node,type),Port(node),
99                                                                                             _repr(0),_intercptr(0),_cnt(1)
100 {
101 }
102
103 AnySplitOutputPort::AnySplitOutputPort(const AnySplitOutputPort& other, Node *newHelder):OutputPort(other,newHelder),
104                                                                                          DataPort(other,newHelder),
105                                                                                          Port(other,newHelder),
106                                                                                          _repr(0),_intercptr(0),_cnt(1)
107 {
108 }
109
110 bool AnySplitOutputPort::addInPort(InPort *inPort) throw(YACS::Exception)
111 {
112   bool ret=OutputPort::addInPort(inPort);
113   if(_repr)
114     _repr->addInPort(_intercptr);
115   return ret;
116 }
117
118 void AnySplitOutputPort::getAllRepresented(std::set<OutPort *>& represented) const
119 {
120   if(!_repr)
121     OutPort::getAllRepresented(represented);
122   else
123     _repr->getAllRepresented(represented);
124 }
125
126 int AnySplitOutputPort::removeInPort(InPort *inPort, bool forward) throw(YACS::Exception)
127 {
128   bool ret=OutputPort::removeInPort(inPort,forward);
129   if(_repr)
130     if(_setOfInputPort.empty())
131       _repr->removeInPort(_intercptr,forward);
132   return ret;
133 }
134
135 void AnySplitOutputPort::addRepr(OutPort *repr, InterceptorInputPort *intercptr)
136 {
137   _repr=repr;
138   _intercptr=intercptr;
139 }
140
141 OutputPort *AnySplitOutputPort::clone(Node *newHelder) const
142 {
143   return new AnySplitOutputPort(*this,newHelder);
144 }
145
146 SeqAnyInputPort::SeqAnyInputPort(const std::string& name, Node *node, TypeCodeSeq* type):AnyInputPort(name,node,type),DataPort(name,node,type),Port(node)
147 {
148   _type->decrRef();
149 }
150
151 SeqAnyInputPort::SeqAnyInputPort(const  SeqAnyInputPort& other, Node *newHelder):AnyInputPort(other,newHelder),DataPort(other,newHelder),Port(other,newHelder)
152 {
153 }
154
155 InputPort *SeqAnyInputPort::clone(Node *newHelder) const
156 {
157   return new SeqAnyInputPort(*this,newHelder);
158 }
159
160 unsigned SeqAnyInputPort::getNumberOfElements() const
161 {
162   const SequenceAny * valCsted=(const SequenceAny *) _value;
163   if (valCsted) return valCsted->size();
164   return 0;
165 }
166
167 Any *SeqAnyInputPort::getValueAtRank(int i) const
168 {
169   const SequenceAny * valCsted=(const SequenceAny *) _value;
170   AnyPtr ret=(*valCsted)[i];
171   ret->incrRef();
172   return ret;
173 }
174
175 std::string SeqAnyInputPort::dump()
176 {
177   stringstream xmldump;
178   int nbElem = getNumberOfElements();
179   xmldump << "<value><array><data>" << endl;
180   for (int i = 0; i < nbElem; i++)
181     {
182       Any *val = getValueAtRank(i);
183       switch (((YACS::ENGINE::TypeCodeSeq *)edGetType())->contentType()->kind())
184         {
185         case Double:
186           xmldump << "<value><double>" << setprecision(16) << val->getDoubleValue() << "</double></value>" << endl;
187           break;
188         case Int:
189           xmldump << "<value><int>" << val->getIntValue() << "</int></value>" << endl;
190           break;
191         case Bool:
192           xmldump << "<value><boolean>" << val->getBoolValue() << "</boolean></value>" << endl;
193           break;
194         case String:
195           xmldump << "<value><string>" << val->getStringValue() << "</string></value>" << endl;
196           break;
197         case Objref:
198           xmldump << "<value><objref>" << ToBase64(val->getStringValue()) << "</objref></value>" << endl;
199           break;
200         default:
201           xmldump << "<value><error> NO_SERIALISATION_AVAILABLE </error></value>" << endl;
202           break;
203         }
204     }
205   xmldump << "</data></array></value>" << endl;
206   return xmldump.str();
207 }
208
209 SplitterNode::SplitterNode(const std::string& name, TypeCode *typeOfData, 
210                            ForEachLoopGen *father):ElementaryNode(name),
211                                                 _dataPortToDispatch(NAME_OF_SEQUENCE_INPUT,
212                                                                     this,(TypeCodeSeq *)TypeCode::sequenceTc("","",typeOfData))
213 {
214   _father=father;
215 }
216
217 SplitterNode::SplitterNode(const SplitterNode& other, ForEachLoopGen *father):ElementaryNode(other,father),
218                                                                            _dataPortToDispatch(other._dataPortToDispatch,this)
219 {
220 }
221
222 InputPort *SplitterNode::getInputPort(const std::string& name) const throw(YACS::Exception)
223 {
224   if(name==NAME_OF_SEQUENCE_INPUT)
225     return (InputPort *)&_dataPortToDispatch;
226   else
227     return ElementaryNode::getInputPort(name);
228 }
229
230 Node *SplitterNode::simpleClone(ComposedNode *father, bool editionOnly) const
231 {
232   return new SplitterNode(*this,(ForEachLoopGen *)father);
233 }
234
235 unsigned SplitterNode::getNumberOfElements() const
236 {
237   return _dataPortToDispatch.getNumberOfElements();
238 }
239
240 void SplitterNode::execute()
241 {
242   //Nothing : should never been called elsewhere big problem...
243 }
244
245 void SplitterNode::init(bool start)
246 {
247   ElementaryNode::init(start);
248   _dataPortToDispatch.exInit(start);
249 }
250
251 void SplitterNode::putSplittedValueOnRankTo(int rankInSeq, int branch, bool first)
252 {
253   Any *valueToDispatch=_dataPortToDispatch.getValueAtRank(rankInSeq);
254   ForEachLoopGen *fatherTyped=(ForEachLoopGen *)_father;
255   fatherTyped->putValueOnBranch(valueToDispatch,branch,first);
256   valueToDispatch->decrRef();
257 }
258
259 FakeNodeForForEachLoop::FakeNodeForForEachLoop(ForEachLoopGen *loop, bool normalFinish):ElementaryNode(NAME),
260                                                                                         _loop(loop),
261                                                                                         _normalFinish(normalFinish)
262 {
263   _state=YACS::TOACTIVATE;
264   _father=_loop->getFather();
265 }
266
267 FakeNodeForForEachLoop::FakeNodeForForEachLoop(const FakeNodeForForEachLoop& other):ElementaryNode(other),_loop(0),
268                                                                                     _normalFinish(false)
269 {
270 }
271
272 Node *FakeNodeForForEachLoop::simpleClone(ComposedNode *father, bool editionOnly) const
273 {
274   return new FakeNodeForForEachLoop(*this);
275 }
276
277 void FakeNodeForForEachLoop::exForwardFailed()
278 {
279   _loop->exForwardFailed();
280 }
281
282 void FakeNodeForForEachLoop::exForwardFinished()
283
284   _loop->exForwardFinished();
285 }
286
287 void FakeNodeForForEachLoop::execute()
288 {
289   if(!_normalFinish)
290     throw Exception("");//only to trigger ABORT on Executor
291   else
292     _loop->pushAllSequenceValues();
293 }
294
295 void FakeNodeForForEachLoop::aborted()
296 {
297   _loop->setState(YACS::ERROR);
298 }
299
300 void FakeNodeForForEachLoop::finished()
301 {
302   _loop->setState(YACS::DONE);
303 }
304
305 ForEachLoopPassedData::ForEachLoopPassedData(const std::vector<unsigned int>& passedIds, const std::vector<SequenceAny *>& passedOutputs, const std::vector<std::string>& nameOfOutputs):_passedIds(passedIds),_passedOutputs(passedOutputs),_nameOfOutputs(nameOfOutputs)
306 {
307   std::size_t sz(_passedIds.size()),sz1(passedOutputs.size()),sz2(nameOfOutputs.size());
308   if(sz1!=sz2)
309     throw YACS::Exception("ForEachLoopPassedData::ForEachLoopPassedData : nameOfOutputs and passedOutputs must have the same size !");
310   for(std::vector<SequenceAny *>::iterator it=_passedOutputs.begin();it!=_passedOutputs.end();it++)
311     {
312       const SequenceAny *elt(*it);
313       if(elt)
314         if(sz!=(std::size_t)elt->size())
315           throw YACS::Exception("ForEachLoopPassedData::ForEachLoopPassedData : incoherent input of passed data !");
316     }
317   for(std::vector<SequenceAny *>::iterator it=_passedOutputs.begin();it!=_passedOutputs.end();it++)
318     {
319       SequenceAny *elt(*it);
320       if(elt)
321         elt->incrRef();
322     }
323 }
324
325 ForEachLoopPassedData::ForEachLoopPassedData(const ForEachLoopPassedData& copy)
326 : _passedIds(copy._passedIds),
327   _passedOutputs(copy._passedOutputs),
328   _nameOfOutputs(copy._nameOfOutputs),
329   _flagsIds(copy._flagsIds)
330 {
331 }
332
333 ForEachLoopPassedData::~ForEachLoopPassedData()
334 {
335   for(std::vector<SequenceAny *>::iterator it=_passedOutputs.begin();it!=_passedOutputs.end();it++)
336     {
337       SequenceAny *elt(*it);
338       if(elt)
339         elt->decrRef();
340     }
341 }
342
343 void ForEachLoopPassedData::init()
344 {
345   _flagsIds.clear();
346 }
347
348 void ForEachLoopPassedData::checkCompatibilyWithNb(int nbOfElts) const
349 {
350   if(nbOfElts<0)
351     throw YACS::Exception("ForEachLoopPassedData::checkCompatibilyWithNb : nb of elts is expected to be > 0 !");
352   std::size_t sizeExp(_passedIds.size()),nbOfElts2(nbOfElts);
353   if(nbOfElts2<sizeExp)
354     throw YACS::Exception("ForEachLoopPassedData::checkCompatibilyWithNb : Invalid nb of elemts in input seq regarding passed data set !");
355   for(std::vector<unsigned int>::const_iterator it=_passedIds.begin();it!=_passedIds.end();it++)
356     {
357       if((*it)>=nbOfElts2)
358         throw YACS::Exception("ForEachLoopPassedData::checkCompatibilyWithNb : Invalid nb of elemts in input seq regarding passed data set 2 !");
359     }
360   _flagsIds.resize(nbOfElts);
361   std::fill(_flagsIds.begin(),_flagsIds.end(),false);
362   for(std::vector<unsigned int>::const_iterator it=_passedIds.begin();it!=_passedIds.end();it++)
363     {
364       if(*it<nbOfElts)
365         {
366           if(!_flagsIds[*it])
367             _flagsIds[*it]=true;
368           else
369             {
370               std::ostringstream oss; oss << "ForEachLoopPassedData::checkCompatibilyWithNb : id " << *it << " in list of ids appears more than once !";
371               throw YACS::Exception(oss.str());
372             }
373         }
374       else
375         {
376           std::ostringstream oss; oss << "ForEachLoopPassedData::checkCompatibilyWithNb : Presence of id " << *it << " in list of ids ! Must be in [0," <<  nbOfElts << ") !";
377           throw YACS::Exception(oss.str());
378         }
379     }
380 }
381
382 void ForEachLoopPassedData::checkLevel2(const std::vector<AnyInputPort *>& ports) const
383 {
384   std::size_t sz(_nameOfOutputs.size());
385   if(sz!=ports.size())
386     throw YACS::Exception("ForEachLoopPassedData::checkLevel2 : mismatch of size of vectors !");
387   for(std::size_t i=0;i<sz;i++)
388     {
389       AnyInputPort *elt(ports[i]);
390       if(!elt)
391         throw YACS::Exception("ForEachLoopPassedData::checkLevel2 : presence of null instance !");
392       if(_nameOfOutputs[i]!=elt->getName())
393         {
394           std::ostringstream oss; oss << "ForEachLoopPassedData::checkLevel2 : At pos #" << i << " the name is not OK !";
395           throw YACS::Exception(oss.str());
396         }
397     }
398 }
399
400 /*!
401  * performs local to abs id. Input \a localId refers to an id in all jobs to perform. Returned id refers to pos in whole output sequences.
402  */
403 int ForEachLoopPassedData::toAbsId(int localId) const
404 {
405   if(localId<0)
406     throw YACS::Exception("ForEachLoopPassedData::toAbsId : local pos must be >= 0 !");
407   int ret(0),curLocId(0);
408   for(std::vector<bool>::const_iterator it=_flagsIds.begin();it!=_flagsIds.end();it++,ret++)
409     {
410       if(!*it)
411         {
412           if(localId==curLocId)
413             return ret;
414           curLocId++;
415         }
416     }
417   throw YACS::Exception("ForEachLoopPassedData::toAbsId : not referenced Id !");
418 }
419
420 /*!
421  * Equivalent to toAbsId except that only ON are considered here.
422  */
423 int ForEachLoopPassedData::toAbsIdNot(int localId) const
424 {
425   if(localId<0)
426     throw YACS::Exception("ForEachLoopPassedData::toAbsIdNot : local pos must be >= 0 !");
427   int ret(0),curLocId(0);
428   for(std::vector<bool>::const_iterator it=_flagsIds.begin();it!=_flagsIds.end();it++,ret++)
429     {
430       if(*it)//<- diff is here !
431         {
432           if(localId==curLocId)
433             return ret;
434           curLocId++;
435         }
436     }
437   throw YACS::Exception("ForEachLoopPassedData::toAbsIdNot : not referenced Id !");
438 }
439
440 int ForEachLoopPassedData::getNumberOfElementsToDo() const
441 {
442   std::size_t nbAllElts(_flagsIds.size());
443   std::size_t ret(nbAllElts-_passedIds.size());
444   return ret;
445 }
446
447 void ForEachLoopPassedData::assignAlreadyDone(const std::vector<SequenceAny *>& execVals) const
448 {
449   std::size_t sz(execVals.size());
450   if(_passedOutputs.size()!=sz)
451     throw YACS::Exception("ForEachLoopPassedData::assignedAlreadyDone : mismatch of size of vectors !");
452   for(std::size_t i=0;i<sz;i++)
453     {
454       SequenceAny *elt(_passedOutputs[i]);
455       SequenceAny *eltDestination(execVals[i]);
456       if(!elt)
457         throw YACS::Exception("ForEachLoopPassedData::assignedAlreadyDone : presence of null elt !");
458       unsigned int szOfElt(elt->size());
459       for(unsigned int j=0;j<szOfElt;j++)
460         {
461           AnyPtr elt1((*elt)[j]);
462           int jAbs(toAbsIdNot(j));
463           eltDestination->setEltAtRank(jAbs,elt1);
464         }
465     }
466 }
467
468 ForEachLoopGen::ForEachLoopGen(const std::string& name, TypeCode *typeOfDataSplitted, std::unique_ptr<NbBranchesAbstract>&& branchManager):
469                                                 DynParaLoop(name,typeOfDataSplitted,std::move(branchManager)),
470                                                 _splitterNode(NAME_OF_SPLITTERNODE,typeOfDataSplitted,this),
471                                                 _execCurrentId(0),_nodeForSpecialCases(0),_currentIndex(0),_passedData(0)
472 {
473 }
474
475 ForEachLoopGen::ForEachLoopGen(const ForEachLoopGen& other, ComposedNode *father, bool editionOnly):DynParaLoop(other,father,editionOnly),
476                                                                                                    _splitterNode(other._splitterNode,this),
477                                                                                                    _execCurrentId(0),_nodeForSpecialCases(0),_currentIndex(0),_passedData(0)
478 {
479   int i=0;
480   if(!editionOnly)
481     for(vector<AnySplitOutputPort *>::const_iterator iter2=other._outGoingPorts.begin();iter2!=other._outGoingPorts.end();iter2++,i++)
482       {
483         AnySplitOutputPort *temp=new AnySplitOutputPort(*(*iter2),this);
484         InterceptorInputPort *interc=new InterceptorInputPort(*other._intecptrsForOutGoingPorts[i],this);
485         temp->addRepr(getOutPort(other.getOutPortName((*iter2)->getRepr())),interc);
486         interc->setRepr(temp);
487         _outGoingPorts.push_back(temp);
488         _intecptrsForOutGoingPorts.push_back(interc);
489       }
490 }
491
492 ForEachLoopGen::~ForEachLoopGen()
493 {
494   cleanDynGraph();
495   for(vector<AnySplitOutputPort *>::iterator iter=_outGoingPorts.begin();iter!=_outGoingPorts.end();iter++)
496     delete *iter;
497   for(vector<InterceptorInputPort *>::iterator iter2=_intecptrsForOutGoingPorts.begin();iter2!=_intecptrsForOutGoingPorts.end();iter2++)
498     delete *iter2;
499   delete _passedData;
500 }
501
502 void ForEachLoopGen::init(bool start)
503 {
504   DynParaLoop::init(start);
505   _splitterNode.init(start);
506   _execCurrentId=0;
507   cleanDynGraph();
508   _currentIndex = 0;
509   exUpdateProgress();
510   if(_passedData)
511     _passedData->init();
512 }
513
514 void ForEachLoopGen::exUpdateState()
515 {
516   DEBTRACE("ForEachLoopGen::exUpdateState");
517   if(_state == YACS::DISABLED)
518     return;
519   if(_state == YACS::DONE)
520     return;
521   if(_inGate.exIsReady())
522     {
523       //internal graph update
524       int i;
525       int nbOfElts(_splitterNode.getNumberOfElements()),nbOfEltsDone(0);
526       int nbOfBr(_nbOfBranches->getNumberOfBranches(nbOfElts));
527       if(_passedData)
528         {
529           _passedData->checkCompatibilyWithNb(nbOfElts);
530           nbOfEltsDone=_passedData->getNumberOfEltsAlreadyDone();
531         }
532       int nbOfEltsToDo(nbOfElts-nbOfEltsDone);
533
534       DEBTRACE("nbOfElts=" << nbOfElts);
535       DEBTRACE("nbOfBr=" << nbOfBr);
536
537       if(nbOfEltsToDo==0)
538         {
539           prepareSequenceValues(0);
540           delete _nodeForSpecialCases;
541           _nodeForSpecialCases=new FakeNodeForForEachLoop(this,true);
542           setState(YACS::ACTIVATED);
543           return ;
544         }
545       if(nbOfBr<=0)
546         {
547           delete _nodeForSpecialCases;
548           _nodeForSpecialCases=new FakeNodeForForEachLoop(this,getAllOutPortsLeavingCurrentScope().empty());
549           setState(YACS::ACTIVATED);
550           return ;
551         }
552       if(nbOfBr>nbOfEltsToDo)
553         nbOfBr=nbOfEltsToDo;
554       _execNodes.resize(nbOfBr);
555       _execIds.resize(nbOfBr);
556       _execOutGoingPorts.resize(nbOfBr);
557       prepareSequenceValues(nbOfElts);
558       if(_initNode)
559         _execInitNodes.resize(nbOfBr);
560       _initializingCounter = 0;
561       if (_finalizeNode)
562         _execFinalizeNodes.resize(nbOfBr);
563
564       vector<Node *> origNodes;
565       origNodes.push_back(_initNode);
566       origNodes.push_back(_node);
567       origNodes.push_back(_finalizeNode);
568
569       //Conversion exceptions can be thrown by createOutputOutOfScopeInterceptors 
570       //so catch them to control errors
571       try
572         {
573           for(i=0;i<nbOfBr;i++)
574             {
575               DEBTRACE( "-------------- 2" );
576               vector<Node *> clonedNodes = cloneAndPlaceNodesCoherently(origNodes);
577               if(_initNode)
578                 _execInitNodes[i] = clonedNodes[0];
579               _execNodes[i] = clonedNodes[1];
580               if(_finalizeNode)
581                 _execFinalizeNodes[i] = clonedNodes[2];
582               DEBTRACE( "-------------- 4" );
583               prepareInputsFromOutOfScope(i);
584               DEBTRACE( "-------------- 5" );
585               createOutputOutOfScopeInterceptors(i);
586               DEBTRACE( "-------------- 6" );
587             }
588           for(i=0;i<nbOfBr;i++)
589             {
590               DEBTRACE( "-------------- 1 " << i << " " << _execCurrentId);
591               _execIds[i]=_execCurrentId;
592               int posInAbs(_execCurrentId);
593               if(_passedData)
594                 posInAbs=_passedData->toAbsId(_execCurrentId);
595               _splitterNode.putSplittedValueOnRankTo(posInAbs,i,true);
596               _execCurrentId++;
597               DEBTRACE( "-------------- 7" );
598             }
599           if(_passedData)
600             {
601               _passedData->checkLevel2(_execOutGoingPorts[0]);
602               _passedData->assignAlreadyDone(_execVals);
603             }
604           // clean inputs data coming from the outside in _node
605           set< InPort * > portsToSetVals=getAllInPortsComingFromOutsideOfCurrentScope();
606           for(auto iter : portsToSetVals)
607             {
608               InputPort *curPortCasted=(InputPort *) iter;//Cast granted by ForEachLoopGen::buildDelegateOf(InPort)
609               if(!curPortCasted->canSafelySqueezeMemory())// this can appear strange ! if not safelySqueeze -> release. Nevertheless it is true.
610                 curPortCasted->releaseData();             // these input ports have been incremented with InputPort::put into DynParaLoop::prepareInputsFromOutOfScope. So they can be released now.
611             }
612         }
613       catch(YACS::Exception& ex)
614         {
615           //ForEachLoop must be put in error and the exception rethrown to notify the caller
616           DEBTRACE( "ForEachLoopGen::exUpdateState: " << ex.what() );
617           setState(YACS::ERROR);
618           setErrorDetails(ex.what());
619           exForwardFailed();
620           throw;
621         }
622
623       setState(YACS::ACTIVATED); // move the calling of setState method there for adding observers for clone nodes in GUI part
624
625       //let's go
626       for(i=0;i<nbOfBr;i++)
627         if(_initNode)
628           {
629             _execInitNodes[i]->exUpdateState();
630             _initializingCounter++;
631           }
632         else
633           {
634             _nbOfEltConsumed++;
635             _execNodes[i]->exUpdateState();
636           }
637
638       forwardExecStateToOriginalBody(_execNodes[nbOfBr-1]);
639     }
640 }
641
642 void ForEachLoopGen::exUpdateProgress()
643 {
644   // emit notification to all observers registered with the dispatcher on any change of the node's state
645   sendEvent("progress");
646 }
647
648 void ForEachLoopGen::getReadyTasks(std::vector<Task *>& tasks)
649 {
650   if(!_node)
651     return;
652   if(_state==YACS::TOACTIVATE) setState(YACS::ACTIVATED);
653   if(_state==YACS::TOACTIVATE || _state==YACS::ACTIVATED)
654     {
655       if(_nodeForSpecialCases)
656         {
657           _nodeForSpecialCases->getReadyTasks(tasks);
658           return ;
659         }
660       vector<Node *>::iterator iter;
661       for (iter=_execNodes.begin() ; iter!=_execNodes.end() ; iter++)
662         (*iter)->getReadyTasks(tasks);
663       for (iter=_execInitNodes.begin() ; iter!=_execInitNodes.end() ; iter++)
664         (*iter)->getReadyTasks(tasks);
665       for (iter=_execFinalizeNodes.begin() ; iter!=_execFinalizeNodes.end() ; iter++)
666         (*iter)->getReadyTasks(tasks);
667     }
668 }
669
670 int ForEachLoopGen::getNumberOfInputPorts() const
671 {
672   return DynParaLoop::getNumberOfInputPorts()+1;
673 }
674
675 void ForEachLoopGen::checkNoCyclePassingThrough(Node *node) throw(YACS::Exception)
676 {
677   //TO DO
678 }
679
680 void ForEachLoopGen::selectRunnableTasks(std::vector<Task *>& tasks)
681 {
682 }
683
684 std::list<InputPort *> ForEachLoopGen::getSetOfInputPort() const
685 {
686   list<InputPort *> ret=DynParaLoop::getSetOfInputPort();
687   ret.push_back((InputPort *)&_splitterNode._dataPortToDispatch);
688   return ret;
689 }
690
691 std::list<InputPort *> ForEachLoopGen::getLocalInputPorts() const
692 {
693   list<InputPort *> ret=DynParaLoop::getLocalInputPorts();
694   ret.push_back((InputPort *)&_splitterNode._dataPortToDispatch);
695   return ret;
696 }
697
698 InputPort *ForEachLoopGen::getInputPort(const std::string& name) const throw(YACS::Exception)
699 {
700   if(name==SplitterNode::NAME_OF_SEQUENCE_INPUT)
701     return (InputPort *)&_splitterNode._dataPortToDispatch;
702   else
703     return DynParaLoop::getInputPort(name);
704 }
705
706 OutputPort *ForEachLoopGen::getOutputPort(const std::string& name) const throw(YACS::Exception)
707 {
708   for(vector<AnySplitOutputPort *>::const_iterator iter=_outGoingPorts.begin();iter!=_outGoingPorts.end();iter++)
709     {
710       if(name==(*iter)->getName())
711         return (OutputPort *)(*iter);
712     }
713   return DynParaLoop::getOutputPort(name);
714 }
715
716 OutPort *ForEachLoopGen::getOutPort(const std::string& name) const throw(YACS::Exception)
717 {
718   for(vector<AnySplitOutputPort *>::const_iterator iter=_outGoingPorts.begin();iter!=_outGoingPorts.end();iter++)
719     {
720       if(name==(*iter)->getName())
721         return (OutPort *)(*iter);
722     }
723   return DynParaLoop::getOutPort(name);
724 }
725
726 Node *ForEachLoopGen::getChildByShortName(const std::string& name) const throw(YACS::Exception)
727 {
728   if(name==NAME_OF_SPLITTERNODE)
729     return (Node *)&_splitterNode;
730   else
731     return DynParaLoop::getChildByShortName(name);
732 }
733
734 //! Method used to notify the node that a child node has finished
735 /*!
736  * Update the current state and return the change state
737  *
738  *  \param node : the child node that has finished
739  *  \return the state change
740  */
741 YACS::Event ForEachLoopGen::updateStateOnFinishedEventFrom(Node *node)
742 {
743   DEBTRACE("updateStateOnFinishedEventFrom " << node->getName() << " " << node->getState());
744   unsigned int id;
745   switch(getIdentityOfNotifyerNode(node,id))
746     {
747     case INIT_NODE:
748       return updateStateForInitNodeOnFinishedEventFrom(node,id);
749     case WORK_NODE:
750       return updateStateForWorkNodeOnFinishedEventFrom(node,id,true);
751     case FINALIZE_NODE:
752       return updateStateForFinalizeNodeOnFinishedEventFrom(node,id);
753     default:
754       YASSERT(false);
755     }
756   return YACS::NOEVENT;
757 }
758
759 YACS::Event ForEachLoopGen::updateStateForInitNodeOnFinishedEventFrom(Node *node, unsigned int id)
760 {
761   _execNodes[id]->exUpdateState();
762   _nbOfEltConsumed++;
763   _initializingCounter--;
764   _currentIndex++;
765   if (_initializingCounter == 0)
766     _initNode->setState(DONE);
767   return YACS::NOEVENT;
768 }
769
770 /*!
771  * \param [in] isNormalFinish - if true
772  */
773 YACS::Event ForEachLoopGen::updateStateForWorkNodeOnFinishedEventFrom(Node *node, unsigned int id, bool isNormalFinish)
774 {
775   _currentIndex++;
776   exUpdateProgress();
777   if(isNormalFinish)
778     {
779       int globalId(_execIds[id]);
780       if(_passedData)
781         globalId=_passedData->toAbsId(globalId);
782       sendEvent2("progress_ok",&globalId);
783       storeOutValsInSeqForOutOfScopeUse(globalId,id);
784     }
785   else
786     {
787       int globalId(_execIds[id]);
788       if(_passedData)
789         globalId=_passedData->toAbsId(globalId);
790       sendEvent2("progress_ko",&globalId);
791     }
792   //
793   if(_execCurrentId==getFinishedId())
794     {//No more elements of _dataPortToDispatch to treat
795       _execIds[id]=NOT_RUNNING_BRANCH_ID;
796       //analyzing if some samples are still on treatment on other branches.
797       bool isFinished(true);
798       for(int i=0;i<_execIds.size() && isFinished;i++)
799         isFinished=(_execIds[i]==NOT_RUNNING_BRANCH_ID);
800       if(isFinished)
801         {
802           try
803           {
804               if(_failedCounter!=0)
805                 {// case of keepgoing mode + a failed
806                   std::ostringstream oss; oss << "Keep Going mode activated and some errors (" << _failedCounter << ")reported !";
807                   DEBTRACE("ForEachLoopGen::updateStateOnFinishedEventFrom : "<< oss.str());
808                   setState(YACS::FAILED);
809                   return YACS::ABORT;
810                 }
811               pushAllSequenceValues();
812
813               if (_node)
814                 {
815                   _node->setState(YACS::DONE);
816
817                   ComposedNode* compNode = dynamic_cast<ComposedNode*>(_node);
818                   if (compNode)
819                     {
820                       std::list<Node *> aChldn = compNode->getAllRecursiveConstituents();
821                       std::list<Node *>::iterator iter=aChldn.begin();
822                       for(;iter!=aChldn.end();iter++)
823                         (*iter)->setState(YACS::DONE);
824                     }
825                 }
826
827               if (_finalizeNode == NULL)
828                 {
829                   // No finalize node, we just finish the loop at the end of exec nodes execution
830                   setState(YACS::DONE);
831                   return YACS::FINISH;
832                 }
833               else
834                 {
835                   // Run the finalize nodes, the loop will be done only when they all finish
836                   _unfinishedCounter = 0;  // This counter indicates how many branches are not finished
837                   for (int i=0 ; i<_execIds.size() ; i++)
838                     {
839                       YASSERT(_execIds[i] == NOT_RUNNING_BRANCH_ID);
840                       DEBTRACE("Launching finalize node for branch " << i);
841                       _execFinalizeNodes[i]->exUpdateState();
842                       _unfinishedCounter++;
843                     }
844                   return YACS::NOEVENT;
845                 }
846           }
847           catch(YACS::Exception& ex)
848           {
849               DEBTRACE("ForEachLoopGen::updateStateOnFinishedEventFrom: "<<ex.what());
850               //no way to push results : put following nodes in FAILED state
851               //TODO could be more fine grain : put only concerned nodes in FAILED state
852               exForwardFailed();
853               setState(YACS::ERROR);
854               return YACS::ABORT;
855           }
856         }
857     }
858   else if(_state == YACS::ACTIVATED)
859     {//more elements to do and loop still activated
860       _execIds[id]=_execCurrentId;
861       int posInAbs(_execCurrentId);
862       if(_passedData)
863         posInAbs=_passedData->toAbsId(_execCurrentId);
864       _splitterNode.putSplittedValueOnRankTo(posInAbs,id,false);
865       //forwardExecStateToOriginalBody(node);
866       node->init(false);
867       _execCurrentId++;
868       node->exUpdateState();
869       //forwardExecStateToOriginalBody(node);
870       _nbOfEltConsumed++;
871     }
872   else
873     {//elements to process and loop no more activated
874       DEBTRACE("foreach loop state " << _state);
875     }
876   return YACS::NOEVENT;
877 }
878
879 YACS::Event ForEachLoopGen::updateStateForFinalizeNodeOnFinishedEventFrom(Node *node, unsigned int id)
880 {
881   DEBTRACE("Finalize node finished on branch " << id);
882   _unfinishedCounter--;
883   _currentIndex++;
884   exUpdateProgress();
885   DEBTRACE(_unfinishedCounter << " finalize nodes still running");
886   if (_unfinishedCounter == 0)
887     {
888       _finalizeNode->setState(YACS::DONE);
889       setState(YACS::DONE);
890       return YACS::FINISH;
891     }
892   else
893     return YACS::NOEVENT;
894 }
895
896 YACS::Event ForEachLoopGen::updateStateOnFailedEventFrom(Node *node, const Executor *execInst)
897 {
898   unsigned int id;
899   DynParaLoop::TypeOfNode ton(getIdentityOfNotifyerNode(node,id));
900   // TODO: deal with keepgoing without the dependency to Executor
901   if(ton!=WORK_NODE || !execInst->getKeepGoingProperty())
902     return DynParaLoop::updateStateOnFailedEventFrom(node,execInst);
903   else
904     {
905       _failedCounter++;
906       return updateStateForWorkNodeOnFinishedEventFrom(node,id,false);
907     }
908 }
909
910 void ForEachLoopGen::InterceptorizeNameOfPort(std::string& portName)
911 {
912   std::replace_if(portName.begin(), portName.end(), std::bind1st(std::equal_to<char>(), '.'), '_');
913   portName += INTERCEPTOR_STR;
914 }
915
916 void ForEachLoopGen::buildDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView)
917 {
918   DynParaLoop::buildDelegateOf(port,finalTarget,pointsOfView);
919   string typeOfPortInstance=(port.first)->getNameOfTypeOfCurrentInstance();
920   if(typeOfPortInstance==OutputPort::NAME)
921     {
922       vector<AnySplitOutputPort *>::iterator iter=_outGoingPorts.begin();
923       int i=0;
924       for(;iter!=_outGoingPorts.end();iter++,i++)
925         if((*iter)->getRepr()==port.first || *iter==port.first)
926           break;
927       if(iter!=_outGoingPorts.end())
928         {
929           if(*iter!=port.first)
930             {
931               (*iter)->incrRef();
932               (*iter)->addRepr(port.first,_intecptrsForOutGoingPorts[i]);
933             }
934           port.first=*iter;
935         }
936       else
937         {
938           TypeCode *tcTrad((YACS::ENGINE::TypeCode*)finalTarget->edGetType()->subContentType(getFEDeltaBetween(port.first,finalTarget)));
939           TypeCodeSeq *newTc=(TypeCodeSeq *)TypeCode::sequenceTc("","",tcTrad);
940           // The out going ports belong to the ForEachLoop, whereas
941           // the delegated port belongs to a node child of the ForEachLoop.
942           // The name of the delegated port contains dots (bloc.node.outport),
943           // whereas the name of the out going port shouldn't do.
944           std::string outputPortName(getPortName(port.first));
945           InterceptorizeNameOfPort(outputPortName);
946           AnySplitOutputPort *newPort(new AnySplitOutputPort(outputPortName,this,newTc));
947           InterceptorInputPort *intercptor(new InterceptorInputPort(outputPortName + "_in",this,tcTrad));
948           intercptor->setRepr(newPort);
949           newTc->decrRef();
950           newPort->addRepr(port.first,intercptor);
951           _outGoingPorts.push_back(newPort);
952           _intecptrsForOutGoingPorts.push_back(intercptor);
953           port.first=newPort;
954         }
955     }
956   else
957     throw Exception("ForEachLoopGen::buildDelegateOf : not implemented for DS because not specified");
958 }
959
960 void ForEachLoopGen::getDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView) throw(YACS::Exception)
961 {
962   string typeOfPortInstance=(port.first)->getNameOfTypeOfCurrentInstance();
963   if(typeOfPortInstance==OutputPort::NAME)
964     {
965       vector<AnySplitOutputPort *>::iterator iter=_outGoingPorts.begin();
966       for(;iter!=_outGoingPorts.end();iter++)
967         if((*iter)->getRepr()==port.first)
968           break;
969       if(iter==_outGoingPorts.end())
970         {
971           string what("ForEachLoopGen::getDelegateOf : Port with name "); what+=port.first->getName(); what+=" not exported by ForEachLoop "; what+=_name; 
972           throw Exception(what);
973         }
974       else
975         port.first=(*iter);
976     }
977   else
978     throw Exception("ForEachLoopGen::getDelegateOf : not implemented because not specified");
979 }
980
981 void ForEachLoopGen::releaseDelegateOf(OutPort *portDwn, OutPort *portUp, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView) throw(YACS::Exception)
982 {
983   string typeOfPortInstance=portDwn->getNameOfTypeOfCurrentInstance();
984   if(typeOfPortInstance==OutputPort::NAME)
985     {
986       vector<AnySplitOutputPort *>::iterator iter=_outGoingPorts.begin();
987       vector<InterceptorInputPort *>::iterator iter2=_intecptrsForOutGoingPorts.begin();
988       for(;iter!=_outGoingPorts.end();iter++,iter2++)
989         if((*iter)->getRepr()==portDwn)
990           break;
991       //ASSERT(portUp==*iter.second)
992       if((*iter)->decrRef())
993         {
994           AnySplitOutputPort *p=*iter;
995           _outGoingPorts.erase(iter);
996           delete p;
997           InterceptorInputPort *ip=*iter2;
998           _intecptrsForOutGoingPorts.erase(iter2);
999           delete ip;
1000         }
1001     }
1002 }
1003
1004 OutPort *ForEachLoopGen::getDynOutPortByAbsName(int branchNb, const std::string& name)
1005 {
1006   string portName, nodeName;
1007   splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,false);
1008   Node *staticChild = getChildByName(nodeName);
1009   return _execNodes[branchNb]->getOutPort(portName);//It's impossible(garanteed by YACS::ENGINE::ForEachLoopGen::buildDelegateOf)
1010   //that a link starting from _initNode goes out of scope of 'this'.
1011 }
1012
1013 void ForEachLoopGen::cleanDynGraph()
1014 {
1015   DynParaLoop::cleanDynGraph();
1016   for(vector< SequenceAny *>::iterator iter3=_execVals.begin();iter3!=_execVals.end();iter3++)
1017     (*iter3)->decrRef();
1018   _execVals.clear();
1019   for(vector< vector<AnyInputPort *> >::iterator iter4=_execOutGoingPorts.begin();iter4!=_execOutGoingPorts.end();iter4++)
1020     for(vector<AnyInputPort *>::iterator iter5=(*iter4).begin();iter5!=(*iter4).end();iter5++)
1021       delete *iter5;
1022   _execOutGoingPorts.clear();
1023 }
1024
1025 void ForEachLoopGen::storeOutValsInSeqForOutOfScopeUse(int rank, int branchNb)
1026 {
1027   vector<AnyInputPort *>::iterator iter;
1028   int i=0;
1029   for(iter=_execOutGoingPorts[branchNb].begin();iter!=_execOutGoingPorts[branchNb].end();iter++,i++)
1030     {
1031       Any *val=(Any *)(*iter)->getValue();
1032       _execVals[i]->setEltAtRank(rank,val);
1033     }
1034 }
1035
1036 int ForEachLoopGen::getFinishedId()
1037 {
1038   if(!_passedData)
1039     return _splitterNode.getNumberOfElements();
1040   else
1041     return _passedData->getNumberOfElementsToDo();
1042 }
1043
1044 void ForEachLoopGen::prepareSequenceValues(int sizeOfSamples)
1045 {
1046   _execVals.resize(_outGoingPorts.size());
1047   vector<AnySplitOutputPort *>::iterator iter=_outGoingPorts.begin();
1048   for(int i=0;iter!=_outGoingPorts.end();iter++,i++)
1049     _execVals[i]=SequenceAny::New((*iter)->edGetType()->contentType(),sizeOfSamples);
1050 }
1051
1052 void ForEachLoopGen::pushAllSequenceValues()
1053 {
1054   vector<AnySplitOutputPort *>::iterator iter=_outGoingPorts.begin();
1055   int i=0;
1056   for(;iter!=_outGoingPorts.end();iter++,i++)
1057     (*iter)->put((const void *)_execVals[i]);
1058 }
1059
1060 void ForEachLoopGen::createOutputOutOfScopeInterceptors(int branchNb)
1061 {
1062   vector<AnySplitOutputPort *>::iterator iter=_outGoingPorts.begin();
1063   int i=0;
1064   for(;iter!=_outGoingPorts.end();iter++,i++)
1065     {
1066       DEBTRACE( (*iter)->getName() << " " << (*iter)->edGetType()->kind() );
1067       //AnyInputPort *interceptor=new AnyInputPort((*iter)->getName(),this,(*iter)->edGetType());
1068       OutPort *portOut=getDynOutPortByAbsName(branchNb,getOutPortName(((*iter)->getRepr())));
1069       DEBTRACE( portOut->getName() );
1070       TypeCode *tc((TypeCode *)(*iter)->edGetType()->contentType());
1071       AnyInputPort *interceptor=new AnyInputPort((*iter)->getName(),this,tc);
1072       portOut->addInPort(interceptor);
1073       _execOutGoingPorts[branchNb].push_back(interceptor);
1074     }
1075 }
1076
1077 void ForEachLoopGen::checkLinkPossibility(OutPort *start, const std::list<ComposedNode *>& pointsOfViewStart,
1078                                        InPort *end, const std::list<ComposedNode *>& pointsOfViewEnd) throw(YACS::Exception)
1079 {
1080   DynParaLoop::checkLinkPossibility(start, pointsOfViewStart, end, pointsOfViewEnd);
1081   if(end->getNode() == &_splitterNode)
1082     throw Exception("Illegal link within a foreach loop: \
1083 the 'SmplsCollection' port cannot be linked within the scope of the loop.");
1084   if(end == _nbOfBranches->getPort())
1085     throw Exception("Illegal link within a foreach loop: \
1086 the 'nbBranches' port cannot be linked within the scope of the loop.");
1087 }
1088
1089 std::list<OutputPort *> ForEachLoopGen::getLocalOutputPorts() const
1090 {
1091   list<OutputPort *> ret;
1092   ret.push_back(getOutputPort(NAME_OF_SPLITTED_SEQ_OUT)); 
1093   return ret;
1094 }
1095
1096 //! Dump the node state to a stream
1097 /*!
1098  * \param os : the output stream
1099  */
1100 void ForEachLoopGen::writeDot(std::ostream &os) const
1101 {
1102   os << "  subgraph cluster_" << getId() << "  {\n" ;
1103   //only one node in a loop
1104   if(_node)
1105     {
1106       _node->writeDot(os);
1107       os << getId() << " -> " << _node->getId() << ";\n";
1108     }
1109   os << "}\n" ;
1110   os << getId() << "[fillcolor=\"" ;
1111   YACS::StatesForNode state=getEffectiveState();
1112   os << getColorState(state);
1113   os << "\" label=\"" << "Loop:" ;
1114   os << getName() <<"\"];\n";
1115 }
1116
1117 //! Reset the state of the node and its children depending on the parameter level
1118 void ForEachLoopGen::resetState(int level)
1119 {
1120   if(level==0)return;
1121   DynParaLoop::resetState(level);
1122   _execCurrentId=0;
1123   cleanDynGraph();
1124 }
1125
1126 std::string ForEachLoopGen::getProgress() const
1127 {
1128   int nbElems(getNbOfElementsToBeProcessed());
1129   std::stringstream aProgress;
1130   if (nbElems > 0)
1131     aProgress << _currentIndex << "/" << nbElems;
1132   else
1133     aProgress << "0";
1134   return aProgress.str();
1135 }
1136
1137 //! Get the progress weight for all elementary nodes
1138 /*!
1139  * Only elementary nodes have weight. For each node in the loop, the weight done is multiplied
1140  * by the number of elements done and the weight total by the number total of elements
1141  */
1142 list<ProgressWeight> ForEachLoopGen::getProgressWeight() const
1143 {
1144   list<ProgressWeight> ret;
1145   list<Node *> setOfNode=edGetDirectDescendants();
1146   int elemDone=getCurrentIndex();
1147   int elemTotal=getNbOfElementsToBeProcessed();
1148   for(list<Node *>::const_iterator iter=setOfNode.begin();iter!=setOfNode.end();iter++)
1149     {
1150       list<ProgressWeight> myCurrentSet=(*iter)->getProgressWeight();
1151       for(list<ProgressWeight>::iterator iter=myCurrentSet.begin();iter!=myCurrentSet.end();iter++)
1152         {
1153           (*iter).weightDone=((*iter).weightTotal) * elemDone;
1154           (*iter).weightTotal*=elemTotal;
1155         }
1156       ret.insert(ret.end(),myCurrentSet.begin(),myCurrentSet.end());
1157     }
1158   return ret;
1159 }
1160
1161 int ForEachLoopGen::getNbOfElementsToBeProcessed() const
1162 {
1163   int nbOfElems(_splitterNode.getNumberOfElements());
1164   int nbBranches = _nbOfBranches->getNumberOfBranches(nbOfElems);
1165   return nbOfElems
1166          + (_initNode ? nbBranches:0)
1167          + (_finalizeNode ? nbBranches:0) ;
1168 }
1169
1170 /*!
1171  * This method allows to retrieve the state of \a this during execution or after. This method works even if this is \b NOT complete, or during execution or after a failure in \a this.
1172  * The typical usage of this method is to retrieve the results of items that passed successfully to avoid to lose all of them if only one fails.
1173  * This method has one input \a execut and 3 outputs.
1174  *
1175  * \param [in] execut - The single input is for threadsafety reasons because this method can be called safely during the execution of \a this.
1176  * \param [out] outputs - For each output ports in \a this linked with nodes sharing the same father than \a this the passed results are stored.
1177  *                        All of the items in \a outputs have the same size.
1178  * \param [out] nameOfOutputs - The array with same size than \a outputs, that tells for each item in outputs the output port it refers to.
1179  * \return the list of ids among \c this->edGetSeqOfSamplesPort() that run successfully. The length of this returned array will be the length of all
1180  *         SequenceAny objects contained in \a outputs.
1181  *
1182  * \sa edGetSeqOfSamplesPort
1183  */
1184 std::vector<unsigned int> ForEachLoopGen::getPassedResults(Executor *execut, std::vector<SequenceAny *>& outputs, std::vector<std::string>& nameOfOutputs) const
1185 {
1186   YACS::BASES::AutoLocker<YACS::BASES::Mutex> alck(&(execut->getTheMutexForSchedulerUpdate()));
1187   if(_execVals.empty())
1188     return std::vector<unsigned int>();
1189   if(_execOutGoingPorts.empty())
1190     return std::vector<unsigned int>();
1191   std::size_t sz(_execVals.size());
1192   outputs.resize(sz);
1193   nameOfOutputs.resize(sz);
1194   const std::vector<AnyInputPort *>& ports(_execOutGoingPorts[0]);
1195   for(std::size_t i=0;i<sz;i++)
1196     {
1197       outputs[i]=_execVals[i]->removeUnsetItemsFromThis();
1198       nameOfOutputs[i]=ports[i]->getName();
1199     }
1200   return _execVals[0]->getSetItems();
1201 }
1202
1203 /*!
1204  * This method is typically useful for post-mortem relaunch to avoid to recompute already passed cases. This method takes in input exactly the parameters retrieved by
1205  * getPassedResults method.
1206  */
1207 void ForEachLoopGen::assignPassedResults(const std::vector<unsigned int>& passedIds, const std::vector<SequenceAny *>& passedOutputs, const std::vector<std::string>& nameOfOutputs)
1208 {
1209   delete _passedData;
1210   _failedCounter=0;
1211   _passedData=new ForEachLoopPassedData(passedIds,passedOutputs,nameOfOutputs);
1212 }
1213
1214 int ForEachLoopGen::getFEDeltaBetween(OutPort *start, InPort *end)
1215 {
1216   Node *ns(start->getNode()),*ne(end->getNode());
1217   ComposedNode *co(getLowestCommonAncestor(ns,ne));
1218   int ret(0);
1219   Node *work(ns);
1220   while(work!=co)
1221     {
1222       ForEachLoopGen *isFE(dynamic_cast<ForEachLoopGen *>(work));
1223       if(isFE)
1224         ret++;
1225       work=work->getFather();
1226     }
1227   if(dynamic_cast<AnySplitOutputPort *>(start))
1228     ret--;
1229   return ret;
1230 }
1231
1232 /*!
1233  * This method is used to obtain the values already processed by the ForEachLoop.
1234  * A new ForEachLoopPassedData object is returned. You have to delete it.
1235  */
1236 ForEachLoopPassedData* ForEachLoopGen::getProcessedData()const
1237 {
1238   std::vector<SequenceAny *> outputs;
1239   std::vector<std::string> nameOfOutputs;
1240   if(_execVals.empty() || _execOutGoingPorts.empty())
1241     return new ForEachLoopPassedData(std::vector<unsigned int>(), outputs, nameOfOutputs);
1242   std::size_t sz(_execVals.size());
1243   outputs.resize(sz);
1244   nameOfOutputs.resize(sz);
1245   const std::vector<AnyInputPort *>& ports(_execOutGoingPorts[0]);
1246   for(std::size_t i=0;i<sz;i++)
1247     {
1248       outputs[i]=_execVals[i]->removeUnsetItemsFromThis();
1249       nameOfOutputs[i]=ports[i]->getName();
1250     }
1251   return new ForEachLoopPassedData(_execVals[0]->getSetItems(), outputs, nameOfOutputs);
1252 }
1253
1254 void ForEachLoopGen::setProcessedData(ForEachLoopPassedData* processedData)
1255 {
1256   if(_passedData)
1257     delete _passedData;
1258   _passedData = processedData;
1259 }
1260
1261 /*!
1262  * \param portName : "interceptorized" name of port.
1263  */
1264 const YACS::ENGINE::TypeCode* ForEachLoopGen::getOutputPortType(const std::string& portName)const
1265 {
1266   const YACS::ENGINE::TypeCode* ret=NULL;
1267   vector<AnySplitOutputPort *>::const_iterator it;
1268   for(it=_outGoingPorts.begin();it!=_outGoingPorts.end() && ret==NULL;it++)
1269   {
1270     std::string originalPortName(getPortName(*it));
1271     //InterceptorizeNameOfPort(originalPortName);
1272     DEBTRACE("ForEachLoopGen::getOutputPortType compare " << portName << " == " << originalPortName);
1273     if(originalPortName == portName)
1274     {
1275       ret = (*it)->edGetType()->contentType();
1276     }
1277   }
1278   return ret;
1279 }
1280
1281 Node *ForEachLoop::simpleClone(ComposedNode *father, bool editionOnly) const
1282 {
1283   return new ForEachLoop(*this,father,editionOnly);
1284 }
1285
1286 void ForEachLoop::accept(Visitor *visitor)
1287 {
1288   visitor->visitForEachLoop(this);
1289 }
1290
1291 void ForEachLoopDyn::accept(Visitor *visitor)
1292 {
1293   visitor->visitForEachLoopDyn(this);
1294 }
1295
1296 Node *ForEachLoopDyn::simpleClone(ComposedNode *father, bool editionOnly) const
1297 {
1298   return new ForEachLoopDyn(*this,father,editionOnly);
1299 }