1 /***************************************************************************
2                           basic_op_sub.cpp  -  GDL sub (-) operators
3                              -------------------
4     begin                : July 22 2002
5     copyright            : (C) 2002 by Marc Schellens
6     email                : m_schellens@users.sf.net
7 ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 
18 
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22 
23 #ifdef _OPENMP
24 #include <omp.h>
25 #endif
26 
27 //#include "datatypes.hpp" // for friend declaration
28 #include "nullgdl.hpp"
29 #include "dinterpreter.hpp"
30 
31 // needed with gcc-3.3.2
32 #include <cassert>
33 
34 // Sub
35 // substraction: left=left-right
36 template<class Sp>
Sub(BaseGDL * r)37 BaseGDL* Data_<Sp>::Sub( BaseGDL* r)
38 {
39   Data_* right=static_cast<Data_*>(r);
40 
41   ULong rEl=right->N_Elements();
42   ULong nEl=N_Elements();
43   assert( rEl);
44   assert( nEl);
45   //  if( !rEl || !nEl) throw GDLException("Variable is undefined.");
46   if( nEl == 1)
47     {
48       (*this)[0] -= (*right)[0];
49       return this;
50     }
51 #ifdef USE_EIGEN
52 
53   Eigen::Map<Eigen::Array<Ty,Eigen::Dynamic,1> ,Eigen::Aligned> mThis(&(*this)[0], nEl);
54   Eigen::Map<Eigen::Array<Ty,Eigen::Dynamic,1> ,Eigen::Aligned> mRight(&(*right)[0], nEl);
55   mThis -= mRight;
56   return this;
57 #else
58 
59   if( nEl == rEl)
60     dd -= right->dd;
61   else
62     {
63       TRACEOMP( __FILE__, __LINE__)
64 #pragma omp parallel if (nEl >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl))
65 	{
66 #pragma omp for
67 	  for( OMPInt i=0; i < nEl; ++i)
68 	    (*this)[i] -= (*right)[i];
69 	}}  //C delete right;
70   return this;
71 #endif
72 
73 }
74 // inverse substraction: left=right-left
75 template<class Sp>
SubInv(BaseGDL * r)76 BaseGDL* Data_<Sp>::SubInv( BaseGDL* r)
77 {
78   Data_* right=static_cast<Data_*>(r);
79 
80   ULong rEl=right->N_Elements();
81   ULong nEl=N_Elements();
82   assert( rEl);
83   assert( nEl);
84   //  if( !rEl || !nEl) throw GDLException("Variable is undefined.");
85   /*  if( nEl == rEl)
86       dd = right->dd - dd;
87       else*/
88   if( nEl == 1)
89     {
90       (*this)[0] = (*right)[0] - (*this)[0];
91       return this;
92     }
93 #ifdef USE_EIGEN
94 
95   Eigen::Map<Eigen::Array<Ty,Eigen::Dynamic,1> ,Eigen::Aligned> mThis(&(*this)[0], nEl);
96   Eigen::Map<Eigen::Array<Ty,Eigen::Dynamic,1> ,Eigen::Aligned> mRight(&(*right)[0], nEl);
97   mThis = mRight - mThis;
98   return this;
99 #else
100   TRACEOMP( __FILE__, __LINE__)
101 #pragma omp parallel if (nEl >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl))
102     {
103 #pragma omp for
104       for( OMPInt i=0; i < nEl; ++i)
105 	(*this)[i] = (*right)[i] - (*this)[i];
106     }  //C delete right;
107   return this;
108 #endif
109 
110 }
111 // invalid types
112 template<>
Sub(BaseGDL * r)113 BaseGDL* Data_<SpDString>::Sub( BaseGDL* r)
114 {
115   throw GDLException("Cannot apply operation to datatype STRING.",true,false);
116   return this;
117 }
118 template<>
SubInv(BaseGDL * r)119 BaseGDL* Data_<SpDString>::SubInv( BaseGDL* r)
120 {
121   throw GDLException("Cannot apply operation to datatype STRING.",true,false);
122   return this;
123 }
124 template<>
Sub(BaseGDL * r)125 BaseGDL* Data_<SpDPtr>::Sub( BaseGDL* r)
126 {
127   throw GDLException("Cannot apply operation to datatype PTR.",true,false);
128   return this;
129 }
130 template<>
SubInv(BaseGDL * r)131 BaseGDL* Data_<SpDPtr>::SubInv( BaseGDL* r)
132 {
133   throw GDLException("Cannot apply operation to datatype PTR.",true,false);
134   return this;
135 }
136 template<>
Sub(BaseGDL * r)137 BaseGDL* Data_<SpDObj>::Sub( BaseGDL* r)
138 {
139   // overload here
140   Data_* self;
141   DSubUD* plusOverload;
142 
143   ProgNodeP callingNode = interpreter->GetRetTree();
144 
145   if( !Scalar())
146   {
147     if( r->Type() == GDL_OBJ && r->Scalar())
148     {
149       self = static_cast<Data_*>( r);
150       plusOverload = static_cast<DSubUD*>(GDLInterpreter::GetObjHeapOperator( (*self)[0], OOMinus));
151       if( plusOverload == NULL)
152       {
153 	throw GDLException( callingNode, "Cannot apply not overloaded operator to datatype OBJECT.", true, false);
154       }
155     }
156     else
157       {
158 	throw GDLException( callingNode, "Cannot apply operation to non-scalar datatype OBJECT.", true, false);
159       }
160   }
161   else
162   {
163     // Scalar()
164     self = static_cast<Data_*>( this);
165     plusOverload = static_cast<DSubUD*>(GDLInterpreter::GetObjHeapOperator( (*self)[0], OOMinus));
166     if( plusOverload == NULL)
167     {
168       if( r->Type() == GDL_OBJ && r->Scalar())
169       {
170 	self = static_cast<Data_*>( r);
171 	plusOverload = static_cast<DSubUD*>(GDLInterpreter::GetObjHeapOperator( (*self)[0], OOMinus));
172 	if( plusOverload == NULL)
173 	{
174 	  throw GDLException(callingNode,"Cannot apply not overloaded operator to datatype OBJECT.",true, false);
175 	}
176       }
177       else
178       {
179 	throw GDLException( callingNode, "Cannot apply not overloaded operator to datatype OBJECT.", true, false);
180       }
181     }
182   }
183 
184   assert( self->Scalar());
185   assert( plusOverload != NULL);
186 
187   // hidden SELF is counted as well
188   int nParSub = plusOverload->NPar();
189   assert( nParSub >= 1); // SELF
190   if( nParSub < 3) // (SELF), LEFT, RIGHT
191   {
192     throw GDLException( callingNode, plusOverload->ObjectName() +
193 		    ": Incorrect number of arguments.",
194 		    false, false);
195   }
196   EnvUDT* newEnv;
197   Guard<BaseGDL> selfGuard;
198   BaseGDL* thisP;
199   // Dup() here is not optimal
200   // avoid at least for internal overload routines (which do/must not change SELF or r)
201   bool internalDSubUD = plusOverload->GetTree()->IsWrappedNode();
202   if( internalDSubUD)
203   {
204     thisP = this;
205     newEnv= new EnvUDT( callingNode, plusOverload, &self);
206     newEnv->SetNextParUnchecked( &thisP); // LEFT  parameter, as reference to prevent cleanup in newEnv
207     newEnv->SetNextParUnchecked( &r); // RVALUE  parameter, as reference to prevent cleanup in newEnv
208   }
209   else
210   {
211     self = self->Dup();
212     selfGuard.Init( self);
213     newEnv= new EnvUDT( callingNode, plusOverload, &self);
214     newEnv->SetNextParUnchecked( this->Dup()); // LEFT  parameter, as value
215     newEnv->SetNextParUnchecked( r->Dup()); // RIGHT parameter, as value
216   }
217 
218 
219   // better than auto_ptr: auto_ptr wouldn't remove newEnv from the stack
220   StackGuard<EnvStackT> guard(interpreter->CallStack());
221 
222   interpreter->CallStack().push_back( newEnv);
223 
224   // make the call
225   BaseGDL* res=interpreter->call_fun(static_cast<DSubUD*>(newEnv->GetPro())->GetTree());
226 
227   if( !internalDSubUD && self != selfGuard.Get())
228   {
229     // always put out warning first, in case of a later crash
230     Warning( "WARNING: " + plusOverload->ObjectName() +
231 	  ": Assignment to SELF detected (GDL session still ok).");
232     // assignment to SELF -> self was deleted and points to new variable
233     // which it owns
234     selfGuard.Release();
235     if( static_cast<BaseGDL*>(self) != NullGDL::GetSingleInstance())
236       selfGuard.Reset(self);
237   }
238   return res;
239 }
240 template<>
SubInv(BaseGDL * r)241 BaseGDL* Data_<SpDObj>::SubInv( BaseGDL* r)
242 {
243   if( r->Type() == GDL_OBJ && r->Scalar())
244   {
245     return r->Sub( this); // for right order of parameters
246   }
247 
248   // overload here
249   Data_* self;
250   DSubUD* plusOverload;
251 
252   ProgNodeP callingNode = interpreter->GetRetTree();
253 
254   if( !Scalar())
255   {
256     throw GDLException( callingNode, "Cannot apply operation to non-scalar datatype OBJECT.", true, false);
257   }
258   else
259   {
260     // Scalar()
261     self = static_cast<Data_*>( this);
262     plusOverload = static_cast<DSubUD*>(GDLInterpreter::GetObjHeapOperator( (*self)[0], OOMinus));
263     if( plusOverload == NULL)
264     {
265 	throw GDLException( callingNode, "Cannot apply not overloaded operator to datatype OBJECT.", true, false);
266     }
267   }
268 
269   assert( self->Scalar());
270   assert( plusOverload != NULL);
271 
272   // hidden SELF is counted as well
273   int nParSub = plusOverload->NPar();
274   assert( nParSub >= 1); // SELF
275   if( nParSub < 3) // (SELF), LEFT, RIGHT
276   {
277     throw GDLException( callingNode, plusOverload->ObjectName() +
278 		    ": Incorrect number of arguments.",
279 		    false, false);
280   }
281   EnvUDT* newEnv;
282   Guard<BaseGDL> selfGuard;
283   BaseGDL* thisP;
284   // Dup() here is not optimal
285   // avoid at least for internal overload routines (which do/must not change SELF or r)
286   bool internalDSubUD = plusOverload->GetTree()->IsWrappedNode();
287   if( internalDSubUD)
288   {
289     thisP = this;
290     newEnv= new EnvUDT( callingNode, plusOverload, &self);
291     // order different to Add
292     newEnv->SetNextParUnchecked( &r); // RVALUE  parameter, as reference to prevent cleanup in newEnv
293     newEnv->SetNextParUnchecked( &thisP); // LEFT  parameter, as reference to prevent cleanup in newEnv
294   }
295   else
296   {
297     self = self->Dup();
298     selfGuard.Init( self);
299     newEnv= new EnvUDT( callingNode, plusOverload, &self);
300     // order different to Add
301     newEnv->SetNextParUnchecked( r->Dup()); // RIGHT parameter, as value
302     newEnv->SetNextParUnchecked( this->Dup()); // LEFT  parameter, as value
303   }
304 
305 
306   // better than auto_ptr: auto_ptr wouldn't remove newEnv from the stack
307   StackGuard<EnvStackT> guard(interpreter->CallStack());
308 
309   interpreter->CallStack().push_back( newEnv);
310 
311   // make the call
312   BaseGDL* res=interpreter->call_fun(static_cast<DSubUD*>(newEnv->GetPro())->GetTree());
313 
314   if( !internalDSubUD && self != selfGuard.Get())
315   {
316     // always put out warning first, in case of a later crash
317     Warning( "WARNING: " + plusOverload->ObjectName() +
318 	  ": Assignment to SELF detected (GDL session still ok).");
319     // assignment to SELF -> self was deleted and points to new variable
320     // which it owns
321     selfGuard.Release();
322     if( static_cast<BaseGDL*>(self) != NullGDL::GetSingleInstance())
323       selfGuard.Reset(self);
324   }
325   return res;
326 }
327 template<class Sp>
SubS(BaseGDL * r)328 Data_<Sp>* Data_<Sp>::SubS( BaseGDL* r)
329 {
330   Data_* right=static_cast<Data_*>(r);
331 
332   ULong nEl=N_Elements();
333   assert( nEl);
334   if( nEl == 1)
335     {
336       (*this)[0] -= (*right)[0];
337       return this;
338     }
339 
340   Ty s = (*right)[0];
341   // right->Scalar(s);
342   //  dd -= s;
343 #ifdef USE_EIGEN
344 
345         Eigen::Map<Eigen::Array<Ty,Eigen::Dynamic,1> ,Eigen::Aligned> mThis(&(*this)[0], nEl);
346 	mThis -= s;
347 	return this;
348 #else
349   TRACEOMP( __FILE__, __LINE__)
350 #pragma omp parallel if (nEl >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl))
351     {
352 #pragma omp for
353       for( OMPInt i=0; i < nEl; ++i)
354 	(*this)[i] -= s;
355     }  //C delete right;
356   return this;
357 #endif
358 
359 }
360 // inverse substraction: left=right-left
361 template<class Sp>
SubInvS(BaseGDL * r)362 Data_<Sp>* Data_<Sp>::SubInvS( BaseGDL* r)
363 {
364   Data_* right=static_cast<Data_*>(r);
365 
366   ULong nEl=N_Elements();
367   assert( nEl);
368 
369   if( nEl == 1)
370     {
371       (*this)[0] = (*right)[0] - (*this)[0];
372       return this;
373     }
374 
375   Ty s = (*right)[0];
376   // right->Scalar(s);
377   //  dd = s - dd;
378 #ifdef USE_EIGEN
379 
380         Eigen::Map<Eigen::Array<Ty,Eigen::Dynamic,1> ,Eigen::Aligned> mThis(&(*this)[0], nEl);
381 	mThis = s - mThis;
382 	return this;
383 #else
384   TRACEOMP( __FILE__, __LINE__)
385 #pragma omp parallel if (nEl >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl))
386     {
387 #pragma omp for
388       for( OMPInt i=0; i < nEl; ++i)
389 	(*this)[i] = s - (*this)[i];
390     }  //C delete right;
391   return this;
392 #endif
393 
394 }
395 // invalid types
396 template<>
SubS(BaseGDL * r)397 Data_<SpDString>* Data_<SpDString>::SubS( BaseGDL* r)
398 {
399   throw GDLException("Cannot apply operation to datatype STRING.",true,false);
400   return this;
401 }
402 template<>
SubInvS(BaseGDL * r)403 Data_<SpDString>* Data_<SpDString>::SubInvS( BaseGDL* r)
404 {
405   throw GDLException("Cannot apply operation to datatype STRING.",true,false);
406   return this;
407 }
408 template<>
SubS(BaseGDL * r)409 Data_<SpDPtr>* Data_<SpDPtr>::SubS( BaseGDL* r)
410 {
411   throw GDLException("Cannot apply operation to datatype PTR.",true,false);
412   return this;
413 }
414 template<>
SubInvS(BaseGDL * r)415 Data_<SpDPtr>* Data_<SpDPtr>::SubInvS( BaseGDL* r)
416 {
417   throw GDLException("Cannot apply operation to datatype PTR.",true,false);
418   return this;
419 }
420 template<>
SubS(BaseGDL * r)421 Data_<SpDObj>* Data_<SpDObj>::SubS( BaseGDL* r)
422 {
423   throw GDLException("Cannot apply operation to datatype OBJECT.",true,false);
424   return this;
425 }
426 template<>
SubInvS(BaseGDL * r)427 Data_<SpDObj>* Data_<SpDObj>::SubInvS( BaseGDL* r)
428 {
429   throw GDLException("Cannot apply operation to datatype OBJECT.",true,false);
430   return this;
431 }
432 
433 #include "instantiate_templates.hpp"
434