* Bug 14606 fixed: now `[names,mem]=who()` returns memory used by variables
[scilab.git] / scilab / modules / ast / src / cpp / types / list.cpp
1 /*
2 *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 *  Copyright (C) 2010-2010 - DIGITEO - Bruno JOFRET
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 <sstream>
17 #include "double.hxx"
18 #include "list.hxx"
19 #include "listundefined.hxx"
20 #include "listinsert.hxx"
21 #include "types_tools.hxx"
22 #include "localization.hxx"
23 #include "scilabWrite.hxx"
24 #include "types_tools.hxx"
25 #include "function.hxx"
26
27 #ifndef NDEBUG
28 #include "inspector.hxx"
29 #endif
30
31 extern "C"
32 {
33 #include "os_string.h"
34 }
35
36 namespace types
37 {
38 /**
39 ** Constructor & Destructor (public)
40 */
41 List::List() : Container()
42 {
43     m_plData = new std::vector<InternalType *>();
44 #ifndef NDEBUG
45     Inspector::addItem(this);
46 #endif
47 }
48
49 List::~List()
50 {
51     if (isDeletable() == true)
52     {
53         for (auto data : *m_plData)
54         {
55             data->DecreaseRef();
56             data->killMe();
57         }
58         delete m_plData;
59     }
60 #ifndef NDEBUG
61     Inspector::removeItem(this);
62 #endif
63 }
64
65 /**
66 ** Private Copy Constructor and data Access
67 */
68 List::List(List *_oListCopyMe)
69 {
70     m_plData = new std::vector<InternalType *>;
71     std::vector<InternalType *>* lData = _oListCopyMe->getData();
72     int size = lData->size();
73     for (int i = 0 ; i < size ; i++)
74     {
75         append((*lData)[i]);
76     }
77
78     m_iSize = static_cast<int>(size);
79 #ifndef NDEBUG
80     Inspector::addItem(this);
81 #endif
82 }
83
84 std::vector<InternalType *> *List::getData()
85 {
86     return m_plData;
87 }
88
89 bool List::getMemory(int* _piSize, int* _piSizePlusType)
90 {
91     *_piSize = 0;
92     *_piSizePlusType = 0;
93     for (auto pData : *m_plData)
94     {
95         int piS, piSPT;
96         if (pData->getMemory(&piS, &piSPT))
97         {
98             *_piSize += piS;
99             *_piSizePlusType += piSPT;
100         }
101     }
102
103     *_piSizePlusType += sizeof(List);
104     return true;
105 }
106
107 /**
108 ** size_get
109 ** Return the number of elements in list
110 */
111 int List::getSize() const
112 {
113     return static_cast<int>(m_plData->size());
114 }
115
116 /**
117 ** append(InternalType *_typedValue)
118 ** Append the given value to the end of the List
119 */
120 List* List::append(InternalType *_typedValue)
121 {
122     List* pIT = checkRef(this, &List::append, _typedValue);
123     if (pIT != this)
124     {
125         return pIT;
126     }
127
128     _typedValue->IncreaseRef();
129     m_plData->push_back(_typedValue);
130     m_iSize = static_cast<int>(m_plData->size());
131     return this;
132 }
133
134 /**
135 ** Clone
136 ** Create a new List and Copy all values.
137 */
138 List *List::clone()
139 {
140     return new List(this);
141 }
142
143 /**
144 ** toString to display Lists
145 */
146 bool List::toString(std::wostringstream& ostr)
147 {
148     if (getSize() == 0)
149     {
150         ostr.str(L"");
151         ostr << L"     ()" << std::endl;
152     }
153     else
154     {
155         wchar_t* wcsVarName = os_wcsdup(ostr.str().c_str());
156         int iPosition = 1;
157         for (auto val : *m_plData)
158         {
159             std::wostringstream nextVarName;
160             ostr.str(L"");
161             nextVarName << " " << SPACES_LIST << wcsVarName << L"(" << iPosition++ << L")";
162             ostr << std::endl << nextVarName.str() << std::endl << std::endl;
163             scilabForcedWriteW(ostr.str().c_str());
164             if (VariableToString(val, nextVarName.str().c_str()) == types::Function::Error)
165             {
166                 free(wcsVarName);
167                 ostr.str(L"");
168                 return true;
169             }
170         }
171
172         ostr.str(L"");
173         free(wcsVarName);
174     }
175
176     return true;
177 }
178
179 InternalType* List::extract(typed_list* _pArgs)
180 {
181     List* outList = new List();
182     //check input param
183     if (_pArgs->size() != 1)
184     {
185         return outList;
186     }
187
188     typed_list pArg;
189     int iDims           = (int)_pArgs->size();
190
191     int* piMaxDim       = new int[iDims];
192     int* piCountDim     = new int[iDims];
193
194     //evaluate each argument and replace by appropriate value and compute the count of combinations
195     int iSeqCount = checkIndexesArguments(this, _pArgs, &pArg, piMaxDim, piCountDim);
196     delete[] piMaxDim;
197     delete[] piCountDim;
198
199     for (int i = 0 ; i < iSeqCount ; i++)
200     {
201         int idx = (int)pArg[0]->getAs<Double>()->get(i);
202         if (idx > getSize() || idx < 1)
203         {
204             delete outList;
205             outList = NULL;
206             break;
207         }
208         InternalType* pIT = (*m_plData)[idx - 1];
209         outList->set(i, pIT);
210     }
211
212     //free pArg content
213     cleanIndexesArguments(_pArgs, &pArg);
214
215     return outList;
216 }
217
218 List* List::insert(typed_list* _pArgs, InternalType* _pSource)
219 {
220     //check input param
221     if (_pArgs->size() != 1)
222     {
223         return NULL;
224     }
225
226     List* pIT = checkRef(this, &List::insert, _pArgs, _pSource);
227     if (pIT != this)
228     {
229         return pIT;
230     }
231
232     typed_list pArg;
233     int iDims           = (int)_pArgs->size();
234
235     int* piMaxDim       = new int[iDims];
236     int* piCountDim     = new int[iDims];
237
238     int iSeqCount = checkIndexesArguments(this, _pArgs, &pArg, piMaxDim, piCountDim);
239     delete[] piMaxDim;
240     delete[] piCountDim;
241     if (iSeqCount == 0)
242     {
243         //free pArg content
244         cleanIndexesArguments(_pArgs, &pArg);
245         //do nothing
246         return this;
247     }
248     else if (iSeqCount > 1)
249     {
250         //free pArg content
251         cleanIndexesArguments(_pArgs, &pArg);
252         std::wostringstream os;
253         os << _W("Unable to insert multiple item in a list.\n");
254         throw ast::InternalError(os.str());
255     }
256     else if (iSeqCount < 0)
257     {
258         //free pArg content
259         cleanIndexesArguments(_pArgs, &pArg);
260         return NULL;
261     }
262
263     int idx = (int)pArg[0]->getAs<Double>()->get(0);
264     if (_pSource->isListDelete())
265     {
266         //delete item
267         if (idx == 0)
268         {
269             //free pArg content
270             cleanIndexesArguments(_pArgs, &pArg);
271             //do nothing
272             return this;
273         }
274         else if (idx <= (int)m_plData->size())
275         {
276             InternalType* pIT = (*m_plData)[idx - 1];
277             if (pIT)
278             {
279                 pIT->DecreaseRef();
280                 pIT->killMe();
281             }
282             m_plData->erase(m_plData->begin() + idx - 1);
283         }
284     }
285     else if (_pSource->isListInsert())
286     {
287         //insert item
288         if (idx == 0)
289         {
290             //free pArg content
291             cleanIndexesArguments(_pArgs, &pArg);
292             std::wostringstream os;
293             os << _W("Index out of bounds.\n");
294             throw ast::InternalError(os.str());
295         }
296
297         InternalType* pInsert = _pSource->getAs<ListInsert>()->getInsert();
298         pInsert->IncreaseRef();
299         if (idx > (int)m_plData->size())
300         {
301             //try to insert after the last index, increase list size and assign value
302             while ((int)m_plData->size() < idx)
303             {
304                 //incease list size and fill with "Undefined"
305                 m_plData->push_back(new ListUndefined());
306             }
307             (*m_plData)[idx - 1] = pInsert;
308         }
309         else
310         {
311             m_plData->insert(m_plData->begin() + idx - 1, pInsert);
312         }
313     }
314     else if (idx == 0)
315     {
316         //special case to insert at the first position
317         _pSource->IncreaseRef();
318         m_plData->insert(m_plData->begin(), _pSource);
319     }
320     else
321     {
322         while ((int)m_plData->size() < idx)
323         {
324             //incease list size and fill with "Undefined"
325             InternalType* pLU = new ListUndefined();
326             pLU->IncreaseRef();
327             m_plData->push_back(pLU);
328         }
329
330         InternalType* pIT = (*m_plData)[idx - 1];
331
332         (*m_plData)[idx - 1] = _pSource;
333         (*m_plData)[idx - 1]->IncreaseRef();
334
335         pIT->DecreaseRef();
336         pIT->killMe();
337     }
338
339     m_iSize = (int)m_plData->size();
340
341     //free pArg content
342     cleanIndexesArguments(_pArgs, &pArg);
343
344     return this;
345 }
346
347 InternalType* List::get(const int _iIndex)
348 {
349     if (_iIndex >= 0 && _iIndex < (int)m_plData->size())
350     {
351         return (*m_plData)[_iIndex];
352     }
353     return NULL;
354 }
355
356 List* List::set(const int _iIndex, InternalType* _pIT)
357 {
358     if (_iIndex < 0)
359     {
360         return NULL;
361     }
362
363     List* pIT = checkRef(this, &List::set, _iIndex, _pIT);
364     if (pIT != this)
365     {
366         return pIT;
367     }
368
369     while ((int)m_plData->size() < _iIndex)
370     {
371         //incease list size and fill with "Undefined"
372         m_plData->push_back(new ListUndefined());
373         m_plData->back()->IncreaseRef();
374         m_iSize = getSize();
375     }
376
377     if ((int)m_plData->size() == _iIndex)
378     {
379         _pIT->IncreaseRef();
380         m_plData->push_back(_pIT);
381         m_iSize = getSize();
382     }
383     else
384     {
385         InternalType* pOld = (*m_plData)[_iIndex];
386
387         _pIT->IncreaseRef();
388         (*m_plData)[_iIndex] = _pIT;
389
390         //manage ref on the old value
391         if (pOld)
392         {
393             pOld->DecreaseRef();
394             pOld->killMe();
395         }
396     }
397
398     return this;
399 }
400
401 bool List::operator==(const InternalType& it)
402 {
403     if (const_cast<InternalType &>(it).isList() == false)
404     {
405         return false;
406     }
407
408     List* plst = const_cast<InternalType &>(it).getAs<List>();
409
410     if (getSize() != plst->getSize())
411     {
412         return false;
413     }
414
415     for (int i = 0; i < getSize(); i++)
416     {
417         if (*(*m_plData)[i] != *plst->get(i))
418         {
419             return false;
420         }
421     }
422
423     return true;
424 }
425
426 }