Salome HOME
copy tag mergefrom_BR_V0_1_CC_Salome_04oct07
[modules/yacs.git] / src / engine / DynParaLoop.cxx
1 #include "DynParaLoop.hxx"
2 #include "OutPort.hxx"
3 #include<iostream>
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   ComposedNode::edRemoveChild(_node);
92   Node *ret=_node;
93   _node=node;
94   _node->_father=this;
95   return ret;
96 }
97
98 void DynParaLoop::init(bool start)
99 {
100   ComposedNode::init(start);
101   if(!_node)
102     {
103       string what("DynParaLoop::init : no node specified for ForEachLoop with name "); what +=_name;
104       throw Exception(what);
105     }
106   _nbOfBranches.exInit(start);
107   _splittedPort.exInit();
108   _nbOfEltConsumed=0;
109 }
110
111 Node *DynParaLoop::edSetInitNode(Node *node)
112 {
113   if(_initNode==node)
114     return 0;
115   if(node)
116     {
117       if(node->_father)
118         {
119           std::string what = "DynParaLoop::edSetInitNode : node "; what += node->getName(); what += " is not orphan ! "; 
120           throw Exception(what);
121         }
122       if(_node)
123         if(_node->getName()==node->getName())
124           {
125             std::string what = "DynParaLoop::edSetInitNode : node "; what += node->getName(); what += " has the same name than node already in "; what+=_name; what+="! ";
126             throw Exception(what);
127           }
128     }
129   edRemoveChild(_initNode);
130   Node *ret=_initNode;
131   _initNode=node;
132   _initNode->_father=this;
133   return ret;
134 }
135
136 int DynParaLoop::getNumberOfInputPorts() const
137 {
138   return ComposedNode::getNumberOfInputPorts()+1;
139 }
140
141 int DynParaLoop::getNumberOfOutputPorts() const
142 {
143   return ComposedNode::getNumberOfOutputPorts()+1;
144 }
145
146 std::list<OutputPort *> DynParaLoop::getSetOfOutputPort() const
147 {
148   list<OutputPort *> ret=ComposedNode::getSetOfOutputPort();
149   ret.push_back((OutputPort *)&_splittedPort);
150   return ret;
151 }
152
153 OutPort *DynParaLoop::getOutPort(const std::string& name) const throw(Exception)
154 {
155   if(name==NAME_OF_SPLITTED_SEQ_OUT)
156     return (OutPort *)&_splittedPort;
157   return ComposedNode::getOutPort(name);
158 }
159
160 InputPort *DynParaLoop::getInputPort(const std::string& name) const throw(Exception)
161 {
162   if(name==NAME_OF_NUMBER_OF_BRANCHES)
163     return (InputPort *)&_nbOfBranches;
164   return ComposedNode::getInputPort(name);
165 }
166
167 OutputPort *DynParaLoop::getOutputPort(const std::string& name) const throw(Exception)
168 {
169   if(name==NAME_OF_SPLITTED_SEQ_OUT)
170     return (OutputPort *)&_splittedPort;
171   return ComposedNode::getOutputPort(name);
172 }
173
174 bool DynParaLoop::isPlacementPredictableB4Run() const
175 {
176   return false;
177 }
178
179 Node *DynParaLoop::edRemoveNode()
180 {
181   if(!_node)
182     return 0;
183   ComposedNode::edRemoveChild(_node);
184   Node *ret=_node;
185   _node=0;
186   return ret;
187 }
188
189 Node *DynParaLoop::edRemoveInitNode()
190 {
191   if(!_initNode)
192     return 0;
193   ComposedNode::edRemoveChild(_initNode);
194   Node *ret=_initNode;
195   _initNode=0;
196   return ret;
197 }
198
199 void DynParaLoop::edRemoveChild(Node *node) throw(Exception)
200 {
201   ComposedNode::edRemoveChild(node);
202   if(node==_node)
203     _node=0;
204   if(node==_initNode)
205     _initNode=0;
206 }
207
208 std::set<Node *> DynParaLoop::edGetDirectDescendants() const
209 {
210   set<Node *> ret;
211   if(_node)
212     ret.insert(_node);
213   if(_initNode)
214     ret.insert(_initNode);
215   return ret;
216 }
217
218 std::list<InputPort *> DynParaLoop::getSetOfInputPort() const
219 {
220   list<InputPort *> ret=ComposedNode::getSetOfInputPort();
221   ret.push_back((InputPort *)&_nbOfBranches);
222   return ret;
223 }
224
225 unsigned DynParaLoop::getNumberOfBranchesCreatedDyn() const throw(Exception)
226 {
227   if(_execNodes.empty())
228     throw Exception("ForEachLoop::getNumberOfBranches : No branches created dynamically ! - ForEachLoop needs to run or to be runned to call getNumberOfBranches");
229   else
230     return _execNodes.size();
231 }
232
233 Node *DynParaLoop::getChildByShortName(const std::string& name) const throw(Exception)
234 {
235   if(_node)
236     if(name==_node->getName())
237       return _node;
238   if(_initNode)
239     if(name==_initNode->getName())
240       return  _initNode;
241   std::string what("node "); what+= name ; what+=" is not a child of DynParaLoop node "; what += getName();
242   throw Exception(what);
243 }
244
245 Node *DynParaLoop::getChildByNameExec(const std::string& name, unsigned id) const throw(Exception)
246 {
247   if(id>=getNumberOfBranchesCreatedDyn())
248     throw Exception("ForEachLoop::getChildByNameExec : invalid id - too large compared with dynamically created branches.");
249   if(_node)
250     if(name==_node->getName())
251       return _execNodes[id];
252   if(_initNode)
253     if(name==_initNode->getName())
254       return  _execInitNodes[id];
255   std::string what("node "); what+= name ; what+=" is not a child of DynParaLoop node "; what += getName();
256   throw Exception(what);
257 }
258
259 void DynParaLoop::cleanDynGraph()
260 {
261   for(vector<Node *>::iterator iter=_execNodes.begin();iter!=_execNodes.end();iter++)
262     delete *iter;
263   _execNodes.clear();
264   for(vector<Node *>::iterator iter2=_execInitNodes.begin();iter2!=_execInitNodes.end();iter2++)
265     delete *iter2;
266   _execNodes.clear();
267 }
268
269 /*!
270  * This method applies on newly cloned on exec nodes (_execNodes/_execInitNodes)
271  * the setting of input ports coming from outside of 'this'
272  */
273 void DynParaLoop::prepareInputsFromOutOfScope(int branchNb)
274 {
275   set< InPort * > portsToSetVals=getAllInPortsComingFromOutsideOfCurrentScope();
276   portsToSetVals.erase(&_nbOfBranches);//_nbOfBranches inport is not a candidate of dynamically duplicated inport.
277   for(set< InPort * >::iterator iter=portsToSetVals.begin();iter!=portsToSetVals.end();iter++)
278     {
279       InputPort *curPortCasted=(InputPort *) *iter;//Cast granted by ForEachLoop::buildDelegateOf(InPort)
280       void *val=curPortCasted->get();
281       InputPort *portToSet=getDynInputPortByAbsName(branchNb,getInPortName(*iter),true);
282       if(portToSet)//portToSet==0 in case of portToSet==_splitterNode._dataPortToDispatch of ForEach
283         {
284           portToSet->put((const void *)val);
285           portToSet->edNotifyReferencedBy(0);//This is to indicate that somewhere somebody deals with this inputport
286           //even if no direct physical link exists. This exclusively for _execNodes[branchNb]::init on the next turn of loop.
287         }
288     }
289 }
290
291 void DynParaLoop::putValueOnBranch(Any *val, unsigned branchId, bool first)
292 {
293   bool isDispatched = false;
294   set<InPort *> inPrtLkdWthSplttdPrt=_splittedPort.edSetInPort();
295   for(set<InPort *>::iterator iter=inPrtLkdWthSplttdPrt.begin();iter!=inPrtLkdWthSplttdPrt.end();iter++)
296     {
297       std::string portNameOnCurPrt=getPortName(*iter);
298       InputPort *portOnGivenBranch=getDynInputPortByAbsName(branchId,portNameOnCurPrt,first);//Cast granted because impossible to have cross protocol with _splittedPort
299       //see OptimizerLoop::buildDelegateOf
300       if(portOnGivenBranch)
301         {
302           if(first)
303             portOnGivenBranch->edNotifyReferencedBy(0);
304           InputPort *traducer=getRuntime()->adapt(portOnGivenBranch,
305                                                   Runtime::RUNTIME_ENGINE_INTERACTION_IMPL_NAME,_splittedPort.edGetType());
306           traducer->put((const void *)val);
307           isDispatched = true;
308           if(traducer!=portOnGivenBranch)
309             delete traducer;
310         }
311     }
312   if ( isDispatched )
313     {
314       Any *tmp=val->clone();
315       _splittedPort.setValue(tmp);
316       tmp->decrRef();
317     }
318 }
319
320 DynParaLoop::TypeOfNode DynParaLoop::getIdentityOfNotifyerNode(const Node *node, unsigned& id)
321 {
322   id=0;
323   for(vector<Node *>::iterator iter=_execNodes.begin();iter!=_execNodes.end();iter++,id++)
324     if(*iter==node)
325       return WORK_NODE;
326   id=0;
327   for(vector<Node *>::iterator iter2=_execInitNodes.begin();iter2!=_execInitNodes.end();iter2++,id++)
328     if(*iter2==node)
329       return INIT_NODE;
330 }
331
332 bool DynParaLoop::isMultiplicitySpecified(unsigned& value) const
333 {
334   if(_nbOfBranches.edIsManuallyInitialized())
335     if(_nbOfBranches.edGetNumberOfLinks()==0)
336       {
337         value=_nbOfBranches.getIntValue();
338         return true;
339       }
340   return false;
341 }
342
343 void DynParaLoop::forceMultiplicity(unsigned value)
344 {
345   _nbOfBranches.edRemoveAllLinksLinkedWithMe();
346   _nbOfBranches.edInit((int)value);
347 }
348
349 void DynParaLoop::buildDelegateOf(InPort * & port, OutPort *initialStart, const std::set<ComposedNode *>& pointsOfView)
350 {
351   string typeOfPortInstance=port->getNameOfTypeOfCurrentInstance();
352   if(typeOfPortInstance!=InputPort::NAME)
353     throw Exception("DynParaLoop::buildDelegateOf : A link with datastream end inside DynParaLoop this is not possible");
354 }
355
356 void DynParaLoop::buildDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, const std::set<ComposedNode *>& pointsOfView)
357 {
358   if(_initNode)
359     if(isInMyDescendance(port.first->getNode())==_initNode)
360       throw Exception("DynParaLoop::buildDelegateOf : uncorrect ForEach link : a link starting from init node can't leave the scope of ForEachLoop node it belongs to.");
361   if(port.first==&_splittedPort)
362     throw Exception("DynParaLoop::buildDelegateOf : uncorrect ForEach link : splitted port must be link within the scope of ForEachLoop node it belongs to.");
363 }
364
365 /*!
366  * \note : For a given name 'name' of port in absolute form from this, returns the corresponding InputPort instance of the
367  *         port for the branch # 'branchNb'. The port can be part of _node or _initNode if it exists (if 'initNodeAdmitted' is true).
368  *         \b WARNING : no check performed on  'branchNb' value to see if it is compatible with size of '_execNodes'.
369  *         This method is called to dispatch value on each InputPort linked to this->._splitterNode._splittedPort
370  */
371 InputPort *DynParaLoop::getDynInputPortByAbsName(int branchNb, const std::string& name, bool initNodeAdmitted)
372 {
373   string portName, nodeName;
374   splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,true);
375   Node *staticChild = getChildByName(nodeName);
376   Node *desc=isInMyDescendance(staticChild);
377   if(desc==_node)
378     {
379       splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,false);
380       return _execNodes[branchNb]->getInputPort(portName);
381     }
382   else if(desc==_initNode)
383     if(initNodeAdmitted)
384       {
385         splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,false);
386         return _execInitNodes[branchNb]->getInputPort(portName);
387       }
388   return 0;
389 }