]> SALOME platform Git repositories - modules/yacs.git/blob - src/engine/DynParaLoop.cxx
Salome HOME
4d3ec98dbb52818bc88cceff42b94a6f9e604a74
[modules/yacs.git] / src / engine / DynParaLoop.cxx
1 #include "DynParaLoop.hxx"
2 #include "LinkInfo.hxx"
3 #include "OutPort.hxx"
4
5 //#define _DEVDEBUG_
6 #include "YacsTrace.hxx"
7
8 using namespace std;
9 using namespace YACS::ENGINE;
10
11 const char DynParaLoop::NAME_OF_SPLITTED_SEQ_OUT[]="SmplPrt";
12
13 const char DynParaLoop::NAME_OF_NUMBER_OF_BRANCHES[]="nbBranches";
14
15 AnyOutputPort::AnyOutputPort(const std::string& name, Node *node, TypeCode *type):OutputPort(name,node,type),
16                                                                                   DataPort(name,node,type),Port(node),_data(0)
17 {
18 }
19
20 AnyOutputPort::AnyOutputPort(const AnyOutputPort& other, Node *newHelder):OutputPort(other,newHelder),
21                                                                           DataPort(other,newHelder),
22                                                                           Port(other,newHelder),_data(0)
23 {
24 }
25
26 AnyOutputPort::~AnyOutputPort()
27 {
28   if(_data)
29     _data->decrRef();
30 }
31
32 void AnyOutputPort::setValue(Any *data) 
33 {
34   if(_data)
35     _data->decrRef();
36   _data = data; 
37   if(_data)
38     _data->incrRef();
39 }
40
41 OutputPort *AnyOutputPort::clone(Node *newHelder) const
42 {
43   return new AnyOutputPort(*this,newHelder);
44 }
45
46 DynParaLoop::DynParaLoop(const std::string& name, TypeCode *typeOfDataSplitted):ComposedNode(name),_node(0),_initNode(0),_nbOfEltConsumed(0),
47                                                                                 _nbOfBranches(NAME_OF_NUMBER_OF_BRANCHES,this,Runtime::_tc_int),
48                                                                                 _splittedPort(NAME_OF_SPLITTED_SEQ_OUT,this,typeOfDataSplitted)
49 {
50 }
51
52 DynParaLoop::~DynParaLoop()
53 {
54   delete _node;
55   delete _initNode;
56 }
57
58 DynParaLoop::DynParaLoop(const DynParaLoop& other, ComposedNode *father, bool editionOnly):ComposedNode(other,father),
59                                                                                            _nbOfBranches(other._nbOfBranches,this),
60                                                                                            _splittedPort(other._splittedPort,this),
61                                                                                            _node(0),_initNode(0),_nbOfEltConsumed(0)
62 {
63   if(other._node)
64     _node=other._node->clone(this,editionOnly);
65   if(other._initNode)
66     _initNode=other._initNode->clone(this,editionOnly);
67   const AnyOutputPort& startOfLinksToReproduce=other._splittedPort;
68   set<InPort *> endsOfLinksToReproduce=startOfLinksToReproduce.edSetInPort();
69   for(set<InPort *>::iterator iter=endsOfLinksToReproduce.begin();iter!=endsOfLinksToReproduce.end();iter++)
70     edAddLink(&_splittedPort,getInPort(other.getPortName(*iter)));
71 }
72
73 Node *DynParaLoop::edSetNode(Node *node)
74 {
75   if(_node==node)
76     return 0;
77   if(node)
78     {
79       if(node->_father)
80         {
81           std::string what = "DynParaLoop::edSetNode: node "; what += node->getName(); what += " is not orphan ! "; 
82           throw Exception(what);
83         }
84       if(_initNode)
85         if(_initNode->getName()==node->getName())
86           {
87             std::string what = "DynParaLoop::edSetNode: node "; what += node->getName(); what += " has the same name than init node already in "; what+=_name; what+="! "; 
88             throw Exception(what);
89           }
90     }
91   checkNoCrossHierachyWith(node);
92   ComposedNode::edRemoveChild(_node);
93   Node *ret=_node;
94   _node=node;
95   _node->_father=this;
96   //set _modified flag so that edUpdateState can refresh state
97   modified();
98   return ret;
99 }
100
101 void DynParaLoop::init(bool start)
102 {
103   ComposedNode::init(start);
104   if(!_node)
105     {
106       string what("DynParaLoop::init : no node specified for ForEachLoop with name "); what +=_name;
107       throw Exception(what);
108     }
109   _nbOfBranches.exInit(start);
110   _splittedPort.exInit();
111   _nbOfEltConsumed=0;
112 }
113
114 Node *DynParaLoop::edSetInitNode(Node *node)
115 {
116   if(_initNode==node)
117     return 0;
118   if(node)
119     {
120       if(node->_father)
121         {
122           std::string what = "DynParaLoop::edSetInitNode : node "; what += node->getName(); what += " is not orphan ! "; 
123           throw Exception(what);
124         }
125       if(_node)
126         if(_node->getName()==node->getName())
127           {
128             std::string what = "DynParaLoop::edSetInitNode : node "; what += node->getName(); what += " has the same name than node already in "; what+=_name; what+="! ";
129             throw Exception(what);
130           }
131     }
132   checkNoCrossHierachyWith(node);
133   edRemoveChild(_initNode);
134   Node *ret=_initNode;
135   _initNode=node;
136   _initNode->_father=this;
137   modified();
138   return ret;
139 }
140
141 int DynParaLoop::getNumberOfInputPorts() const
142 {
143   return ComposedNode::getNumberOfInputPorts()+1;
144 }
145
146 int DynParaLoop::getNumberOfOutputPorts() const
147 {
148   return ComposedNode::getNumberOfOutputPorts()+1;
149 }
150
151 std::list<OutputPort *> DynParaLoop::getSetOfOutputPort() const
152 {
153   list<OutputPort *> ret=ComposedNode::getSetOfOutputPort();
154   ret.push_back((OutputPort *)&_splittedPort);
155   return ret;
156 }
157
158 OutPort *DynParaLoop::getOutPort(const std::string& name) const throw(Exception)
159 {
160   if(name==NAME_OF_SPLITTED_SEQ_OUT)
161     return (OutPort *)&_splittedPort;
162   return ComposedNode::getOutPort(name);
163 }
164
165 InputPort *DynParaLoop::getInputPort(const std::string& name) const throw(Exception)
166 {
167   if(name==NAME_OF_NUMBER_OF_BRANCHES)
168     return (InputPort *)&_nbOfBranches;
169   return ComposedNode::getInputPort(name);
170 }
171
172 OutputPort *DynParaLoop::getOutputPort(const std::string& name) const throw(Exception)
173 {
174   if(name==NAME_OF_SPLITTED_SEQ_OUT)
175     return (OutputPort *)&_splittedPort;
176   return ComposedNode::getOutputPort(name);
177 }
178
179 bool DynParaLoop::isPlacementPredictableB4Run() const
180 {
181   return false;
182 }
183
184 Node *DynParaLoop::edRemoveNode()
185 {
186   if(!_node)
187     return 0;
188   ComposedNode::edRemoveChild(_node);
189   Node *ret=_node;
190   _node=0;
191   return ret;
192 }
193
194 Node *DynParaLoop::edRemoveInitNode()
195 {
196   if(!_initNode)
197     return 0;
198   ComposedNode::edRemoveChild(_initNode);
199   Node *ret=_initNode;
200   _initNode=0;
201   return ret;
202 }
203
204 void DynParaLoop::edRemoveChild(Node *node) throw(Exception)
205 {
206   ComposedNode::edRemoveChild(node);
207   if(node==_node)
208     _node=0;
209   if(node==_initNode)
210     _initNode=0;
211 }
212
213 std::list<Node *> DynParaLoop::edGetDirectDescendants() const
214 {
215   list<Node *> ret;
216   if(_node)
217     ret.push_back(_node);
218   if(_initNode)
219     ret.push_back(_initNode);
220   return ret;
221 }
222
223 std::list<InputPort *> DynParaLoop::getSetOfInputPort() const
224 {
225   list<InputPort *> ret=ComposedNode::getSetOfInputPort();
226   ret.push_back((InputPort *)&_nbOfBranches);
227   return ret;
228 }
229
230 std::list<InputPort *> DynParaLoop::getLocalInputPorts() const
231 {
232   list<InputPort *> ret=ComposedNode::getLocalInputPorts();
233   ret.push_back((InputPort *)&_nbOfBranches);
234   return ret;
235 }
236
237 unsigned DynParaLoop::getNumberOfBranchesCreatedDyn() const throw(Exception)
238 {
239   if(_execNodes.empty())
240     throw Exception("ForEachLoop::getNumberOfBranches : No branches created dynamically ! - ForEachLoop needs to run or to be runned to call getNumberOfBranches");
241   else
242     return _execNodes.size();
243 }
244
245 Node *DynParaLoop::getChildByShortName(const std::string& name) const throw(Exception)
246 {
247   if(_node)
248     if(name==_node->getName())
249       return _node;
250   if(_initNode)
251     if(name==_initNode->getName())
252       return  _initNode;
253   std::string what("node "); what+= name ; what+=" is not a child of DynParaLoop node "; what += getName();
254   throw Exception(what);
255 }
256
257 Node *DynParaLoop::getChildByNameExec(const std::string& name, unsigned id) const throw(Exception)
258 {
259   if(id>=getNumberOfBranchesCreatedDyn())
260     throw Exception("ForEachLoop::getChildByNameExec : invalid id - too large compared with dynamically created branches.");
261   if(_node)
262     if(name==_node->getName())
263       return _execNodes[id];
264   if(_initNode)
265     if(name==_initNode->getName())
266       return  _execInitNodes[id];
267   std::string what("node "); what+= name ; what+=" is not a child of DynParaLoop node "; what += getName();
268   throw Exception(what);
269 }
270
271 void DynParaLoop::cleanDynGraph()
272 {
273   for(vector<Node *>::iterator iter=_execNodes.begin();iter!=_execNodes.end();iter++)
274     delete *iter;
275   _execNodes.clear();
276   for(vector<Node *>::iterator iter2=_execInitNodes.begin();iter2!=_execInitNodes.end();iter2++)
277     delete *iter2;
278   _execNodes.clear();
279 }
280
281 /*!
282  * This method applies on newly cloned on exec nodes (_execNodes/_execInitNodes)
283  * the setting of input ports coming from outside of 'this'
284  */
285 void DynParaLoop::prepareInputsFromOutOfScope(int branchNb)
286 {
287   set< InPort * > portsToSetVals=getAllInPortsComingFromOutsideOfCurrentScope();
288   portsToSetVals.erase(&_nbOfBranches);//_nbOfBranches inport is not a candidate of dynamically duplicated inport.
289   for(set< InPort * >::iterator iter=portsToSetVals.begin();iter!=portsToSetVals.end();iter++)
290     {
291       InputPort *curPortCasted=(InputPort *) *iter;//Cast granted by ForEachLoop::buildDelegateOf(InPort)
292       void *val=curPortCasted->get();
293       InputPort *portToSet=getDynInputPortByAbsName(branchNb,getInPortName(*iter),true);
294       if(portToSet)//portToSet==0 in case of portToSet==_splitterNode._dataPortToDispatch of ForEach
295         {
296           portToSet->put((const void *)val);
297           portToSet->edNotifyReferencedBy(0);//This is to indicate that somewhere somebody deals with this inputport
298           //even if no direct physical link exists. This exclusively for _execNodes[branchNb]::init on the next turn of loop.
299         }
300     }
301 }
302
303 void DynParaLoop::putValueOnBranch(Any *val, unsigned branchId, bool first)
304 {
305   bool isDispatched = false;
306   set<InPort *> inPrtLkdWthSplttdPrt=_splittedPort.edSetInPort();
307   for(set<InPort *>::iterator iter=inPrtLkdWthSplttdPrt.begin();iter!=inPrtLkdWthSplttdPrt.end();iter++)
308     {
309       std::string portNameOnCurPrt=getPortName(*iter);
310       InputPort *portOnGivenBranch=getDynInputPortByAbsName(branchId,portNameOnCurPrt,first);//Cast granted because impossible to have cross protocol with _splittedPort
311       //see OptimizerLoop::buildDelegateOf
312       if(portOnGivenBranch)
313         {
314           if(first)
315             portOnGivenBranch->edNotifyReferencedBy(0);
316           InputPort *traducer=getRuntime()->adapt(portOnGivenBranch,
317                                                   Runtime::RUNTIME_ENGINE_INTERACTION_IMPL_NAME,_splittedPort.edGetType());
318           traducer->put((const void *)val);
319           isDispatched = true;
320           if(traducer!=portOnGivenBranch)
321             delete traducer;
322         }
323     }
324   if ( isDispatched )
325     {
326       Any *tmp=val->clone();
327       _splittedPort.setValue(tmp);
328       tmp->decrRef();
329     }
330 }
331
332 DynParaLoop::TypeOfNode DynParaLoop::getIdentityOfNotifyerNode(const Node *node, unsigned& id)
333 {
334   id=0;
335   for(vector<Node *>::iterator iter=_execNodes.begin();iter!=_execNodes.end();iter++,id++)
336     if(*iter==node)
337       return WORK_NODE;
338   id=0;
339   for(vector<Node *>::iterator iter2=_execInitNodes.begin();iter2!=_execInitNodes.end();iter2++,id++)
340     if(*iter2==node)
341       return INIT_NODE;
342 }
343
344 bool DynParaLoop::isMultiplicitySpecified(unsigned& value) const
345 {
346   if(_nbOfBranches.edIsManuallyInitialized())
347     if(_nbOfBranches.edGetNumberOfLinks()==0)
348       {
349         value=_nbOfBranches.getIntValue();
350         return true;
351       }
352   return false;
353 }
354
355 void DynParaLoop::forceMultiplicity(unsigned value)
356 {
357   _nbOfBranches.edRemoveAllLinksLinkedWithMe();
358   _nbOfBranches.edInit((int)value);
359 }
360
361 void DynParaLoop::buildDelegateOf(InPort * & port, OutPort *initialStart, const std::list<ComposedNode *>& pointsOfView)
362 {
363   string typeOfPortInstance=port->getNameOfTypeOfCurrentInstance();
364   if(typeOfPortInstance!=InputPort::NAME)
365     throw Exception("DynParaLoop::buildDelegateOf : A link with datastream end inside DynParaLoop this is not possible");
366 }
367
368 void DynParaLoop::buildDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView)
369 {
370   if(_initNode)
371     if(isInMyDescendance(port.first->getNode())==_initNode)
372       throw Exception("DynParaLoop::buildDelegateOf : uncorrect ForEach link : a link starting from init node can't leave the scope of ForEachLoop node it belongs to.");
373   if(port.first==&_splittedPort)
374     throw Exception("DynParaLoop::buildDelegateOf : uncorrect ForEach link : splitted port must be link within the scope of ForEachLoop node it belongs to.");
375 }
376
377 void DynParaLoop::checkCFLinks(const std::list<OutPort *>& starts, InputPort *end, unsigned char& alreadyFed, bool direction, LinkInfo& info) const
378 {
379   const char what[]="DynParaLoop::checkCFLinks : internal error.";
380   //First dealing checkCFLinks forwarding...
381   if(isInMyDescendance(end->getNode())==0)//no chance that _splittedPort is in starts due to buildDelegate.
382     solveObviousOrDelegateCFLinks(starts,end,alreadyFed,direction,info);
383   else
384     {//no forwarding here.
385       if(starts.size()!=1)
386         throw Exception(what);
387       //ASSERT(direction) : see DynParaLoop::checkControlDependancy only 'fw' filled.
388       if(*(starts.begin())!=&_splittedPort)
389         throw Exception(what);
390       if(alreadyFed==FREE_ST)
391         alreadyFed=FED_ST;
392       else if(alreadyFed==FED_ST)
393         {//Shame ! splittedPort fills a port already fed...
394           info.pushInfoLink(*(starts.begin()),end,I_USELESS);
395         }
396     }
397 }
398
399 /*!
400  * \param cross indicates if start -> end link is a DS link behind.
401  * \param fw out parameter.
402  * \param fwCross out parameter storing links where a cross has been detected.
403  * \param bw out parameter where backward links are stored.
404  */
405 void DynParaLoop::checkControlDependancy(OutPort *start, InPort *end, bool cross,
406                                          std::map < ComposedNode *,  std::list < OutPort * >, SortHierarc >& fw,
407                                          std::vector<OutPort *>& fwCross,
408                                          std::map< ComposedNode *, std::list < OutPort *>, SortHierarc >& bw,
409                                          LinkInfo& info) const
410 {
411   if(start==&_splittedPort)
412     fw[(ComposedNode *)this].push_back(start);
413   else
414     throw Exception("DynParaLoop::checkControlDependancy : Internal error occured - should never been called !");
415 }
416
417 /*!
418  * \note : For a given name 'name' of port in absolute form from this, returns the corresponding InputPort instance of the
419  *         port for the branch # 'branchNb'. The port can be part of _node or _initNode if it exists (if 'initNodeAdmitted' is true).
420  *         \b WARNING : no check performed on  'branchNb' value to see if it is compatible with size of '_execNodes'.
421  *         This method is called to dispatch value on each InputPort linked to this->._splitterNode._splittedPort
422  */
423 InputPort *DynParaLoop::getDynInputPortByAbsName(int branchNb, const std::string& name, bool initNodeAdmitted)
424 {
425   string portName, nodeName;
426   splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,true);
427   Node *staticChild = getChildByName(nodeName);
428   Node *desc=isInMyDescendance(staticChild);
429   if(desc==_node)
430     {
431       splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,false);
432       return _execNodes[branchNb]->getInputPort(portName);
433     }
434   else if(desc==_initNode)
435     if(initNodeAdmitted)
436       {
437         splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,false);
438         return _execInitNodes[branchNb]->getInputPort(portName);
439       }
440   return 0;
441 }