cumprod(%i+%s) crashed Scilab.
[scilab.git] / scilab / modules / elementary_functions / sci_gateway / cpp / sci_cumprod.cpp
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2012 - DIGITEO - Cedric DELAMARRE
4  *
5  * This file must be used under the terms of the CeCILL.
6  * This source file is licensed as described in the file COPYING, which
7  * you should have received as part of this distribution.  The terms
8  * are also available at
9  * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
10  *
11  */
12 /*--------------------------------------------------------------------------*/
13 #include "elem_func_gw.hxx"
14 #include "function.hxx"
15 #include "double.hxx"
16 #include "string.hxx"
17 #include "overload.hxx"
18 #include "execvisitor.hxx"
19 #include "cumprod.hxx"
20 #include "int.hxx"
21
22 extern "C"
23 {
24 #include "Scierror.h"
25 #include "localization.h"
26 #include "basic_functions.h"
27 }
28
29 /*
30 clear a; nb = 2500; a = rand(nb, nb) * 50; tic(); cumprod(a); toc
31 clear a; nb = 2500; a = rand(nb, nb) * 50; a = a + a *%i; tic(); cumprod(a); toc
32 */
33 /*--------------------------------------------------------------------------*/
34 types::Function::ReturnValue sci_cumprod(types::typed_list &in, int _iRetCount, types::typed_list &out)
35 {
36     types::Double* pDblIn       = NULL;
37     types::Double* pDblOut      = NULL;
38     types::Polynom* pPolyIn     = NULL;
39     types::Polynom* pPolyOut    = NULL;
40
41     int iOrientation    = 0;
42     int iOuttype        = 1; // 1 = native | 2 = double (type of output value)
43
44     if (in.size() < 1 || in.size() > 3)
45     {
46         Scierror(77, _("%s: Wrong number of input argument(s): %d to %d expected.\n"), "cumprod", 1, 3);
47         return types::Function::Error;
48     }
49
50     if (_iRetCount > 1)
51     {
52         Scierror(78, _("%s: Wrong number of output argument(s): %d expected.\n"), "cumprod", 1);
53         return types::Function::Error;
54     }
55
56     bool isCloned = true;
57     /***** get data *****/
58     switch (in[0]->getType())
59     {
60         case InternalType::ScilabDouble :
61             pDblIn = in[0]->getAs<types::Double>();
62             isCloned = false;
63             break;
64         case InternalType::ScilabBool:
65             pDblIn = getAsDouble(in[0]->getAs<types::Bool>());
66             iOuttype = 2;
67             break;
68         case InternalType::ScilabPolynom :
69             pPolyIn = in[0]->getAs<types::Polynom>();
70             isCloned = false;
71             break;
72         case InternalType::ScilabInt8:
73             pDblIn = getAsDouble(in[0]->getAs<types::Int8>());
74             break;
75         case InternalType::ScilabInt16:
76             pDblIn = getAsDouble(in[0]->getAs<types::Int16>());
77             break;
78         case InternalType::ScilabInt32:
79             pDblIn = getAsDouble(in[0]->getAs<types::Int32>());
80             break;
81         case InternalType::ScilabInt64:
82             pDblIn = getAsDouble(in[0]->getAs<types::Int64>());
83             break;
84         case InternalType::ScilabUInt8:
85             pDblIn = getAsDouble(in[0]->getAs<types::UInt8>());
86             break;
87         case InternalType::ScilabUInt16:
88             pDblIn = getAsDouble(in[0]->getAs<types::UInt16>());
89             break;
90         case InternalType::ScilabUInt32:
91             pDblIn = getAsDouble(in[0]->getAs<types::UInt32>());
92             break;
93         case InternalType::ScilabUInt64:
94             pDblIn = getAsDouble(in[0]->getAs<types::UInt64>());
95             break;
96         default :
97             ast::ExecVisitor exec;
98             std::wstring wstFuncName = L"%" + in[0]->getShortTypeStr() + L"_cumprod";
99             return Overload::call(wstFuncName, in, _iRetCount, out, &exec);
100     }
101
102     if (in.size() >= 2)
103     {
104         if (in[1]->isDouble())
105         {
106             types::Double* pDbl = in[1]->getAs<types::Double>();
107
108             if (pDbl->isScalar() == false)
109             {
110                 if (isCloned)
111                 {
112                     pDblIn->killMe();
113                 }
114
115                 Scierror(999, _("%s: Wrong value for input argument #%d: A positive scalar expected.\n"), "cumprod", 2);
116                 return types::Function::Error;
117             }
118
119             iOrientation = static_cast<int>(pDbl->get(0));
120
121             if (iOrientation <= 0)
122             {
123                 if (isCloned)
124                 {
125                     pDblIn->killMe();
126                 }
127
128                 Scierror(999, _("%s: Wrong value for input argument #%d: A positive scalar expected.\n"), "cumprod", 2);
129                 return types::Function::Error;
130             }
131         }
132         else if (in[1]->isString())
133         {
134             types::String* pStr = in[1]->getAs<types::String>();
135
136             if (pStr->isScalar() == false)
137             {
138                 if (isCloned)
139                 {
140                     pDblIn->killMe();
141                 }
142
143                 Scierror(999, _("%s: Wrong size for input argument #%d: A scalar string expected.\n"), "cumprod", 2);
144                 return types::Function::Error;
145             }
146
147             wchar_t* wcsString = pStr->get(0);
148
149             if (wcscmp(wcsString, L"*") == 0)
150             {
151                 iOrientation = 0;
152             }
153             else if (wcscmp(wcsString, L"r") == 0)
154             {
155                 iOrientation = 1;
156             }
157             else if (wcscmp(wcsString, L"c") == 0)
158             {
159                 iOrientation = 2;
160             }
161             else if (wcscmp(wcsString, L"m") == 0)
162             {
163                 int iDims = 0;
164                 int* piDimsArray = NULL;
165
166                 if (pDblIn)
167                 {
168                     iDims = pDblIn->getDims();
169                     piDimsArray = pDblIn->getDimsArray();
170                 }
171                 else
172                 {
173                     iDims = pPolyIn->getDims();
174                     piDimsArray = pPolyIn->getDimsArray();
175                 }
176
177                 // old function was "mtlsel"
178                 for (int i = 0; i < iDims; i++)
179                 {
180                     if (piDimsArray[i] > 1)
181                     {
182                         iOrientation = i + 1;
183                         break;
184                     }
185                 }
186             }
187             else if ((wcscmp(wcsString, L"native") == 0) && (in.size() == 2))
188             {
189                 iOuttype = 1;
190             }
191             else if ((wcscmp(wcsString, L"double") == 0) && (in.size() == 2))
192             {
193                 iOuttype = 2;
194             }
195             else
196             {
197                 const char* pstrExpected = NULL;
198                 if (in.size() == 2)
199                 {
200                     pstrExpected = "\"*\",\"r\",\"c\",\"m\",\"native\",\"double\"";
201                 }
202                 else
203                 {
204                     pstrExpected = "\"*\",\"r\",\"c\",\"m\"";
205                 }
206
207                 if (isCloned)
208                 {
209                     pDblIn->killMe();
210                 }
211
212                 Scierror(999, _("%s: Wrong value for input argument #%d: Must be in the set {%s}.\n"), "cumprod", 2, pstrExpected);
213                 return types::Function::Error;
214             }
215         }
216         else
217         {
218             if (isCloned)
219             {
220                 pDblIn->killMe();
221             }
222
223             Scierror(999, _("%s: Wrong type for input argument #%d: A real matrix or a string expected.\n"), "cumprod", 2);
224             return types::Function::Error;
225         }
226     }
227
228     if (in.size() == 3)
229     {
230         if (in[2]->isString() == false)
231         {
232             if (isCloned)
233             {
234                 pDblIn->killMe();
235             }
236
237             Scierror(999, _("%s: Wrong type for input argument #%d: A string expected.\n"), "cumprod", 3);
238             return types::Function::Error;
239         }
240
241         types::String* pStr = in[2]->getAs<types::String>();
242
243         if (pStr->isScalar() == false)
244         {
245             if (isCloned)
246             {
247                 pDblIn->killMe();
248             }
249
250             Scierror(999, _("%s: Wrong size for input argument #%d: A scalar string expected.\n"), "cumprod", 3);
251             return types::Function::Error;
252         }
253
254         wchar_t* wcsString = pStr->get(0);
255
256         if (wcscmp(wcsString, L"native") == 0)
257         {
258             iOuttype = 1;
259         }
260         else if (wcscmp(wcsString, L"double") == 0)
261         {
262             iOuttype = 2;
263         }
264         else
265         {
266             if (isCloned)
267             {
268                 pDblIn->killMe();
269             }
270
271             Scierror(999, _("%s: Wrong value for input argument #%d: %s or %s expected.\n"), "cumprod", 3, "\"native\"", "\"double\"");
272             return types::Function::Error;
273         }
274     }
275
276     /***** perform operation *****/
277     if (pDblIn)
278     {
279         if (iOrientation > pDblIn->getDims())
280         {
281             if (in[0]->isDouble())
282             {
283                 pDblOut = pDblIn->clone()->getAs<types::Double>();
284             }
285             else
286             {
287                 pDblOut = pDblIn;
288             }
289
290             if (in[0]->isBool() == false)
291             {
292                 iOuttype = 2;
293             }
294         }
295         else
296         {
297             pDblOut = new types::Double(pDblIn->getDims(), pDblIn->getDimsArray(), pDblIn->isComplex());
298             cumprod(pDblIn, iOrientation, pDblOut);
299             if (isCloned)
300             {
301                 delete pDblIn;
302                 pDblIn = NULL;
303             }
304         }
305     }
306     else if (pPolyIn)
307     {
308         iOuttype = 1;
309         if (iOrientation > pPolyIn->getDims())
310         {
311             pPolyOut = pPolyIn->clone()->getAs<types::Polynom>();
312         }
313         else
314         {
315             pPolyOut = new types::Polynom(pPolyIn->getVariableName(), pPolyIn->getDims(), pPolyIn->getDimsArray());
316             cumprod(pPolyIn, iOrientation, pPolyOut);
317         }
318     }
319
320     /***** set result *****/
321     if ((iOuttype == 1) && (in[0]->isDouble() == false))
322     {
323         switch (in[0]->getType())
324         {
325             case InternalType::ScilabBool:
326             {
327                 types::Bool* pB = new types::Bool(pDblOut->getDims(), pDblOut->getDimsArray());
328                 int* p = pB->get();
329                 double* pd = pDblOut->get();
330                 int size = pB->getSize();
331                 for (int i = 0; i < size; ++i)
332                 {
333                     p[i] = pd[i] != 0 ? 1 : 0;
334                 }
335                 out.push_back(pB);
336                 break;
337             }
338             case InternalType::ScilabPolynom:
339             {
340                 out.push_back(pPolyOut);
341                 break;
342             }
343             case InternalType::ScilabInt8:
344             {
345                 out.push_back(toInt<types::Int8>(pDblOut));
346                 break;
347             }
348             case InternalType::ScilabInt16:
349             {
350                 out.push_back(toInt<types::Int16>(pDblOut));
351                 break;
352             }
353             case InternalType::ScilabInt32:
354             {
355                 out.push_back(toInt<types::Int32>(pDblOut));
356                 break;
357             }
358             case InternalType::ScilabInt64:
359             {
360                 out.push_back(toInt<types::Int64>(pDblOut));
361                 break;
362             }
363             case InternalType::ScilabUInt8:
364             {
365                 out.push_back(toInt<types::UInt8>(pDblOut));
366                 break;
367             }
368             case InternalType::ScilabUInt16:
369             {
370                 out.push_back(toInt<types::UInt16>(pDblOut));
371                 break;
372             }
373             case InternalType::ScilabUInt32:
374             {
375                 out.push_back(toInt<types::UInt32>(pDblOut));
376                 break;
377             }
378             case InternalType::ScilabUInt64:
379             {
380                 out.push_back(toInt<types::UInt64>(pDblOut));
381                 break;
382             }
383         }
384
385         if (pDblOut)
386         {
387             delete pDblOut;
388         }
389     }
390     else
391     {
392         out.push_back(pDblOut);
393     }
394
395     return types::Function::OK;
396 }
397 /*--------------------------------------------------------------------------*/