* Bug 16365 fixed: median(m,'r'|'c') was wrong after 5dc990
[scilab.git] / scilab / modules / scicos / src / cpp / vec2var.cpp
1 /*
2 *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 *  Copyright (C) 2015 - Scilab Enterprises - Paul Bignier
4 *
5  * Copyright (C) 2012 - 2016 - Scilab Enterprises
6  *
7  * This file is hereby licensed under the terms of the GNU GPL v2.0,
8  * pursuant to article 5.3.4 of the CeCILL v.2.1.
9  * This file was originally licensed under the terms of the CeCILL v2.1,
10  * and continues to be available under such terms.
11  * For more information, see the COPYING file which you should have received
12  * along with this program.
13 *
14 */
15
16 #include <vector>
17 #include <string>
18 #include <cwchar>
19 #include <cstring>
20 #include <cassert>
21
22 #include "vec2var.hxx"
23
24 #include "types.hxx"
25 #include "internal.hxx"
26 #include "double.hxx"
27 #include "int.hxx"
28 #include "bool.hxx"
29 #include "string.hxx"
30 #include "list.hxx"
31 #include "tlist.hxx"
32 #include "mlist.hxx"
33 //#include "struct.hxx"
34
35 extern "C"
36 {
37 #include "api_scilab.h"
38
39 #include "Scierror.h"
40 #include "localization.h"
41 }
42
43 static const std::string vec2varName = "vec2var";
44
45 /**
46  * Calculate the length increment depending on the type of the Scilab type
47  *
48  * @param T Scilab type
49  * @param v the instance on the Scilab type
50  * @return the number of double used to store the data
51  */
52 template<typename T>
53 size_t required_length(T* v)
54 {
55     const size_t sizeof_double = sizeof(double);
56     if (sizeof(typename T::type) >= sizeof_double)
57     {
58         return v->getSize() * sizeof(typename T::type) / sizeof_double;
59     }
60     else
61     {
62         // Increase the size to contain enough space, manage the size_t rounding issue
63         return (v->getSize() * sizeof(typename T::type) + (sizeof_double - 1)) / sizeof_double;
64     }
65 }
66
67 template<typename T>
68 int decode(const double* const tab, const int tabSize, const int iDims, const int offset, T* &res)
69 {
70     if (iDims < 1)
71     {
72         Scierror(999, _("%s: Wrong value for element #%d of input argument #%d: Integer matrix cannot be empty.\n"), vec2varName.c_str(), offset + 3, 1);
73         return -1;
74     }
75
76     int  iElements = 1;
77     int* pDims = new int[iDims];
78     for (int i = 0; i < iDims; ++i)
79     {
80         pDims[i] = static_cast<int>(tab[i]);
81         iElements *= pDims[i];
82     }
83
84     res = new T(iDims, pDims);
85     delete[] pDims;
86
87     const int numberOfDoubleNeeded = static_cast<int>(required_length(res));
88     if (tabSize < numberOfDoubleNeeded + 2 + iDims)
89     {
90         // Error case: the input doesn't have enough elements
91         Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, numberOfDoubleNeeded + 2 + iDims + offset, 1);
92         delete res;
93         return -1;
94     }
95
96     //Use a buffer to prevent copying only parts of integers
97     double* buffer = new double[numberOfDoubleNeeded];
98     memcpy(buffer, tab + iDims, numberOfDoubleNeeded * sizeof(double));
99     memcpy(res->get(), buffer, iElements * sizeof(typename T::type));
100     delete[] buffer;
101
102     assert(2 + iDims + numberOfDoubleNeeded > 0);
103     return 2 + iDims + numberOfDoubleNeeded;
104 }
105
106 template<>
107 int decode(const double* const tab, const int tabSize, const int iDims, const int offset, types::Double* &res)
108 {
109     int  iElements = 1;
110     int* pDims = new int[iDims];
111     for (int i = 0; i < iDims; ++i)
112     {
113         pDims[i] = static_cast<int>(tab[i]);
114         iElements *= pDims[i];
115     }
116     if (tabSize < iElements + 3 + iDims)
117     {
118         // Error case: the input doesn't have enough elements
119         delete[] pDims;
120         Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, iElements + 3 + iDims + offset, 1);
121         return -1;
122     }
123     if (iElements == 0)
124     {
125         res = types::Double::Empty();
126         delete[] pDims;
127         return 5;
128     }
129     const bool isComplex = (tab[iDims] == 1);
130
131     res = new types::Double(iDims, pDims, isComplex);
132     delete[] pDims;
133
134     res->set(tab + iDims + 1);
135     if (isComplex == true)
136     {
137         res->setImg(tab + iDims + 1 + iElements);
138         iElements *= 2;
139     }
140
141     return 2 + iDims + 1 + iElements;
142 }
143
144 template<>
145 int decode(const double* const tab, const int tabSize, const int iDims, const int offset, types::String* &res)
146 {
147     if (iDims < 1)
148     {
149         Scierror(999, _("%s: Wrong value for element #%d of input argument #%d: String matrix cannot be empty.\n"), vec2varName.c_str(), offset + 2, 1);
150         return -1;
151     }
152
153     int  iElements = 1;
154     int* pDims = new int[iDims];
155     for (int i = 0; i < iDims; ++i)
156     {
157         pDims[i] = static_cast<int>(tab[i]);
158         iElements *= pDims[i];
159     }
160     if (tabSize < iElements * 2 + 2 + iDims)
161     {
162         // Error case: the input doesn't have enough elements
163         delete[] pDims;
164         Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, iElements * 2 + 2 + iDims + offset, 1);
165         return -1;
166     }
167
168     res = new types::String(iDims, pDims);
169     delete[] pDims;
170
171     // Retrieving the first value pointer
172     double* strData = const_cast<double*>(tab + iDims + iElements);
173
174     res->set(0, (char*) & (*strData));
175     strData += static_cast<size_t>(tab[iDims]);
176     int stringOffset = static_cast<int>(tab[iDims]);
177     for (int i = 1; i < iElements; i++)
178     {
179         res->set(i, (char*) & (*strData));
180
181         // Increment the value pointer by the number of elements
182         const size_t numberOfElem = static_cast<size_t>(tab[iDims + i]) - static_cast<size_t>(tab[iDims + i - 1]);
183         strData += numberOfElem;
184         stringOffset += static_cast<int>(numberOfElem);
185     }
186
187     return 2 + iDims + iElements + stringOffset;
188 }
189
190 static bool readElement(const double* const input, const int iType, const int iDims, const int inputRows, int &offset, types::InternalType* &res)
191 {
192     switch (iType)
193     {
194         case sci_matrix  :
195         {
196             if (inputRows < 5)
197             {
198                 Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 5, 1);
199                 return false;
200             }
201
202             types::Double* pDouble = nullptr;
203             const int resSize = decode<types::Double>(input + 2, inputRows, iDims, offset, pDouble);
204             if (resSize < 0)
205             {
206                 return false;
207             }
208             res = pDouble;
209             offset += resSize;
210             break;
211         }
212
213         case sci_ints    :
214         {
215             switch (static_cast<int>(input[1]))
216             {
217                 case sci_int8   :
218                 {
219                     if (inputRows < 5)
220                     {
221                         Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 5, 1);
222                         return false;
223                     }
224
225                     types::Int8* pInt8 = nullptr;
226                     const int resSize = decode<types::Int8>(input + 3, inputRows, iDims, offset, pInt8);
227                     if (resSize < 0)
228                     {
229                         return false;
230                     }
231                     res = pInt8;
232                     offset += 1 + resSize;
233                     break;
234                 }
235                 case sci_uint8  :
236                 {
237                     if (inputRows < 5)
238                     {
239                         Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 5, 1);
240                         return false;
241                     }
242
243                     types::UInt8* pUInt8 = nullptr;
244                     const int resSize = decode<types::UInt8>(input + 3, inputRows, iDims, offset, pUInt8);
245                     if (resSize < 0)
246                     {
247                         return false;
248                     }
249                     res = pUInt8;
250                     offset += 1 + resSize;
251                     break;
252                 }
253                 case sci_int16  :
254                 {
255                     if (inputRows < 5)
256                     {
257                         Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 5, 1);
258                         return false;
259                     }
260
261                     types::Int16* pInt16 = nullptr;
262                     const int resSize = decode<types::Int16>(input + 3, inputRows, iDims, offset, pInt16);
263                     if (resSize < 0)
264                     {
265                         return false;
266                     }
267                     res = pInt16;
268                     offset += 1 + resSize;
269                     break;
270                 }
271                 case sci_uint16 :
272                 {
273                     if (inputRows < 5)
274                     {
275                         Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 5, 1);
276                         return false;
277                     }
278
279                     types::UInt16* pUInt16 = nullptr;
280                     const int resSize = decode<types::UInt16>(input + 3, inputRows, iDims, offset, pUInt16);
281                     if (resSize < 0)
282                     {
283                         return false;
284                     }
285                     res = pUInt16;
286                     offset += 1 + resSize;
287                     break;
288                 }
289                 case sci_int32  :
290                 {
291                     if (inputRows < 5)
292                     {
293                         Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 5, 1);
294                         return false;
295                     }
296
297                     types::Int32* pInt32 = nullptr;
298                     const int resSize = decode<types::Int32>(input + 3, inputRows, iDims, offset, pInt32);
299                     if (resSize < 0)
300                     {
301                         return false;
302                     }
303                     res = pInt32;
304                     offset += 1 + resSize;
305                     break;
306                 }
307                 case sci_uint32 :
308                 {
309                     if (inputRows < 5)
310                     {
311                         Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 5, 1);
312                         return false;
313                     }
314
315                     types::UInt32* pUInt32 = nullptr;
316                     const int resSize = decode<types::UInt32>(input + 3, inputRows, iDims, offset, pUInt32);
317                     if (resSize < 0)
318                     {
319                         return false;
320                     }
321                     res = pUInt32;
322                     offset += 1 + resSize;
323                     break;
324                 }
325                 case sci_int64 :
326                 {
327                     if (inputRows < 5)
328                     {
329                         Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 5, 1);
330                         return false;
331                     }
332
333                     types::Int64* pInt64 = nullptr;
334                     const int resSize = decode<types::Int64>(input + 3, inputRows, iDims, offset, pInt64);
335                     if (resSize < 0)
336                     {
337                         return false;
338                     }
339                     res = pInt64;
340                     offset += 1 + resSize;
341                     break;
342                 }
343                 case sci_uint64 :
344                 {
345                     if (inputRows < 5)
346                     {
347                         Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 5, 1);
348                         return false;
349                     }
350
351                     types::UInt64* pUInt64 = nullptr;
352                     const int resSize = decode<types::UInt64>(input + 3, inputRows, iDims, offset, pUInt64);
353                     if (resSize < 0)
354                     {
355                         return false;
356                     }
357                     res = pUInt64;
358                     offset += 1 + resSize;
359                     break;
360                 }
361             }
362             break;
363         }
364         case sci_boolean :
365         {
366             if (inputRows < 4)
367             {
368                 Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 4, 1);
369                 return false;
370             }
371
372             types::Bool* pBool = nullptr;
373             const int resSize = decode<types::Bool>(input + 2, inputRows, iDims, offset, pBool);
374             if (resSize < 0)
375             {
376                 return false;
377             }
378             res = pBool;
379             offset += resSize;
380             break;
381         }
382
383         case sci_strings :
384         {
385             if (inputRows < 4)
386             {
387                 Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 4, 1);
388                 return false;
389             }
390
391             types::String* pString = nullptr;
392             const int resSize = decode<types::String>(input + 2, inputRows, iDims, offset, pString);
393             if (resSize < 0)
394             {
395                 return false;
396             }
397             res = pString;
398             offset += resSize;
399             break;
400         }
401
402         case sci_list    :
403         case sci_tlist   :
404         case sci_mlist   :
405         {
406             if (inputRows < 2)
407             {
408                 Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 2, 1);
409                 return false;
410             }
411
412             types::List* pList = nullptr;
413             if (iType == sci_list)
414             {
415                 pList = new types::List();
416             }
417             else if (iType == sci_tlist)
418             {
419                 pList = new types::TList();
420             }
421             else
422             {
423                 pList = new types::MList();
424             }
425
426             int offsetSave = 0;
427             if (offset == 0)
428             {
429                 offset += 2;
430             }
431             else
432             {
433                 // If reading a sublist, start off with a new offset
434                 offsetSave = offset;
435                 offset = 2;
436             }
437
438             for (int i = 0; i < iDims; ++i)
439             {
440                 if (inputRows < 2 + offset)
441                 {
442                     delete pList;
443                     Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 2, 1);
444                     return false;
445                 }
446                 // Extract the list elements infos and recursively call readElement
447                 int elementType = static_cast<int>(*(input + offset));
448                 int elementDims;
449                 if (elementType == sci_ints)
450                 {
451                     // Integers store their precision in *(input + offset + 1)
452                     elementDims = static_cast<int>(*(input + offset + 2));
453                 }
454                 else
455                 {
456                     elementDims = static_cast<int>(*(input + offset + 1));
457                 }
458                 types::InternalType* element;
459                 if (!readElement(input + offset, elementType, elementDims, inputRows - offset, offset, element))
460                 {
461                     delete pList;
462                     return false;
463                 }
464
465                 pList->append(element);
466                 if (element->isList())
467                 {
468                     element->killMe();
469                 }
470             }
471             offset += offsetSave;
472             res = pList;
473             break;
474         }
475
476         // Structs are not used yet
477         //case types::InternalType::ScilabStruct :
478         //{
479         //    if (inputRows < 2)
480         //    {
481         //        Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 2, 1);
482         //        return false;
483         //    }
484
485         //    if (iDims <= 0)
486         //    {
487         //        res = new types::Struct();
488         //        offset += 2;
489         //        break;
490         //    }
491
492         //    int offsetSave = 0;
493         //    if (offset == 0)
494         //    {
495         //        offset += 2;
496         //    }
497         //    else
498         //    {
499         //        // If reading a sublist, start off with a new offset
500         //        offsetSave = offset;
501         //        offset = 2;
502         //    }
503         //    // Read the header...
504         //    int elementType = static_cast<int>(*(input + offset));
505         //    if (elementType != types::InternalType::ScilabString)
506         //    {
507         //        Scierror(999, _("%s: Wrong value for input argument #%d: %d (String) expected.\n"), vec2varName.c_str(), 1, 11);
508         //        return false;
509         //    }
510         //    int elementDims = static_cast<int>(*(input + offset + 1));
511         //    types::InternalType* element;
512         //    if (!readElement(input + offset, elementType, elementDims, inputRows - offset, offset, element))
513         //    {
514         //        return false;
515         //    }
516
517         //    types::Struct* pStruct = new types::Struct(1, 1);
518         //    types::String* header = element->getAs<types::String>();
519         //    // ... and copy it in 'pStruct'
520         //    for (int i = 0; i < header->getSize(); ++i)
521         //    {
522         //        pStruct->get(0)->addField(header->get(i));
523         //    }
524
525         //    for (int i = 1; i < iDims + 1; ++i)
526         //    {
527         //        if (inputRows < 2 + offset)
528         //        {
529         //            delete pStruct;
530         //            Scierror(999, _("%s: Wrong size for input argument #%d: At least %dx%d expected.\n"), vec2varName.c_str(), 1, offset + 2, 1);
531         //            return false;
532         //        }
533         //        // Extract the fields content infos and recursively call readElement
534         //        elementType = static_cast<int>(*(input + offset));
535         //        elementDims = static_cast<int>(*(input + offset + 1));
536         //        if (!readElement(input + offset, elementType, elementDims, inputRows - offset, offset, element))
537         //        {
538         //            delete pStruct;
539         //            return false;
540         //        }
541         //        pStruct->get(0)->set(header->get(i - 1), element);
542         //    }
543
544         //    header->killMe();
545         //    offset += offsetSave;
546         //    res = pStruct;
547         //    break;
548         //}
549
550         default :
551             Scierror(999, _("%s: Wrong value for element #%d of input argument #%d: Unknown type.\n"), vec2varName.c_str(), offset + 1, 1);
552             return false;
553     }
554
555     return true;
556 }
557
558 bool vec2var(const std::vector<double> in, types::InternalType* &out)
559 {
560     const int iType = static_cast<int>(in[0]);
561     int iDims;
562     if (iType == sci_ints)
563     {
564         // Integers store their precision in in[1]
565         iDims = static_cast<int>(in[2]);
566     }
567     else
568     {
569         iDims = static_cast<int>(in[1]);
570     }
571
572     int offset = 0;
573     if (!readElement(&in[0], iType, iDims, static_cast<int>(in.size()), offset, out))
574     {
575         return false;
576     }
577
578     return true;
579 }