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