Xcos MVC: fix includes
[scilab.git] / scilab / modules / scicos / src / cpp / var2vec.cpp
1 /*
2 *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 *  Copyright (C) 2015 - Scilab Enterprises - Paul Bignier
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 <vector>
14 #include <string>
15 #include <cwchar>
16 #include <cstring>
17
18 #include "var2vec.hxx"
19
20 #include "types.hxx"
21 #include "internal.hxx"
22 #include "double.hxx"
23 #include "int.hxx"
24 #include "bool.hxx"
25 #include "string.hxx"
26 #include "list.hxx"
27 #include "tlist.hxx"
28 #include "mlist.hxx"
29 #include "struct.hxx"
30
31 extern "C"
32 {
33 #include "charEncoding.h"
34 #include "Scierror.h"
35 #include "localization.h"
36 }
37
38 static const std::string var2vecName = "var2vec";
39
40 static void computeDims(types::GenericType* input, int &iDims, int* &pDims, int &iElements, int &totalSize)
41 {
42     iDims = input->getDims();
43     pDims = input->getDimsArray();
44     iElements = 1;
45     for (int i = 0; i < iDims; ++i)
46     {
47         iElements *= pDims[i];
48     }
49
50     // Type + number of dimensions + dimensions
51     totalSize = 2 + iDims;
52 }
53
54 /**
55  * Calculate the length increment depending on the ::value_type of 'V' and the type of the Scilab type 'T'
56  *
57  * @param V variable that must have a 'value_type' field
58  * @param T Scilab type
59  * @param v the instance of the Scilab type
60  * @return the number of V elements used to store the data
61  */
62 template<typename V, typename T>
63 size_t required_length(const V /*it*/, T* v)
64 {
65     const size_t sizeof_ret_value = sizeof(typename V::value_type);
66     if (sizeof(typename T::type) >= sizeof_ret_value)
67     {
68         return v->getSize() * sizeof(typename T::type) / sizeof_ret_value;
69     }
70     else
71     {
72         // Increase the size to contain enough space, manage the size_t rounding issue
73         return (v->getSize() * sizeof(typename T::type) + (sizeof_ret_value - 1)) / sizeof_ret_value;
74     }
75 }
76
77 template <typename T>
78 void encode(T* input, std::vector<double> &ret)
79 {
80     int iDims, iElements, totalSize;
81     int* pDims;
82     computeDims(input, iDims, pDims, iElements, totalSize);
83
84     const int nDoubleNeeded = static_cast<int>(required_length(ret, input));
85     totalSize += nDoubleNeeded;
86
87     // Allocation for type + number of dimensions + each dimension + each element
88     ret.resize(totalSize);
89
90     ret[0] = ((types::InternalType*) input)->getType();
91     ret[1] = iDims;
92     for (int i = 0; i < iDims; ++i)
93     {
94         ret[2 + i] = pDims[i];
95     }
96
97     // Using contiguity of the memory, we save the input into 'ret'
98     // Use a buffer to fill the entirety of 'ret'
99     memcpy(&ret[2 + iDims], input->get(), iElements * sizeof(typename T::type));
100 }
101
102 static void encode(types::Double* input, std::vector<double> &ret)
103 {
104     int iDims, iElements, totalSize;
105     int* pDims;
106     computeDims(input, iDims, pDims, iElements, totalSize);
107
108     const int isComplex = (input->isComplex()) ? 1 : 0;
109     totalSize++; // Add the complex boolean
110     totalSize += (isComplex + 1) * iElements; // Size of the required data buffer
111
112     // Allocation for type + number of dimensions + each dimension + complex boolean + each element (doubled if complex)
113     ret.resize(totalSize);
114
115     ret[0] = types::InternalType::ScilabDouble;
116     ret[1] = iDims;
117     for (int i = 0; i < iDims; ++i)
118     {
119         ret[2 + i] = pDims[i];
120     }
121     ret[2 + iDims] = isComplex;
122
123     memcpy(&ret[2 + iDims + 1], input->getReal(), iElements * sizeof(double));
124     if (isComplex == 1)
125     {
126         memcpy(&ret[ + 2 + iDims + 1 + iElements], input->getImg(), iElements * sizeof(double));
127     }
128     // An empty matrix input will return [12; 2; 0; 0; 0]
129 }
130
131 static void encode(types::String* input, std::vector<double> &ret)
132 {
133     int iDims, iElements, totalSize;
134     int* pDims;
135     computeDims(input, iDims, pDims, iElements, totalSize);
136
137     totalSize += iElements;
138
139     // Reserve space for the string offsets and contents
140     char** utf8 = new char*[iElements];
141     size_t* pLengths = new size_t[iElements];
142     int* offsets = new int[iElements];
143     int offset_cur = 0, offset_acc = 0;
144     for (int i = 0; i < iElements; ++i)
145     {
146         char* str = wide_string_to_UTF8(input->get(i));
147         utf8[i] = str;
148         // Adding the '\0' byte to the length
149         const size_t len = strlen(str) + 1;
150         pLengths[i] = len;
151
152         offset_cur = static_cast<int>((len * sizeof(char) + sizeof(double) - 1) / sizeof(double));
153         totalSize += offset_cur;
154         offset_acc += offset_cur;
155         offsets[i] = offset_acc;
156     }
157
158     // Allocation for type + number of dimensions + each dimension + each element length + each element
159     ret.resize(totalSize);
160
161     ret[0] = types::InternalType::ScilabString;
162     ret[1] = iDims;
163     for (int i = 0; i < iDims; ++i)
164     {
165         ret[2 + i] = pDims[i];
166     }
167
168     size_t len = pLengths[0];
169     ret[2 + iDims] = offsets[0];
170     memcpy(&ret[2 + iDims + iElements], *utf8, len * sizeof(char));
171     for (int i = 1; i < iElements; ++i)
172     {
173         len = pLengths[i];
174         ret[2 + iDims + i] = offsets[i];
175         memcpy(&ret[2 + iDims + iElements + offsets[i - 1]], *(utf8 + i), len * sizeof(char));
176     }
177
178     // Free all the strings, after being copied
179     for (int i = 0; i < iElements; ++i)
180     {
181         FREE(utf8[i]);
182     }
183     delete[] utf8;
184     delete[] offsets;
185     delete[] pLengths;
186 }
187
188 static void encode(types::List* input, std::vector<double> &ret)
189 {
190     const int iElements = input->getSize();
191     int totalSize = 2;
192
193     std::vector<std::vector<double>> listElements (iElements);
194     for (int i = 0; i < iElements; ++i)
195     {
196         // Recursively call var2vec on each element and extract the obtained results
197         var2vec(input->get(i), listElements[i]);
198         totalSize += static_cast<int>(listElements[i].size());
199     }
200     // Allocation for type + list length + each list element
201     ret.resize(totalSize);
202
203     ret[0] = input->getType();
204     ret[1] = iElements;
205     int offset = 0;
206     for (int i = 0; i < iElements; ++i)
207     {
208         memcpy(&ret[2 + offset], &listElements[i][0], listElements[i].size() * sizeof(double));
209         offset += static_cast<int>(listElements[i].size());
210     }
211     // An empty list input will return [22; 0], a tlist [23; 0] and an mlist [24; 0]
212 }
213
214 static void encode(types::Struct* input, std::vector<double> &ret)
215 {
216     int iElements = 0;
217     types::String* fields;
218     if (input->getSize() > 0)
219     {
220         fields = input->get(0)->getFieldNames();
221         iElements = fields->getSize();
222     }
223     int totalSize = 2;
224
225     std::vector<std::vector<double>> fieldsContent (1 + iElements);
226     if (input->getSize() > 0)
227     {
228         // Call var2vec on the struct's fields to extract a header
229         var2vec(fields, fieldsContent[0]);
230         totalSize += static_cast<int>(fieldsContent[0].size());
231         // Now extract the fields' content
232         for (int i = 1; i < iElements + 1; ++i)
233         {
234             // Recursively call var2vec on each element and extract the obtained results
235             var2vec(input->get(0)->get(fields->get(i - 1)), fieldsContent[i]);
236             totalSize += static_cast<int>(fieldsContent[i].size());
237         }
238     }
239     // Allocation for type + fields names + fields content
240     ret.resize(totalSize);
241
242     ret[0] = input->getType();
243     ret[1] = iElements;
244     int offset = 0;
245     for (int i = 0; i < iElements + 1; ++i)
246     {
247         memcpy(&ret[2 + offset], &fieldsContent[i][0], fieldsContent[i].size() * sizeof(double));
248         offset += static_cast<int>(fieldsContent[i].size());
249     }
250     // An empty struct input will return [26; 0]
251 }
252
253 bool var2vec(types::InternalType* in, std::vector<double> &out)
254 {
255     switch (in->getType())
256     {
257             // Reuse scicos model encoding for 'model.opar' and 'model.odstate' fields
258         case types::InternalType::ScilabDouble :
259             encode(in->getAs<types::Double>(), out);
260             break;
261
262         case types::InternalType::ScilabInt8   :
263             encode(in->getAs<types::Int8>(), out);
264             break;
265         case types::InternalType::ScilabUInt8  :
266             encode(in->getAs<types::UInt8>(), out);
267             break;
268         case types::InternalType::ScilabInt16  :
269             encode(in->getAs<types::Int16>(), out);
270             break;
271         case types::InternalType::ScilabUInt16 :
272             encode(in->getAs<types::UInt16>(), out);
273             break;
274         case types::InternalType::ScilabInt32  :
275             encode(in->getAs<types::Int32>(), out);
276             break;
277         case types::InternalType::ScilabUInt32 :
278             encode(in->getAs<types::UInt32>(), out);
279             break;
280         case types::InternalType::ScilabInt64  :
281             encode(in->getAs<types::Int64>(), out);
282             break;
283         case types::InternalType::ScilabUInt64 :
284             encode(in->getAs<types::UInt64>(), out);
285             break;
286         case types::InternalType::ScilabBool   :
287             encode(in->getAs<types::Bool>(), out);
288             break;
289
290         case types::InternalType::ScilabString :
291             encode(in->getAs<types::String>(), out);
292             break;
293
294         case types::InternalType::ScilabList   :
295             encode(in->getAs<types::List>(), out);
296             break;
297         case types::InternalType::ScilabTList  :
298             encode(in->getAs<types::List>(), out);
299             break;
300         case types::InternalType::ScilabMList  :
301             encode(in->getAs<types::List>(), out);
302             break;
303
304         case types::InternalType::ScilabStruct :
305             encode(in->getAs<types::Struct>(), out);
306             break;
307
308         default :
309             Scierror(999, _("%s: Wrong type for input argument #%d: %s, %s, %s, %s, %s or %s type.\n"), var2vecName.c_str(), 1, "Double", "Integer", "Boolean", "String", "List", "Struct");
310             return false;
311     }
312
313     return true;
314 }