d3a9e841771de95d6d42b7e6d4ffb873f8b2d7fa
[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.reserve(ret.size() + totalSize);
89
90     ret.push_back(((types::InternalType*) input)->getType());
91     ret.push_back(iDims);
92     for (int i = 0; i < iDims; ++i)
93     {
94         ret.push_back(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     double* data = &(*ret.end());
100     ret.resize(ret.size() + nDoubleNeeded);
101     memcpy(data, input->get(), iElements * sizeof(typename T::type));
102 }
103
104 static void encode(types::Double* input, std::vector<double> &ret)
105 {
106     int iDims, iElements, totalSize;
107     int* pDims;
108     computeDims(input, iDims, pDims, iElements, totalSize);
109
110     const int isComplex = (input->isComplex()) ? 1 : 0;
111     totalSize++; // Add the complex boolean
112     totalSize += (isComplex + 1) * iElements; // Size of the required data buffer
113
114     // Allocation for type + number of dimensions + each dimension + complex boolean + each element (doubled if complex)
115     ret.reserve(ret.size() + totalSize);
116
117     ret.push_back(types::InternalType::ScilabDouble);
118     ret.push_back(iDims);
119     for (int i = 0; i < iDims; ++i)
120     {
121         ret.push_back(pDims[i]);
122     }
123     ret.push_back(isComplex);
124
125     double* data = &(*ret.end());
126     ret.resize(ret.size() + iElements);
127     memcpy(data, input->getReal(), iElements * sizeof(double));
128     if (isComplex == 1)
129     {
130         data = &(*ret.end());
131         ret.resize(ret.size() + iElements);
132         memcpy(data, input->getImg(), iElements * sizeof(double));
133     }
134
135     // An empty matrix input will return [12; 2; 0; 0; 0]
136 }
137
138 static void encode(types::String* input, std::vector<double> &ret)
139 {
140     int iDims, iElements, totalSize;
141     int* pDims;
142     computeDims(input, iDims, pDims, iElements, totalSize);
143
144     totalSize += iElements;
145
146     // Reserve space for the string offsets and contents
147     char** utf8 = new char*[iElements];
148     size_t* pLengths = new size_t[iElements];
149     int* offsets = new int[iElements];
150     int offset_cur = 0, offset_acc = 0;
151     for (int i = 0; i < iElements; ++i)
152     {
153         char* str = wide_string_to_UTF8(input->get(i));
154         utf8[i] = str;
155         // Adding the '\0' byte to the length
156         const size_t len = strlen(str) + 1;
157         pLengths[i] = len;
158
159         offset_cur = static_cast<int>((len * sizeof(char) + sizeof(double) - 1) / sizeof(double));
160         totalSize += offset_cur;
161         offset_acc += offset_cur;
162         offsets[i] = offset_acc;
163     }
164
165     // Allocation for type + number of dimensions + each dimension + each element length + each element
166     ret.reserve(ret.size() + totalSize);
167
168     ret.push_back(types::InternalType::ScilabString);
169     ret.push_back(iDims);
170     for (int i = 0; i < iDims; ++i)
171     {
172         ret.push_back(pDims[i]);
173     }
174     for (int i = 0; i < iElements; ++i)
175     {
176         ret.push_back(offsets[i]);
177     }
178
179     double* data = &(*ret.end());
180     ret.resize(ret.size() + offsets[iElements - 1]);
181
182     size_t len = pLengths[0];
183     memcpy(data, utf8[0], len * sizeof(char));
184     data += offsets[0];
185     for (int i = 1; i < iElements; ++i)
186     {
187         size_t len = pLengths[i];
188         memcpy(data, utf8[i], len * sizeof(char));
189         data += offsets[i] - offsets[i - 1];
190     }
191
192     // Free all the strings, after being copied
193     for (int i = 0; i < iElements; ++i)
194     {
195         FREE(utf8[i]);
196     }
197     delete[] utf8;
198     delete[] offsets;
199     delete[] pLengths;
200 }
201
202 static void encode(types::List* input, std::vector<double> &ret)
203 {
204     const int iElements = input->getSize();
205
206     ret.push_back(input->getType());
207     ret.push_back(iElements);
208     for (int i = 0; i < iElements; ++i)
209     {
210         // Recursively call var2vec on each element and extract the obtained results
211         var2vec(input->get(i), ret);
212     }
213
214     // An empty list input will return [22; 0], a tlist [23; 0] and an mlist [24; 0]
215 }
216
217 static void encode(types::Struct* input, std::vector<double> &ret)
218 {
219     const bool isEmpty = input->getSize() == 0;
220
221     types::String* fields = nullptr;
222     int iElements = 0;
223     if (!isEmpty)
224     {
225         fields = input->getFieldNames();
226         iElements = fields->getSize();
227     }
228
229     ret.push_back(input->getType());
230     ret.push_back(iElements);
231     if (!isEmpty)
232     {
233         // Call var2vec on the struct's fields to extract a header
234         var2vec(fields, ret);
235
236         // Now extract the fields' content, assuming this is not a multidimensional struct
237         types::SingleStruct* content = input->get(0);
238         for (int i = 0; i < iElements; ++i)
239         {
240             var2vec(content->get(fields->get(i)), ret);
241         }
242
243
244         fields->killMe();
245     }
246
247     // An empty struct input will return [26; 0]
248 }
249
250 bool var2vec(types::InternalType* in, std::vector<double> &out)
251 {
252     switch (in->getType())
253     {
254         // Reuse scicos model encoding for 'model.opar' and 'model.odstate' fields
255         case types::InternalType::ScilabDouble :
256             encode(in->getAs<types::Double>(), out);
257             break;
258
259         case types::InternalType::ScilabInt8   :
260             encode(in->getAs<types::Int8>(), out);
261             break;
262         case types::InternalType::ScilabUInt8  :
263             encode(in->getAs<types::UInt8>(), out);
264             break;
265         case types::InternalType::ScilabInt16  :
266             encode(in->getAs<types::Int16>(), out);
267             break;
268         case types::InternalType::ScilabUInt16 :
269             encode(in->getAs<types::UInt16>(), out);
270             break;
271         case types::InternalType::ScilabInt32  :
272             encode(in->getAs<types::Int32>(), out);
273             break;
274         case types::InternalType::ScilabUInt32 :
275             encode(in->getAs<types::UInt32>(), out);
276             break;
277         case types::InternalType::ScilabInt64  :
278             encode(in->getAs<types::Int64>(), out);
279             break;
280         case types::InternalType::ScilabUInt64 :
281             encode(in->getAs<types::UInt64>(), out);
282             break;
283         case types::InternalType::ScilabBool   :
284             encode(in->getAs<types::Bool>(), out);
285             break;
286
287         case types::InternalType::ScilabString :
288             encode(in->getAs<types::String>(), out);
289             break;
290
291         case types::InternalType::ScilabList   :
292             encode(in->getAs<types::List>(), out);
293             break;
294         case types::InternalType::ScilabTList  :
295             encode(in->getAs<types::List>(), out);
296             break;
297         case types::InternalType::ScilabMList  :
298             encode(in->getAs<types::List>(), out);
299             break;
300         case types::InternalType::ScilabStruct :
301             encode(in->getAs<types::Struct>(), out);
302             break;
303
304         default :
305             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");
306             return false;
307     }
308
309     return true;
310 }