* Bug 14606 fixed: now `[names,mem]=who()` returns memory used by variables
[scilab.git] / scilab / modules / ast / src / cpp / types / struct.cpp
1 /*
2 *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 *  Copyright (C) 2011 - DIGITEO - Antoine ELIAS
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 #include "struct.hxx"
16 #include "string.hxx"
17 #include "double.hxx"
18 #include "list.hxx"
19 #include "int.hxx"
20 #include "localization.hxx"
21 #include "scilabWrite.hxx"
22 #include "exp.hxx"
23 #include "types_tools.hxx"
24
25 namespace types
26 {
27 Struct::Struct()
28 {
29     m_bDisableCloneInCopyValue = false;
30     SingleStruct** pIT  = NULL;
31     int piDims[2] = {0, 0};
32     create(piDims, 2, &pIT, NULL);
33 #ifndef NDEBUG
34     Inspector::addItem(this);
35 #endif
36 }
37
38 Struct::Struct(int _iRows, int _iCols)
39 {
40     m_bDisableCloneInCopyValue = false;
41     SingleStruct** pIT  = NULL;
42     SingleStruct *p = new SingleStruct();
43     int piDims[2] = {_iRows, _iCols};
44     create(piDims, 2, &pIT, NULL);
45     for (int i = 0 ; i < getSize() ; i++)
46     {
47         set(i, p);
48     }
49
50     p->killMe();
51 #ifndef NDEBUG
52     Inspector::addItem(this);
53 #endif
54 }
55
56 Struct::Struct(int _iDims, const int* _piDims)
57 {
58     m_bDisableCloneInCopyValue = false;
59     SingleStruct** pIT  = NULL;
60     SingleStruct *p = new SingleStruct();
61     create(_piDims, _iDims, &pIT, NULL);
62     for (int i = 0 ; i < getSize() ; i++)
63     {
64         set(i, p);
65     }
66     p->killMe();
67
68 #ifndef NDEBUG
69     Inspector::addItem(this);
70 #endif
71 }
72
73 Struct::~Struct()
74 {
75     if (isDeletable() == true)
76     {
77         for (int i = 0 ; i < m_iSizeMax ; i++)
78         {
79             SingleStruct *pStr = m_pRealData[i];
80             if (pStr)
81             {
82                 pStr->DecreaseRef();
83                 pStr->killMe();
84             }
85         }
86
87         delete[] m_pRealData;
88     }
89 #ifndef NDEBUG
90     Inspector::removeItem(this);
91 #endif
92 }
93
94 Struct::Struct(Struct *_oStructCopyMe)
95 {
96     m_bDisableCloneInCopyValue = false;
97     SingleStruct** pIT = NULL;
98     create(_oStructCopyMe->getDimsArray(), _oStructCopyMe->getDims(), &pIT, NULL);
99     for (int i = 0 ; i < getSize() ; i++)
100     {
101         pIT[i] = _oStructCopyMe->get(i)->clone();
102         pIT[i]->IncreaseRef();
103     }
104 #ifndef NDEBUG
105     Inspector::addItem(this);
106 #endif
107 }
108
109 bool Struct::getMemory(int* _piSize, int* _piSizePlusType)
110 {
111     *_piSize = 0;
112     *_piSizePlusType = 0;
113     SingleStruct** p = get();
114     for (int i = 0; i < getSize(); i++)
115     {
116         int piS, piSPT;
117         if (p[i]->getMemory(&piS, &piSPT))
118         {
119             *_piSize += piS;
120             *_piSizePlusType += piSPT;
121         }
122     }
123
124     *_piSizePlusType += sizeof(Struct);
125     return true;
126 }
127
128 Struct* Struct::clone()
129 {
130     return new Struct(this);
131 }
132
133 bool Struct::transpose(InternalType *& out)
134 {
135     if (isScalar())
136     {
137         out = clone();
138         return true;
139     }
140
141     if (m_iDims == 2)
142     {
143         int piDims[2] = {getCols(), getRows()};
144         Struct * pSt = new Struct(2, piDims);
145         out = pSt;
146         for (int i = 0; i < m_iSize; ++i)
147         {
148             pSt->m_pRealData[i]->DecreaseRef();
149             pSt->m_pRealData[i]->killMe();
150         }
151
152         Transposition::transpose_clone(getRows(), getCols(), m_pRealData, pSt->m_pRealData);
153
154         return true;
155     }
156
157     return false;
158 }
159
160 bool Struct::extract(const std::wstring & name, InternalType *& out)
161 {
162     if (exists(name))
163     {
164         out = extractField(name);
165     }
166     else
167     {
168         wchar_t szError[bsiz];
169         os_swprintf(szError, bsiz, _W("Unknown field : %ls.\n").c_str(), name.c_str());
170         throw std::wstring(szError);
171     }
172
173     return true;
174 }
175
176 bool Struct::invoke(typed_list & in, optional_list & opt, int _iRetCount, typed_list & out, const ast::Exp & e)
177 {
178
179     if (in.size() == 0)
180     {
181         out.push_back(this);
182         return true;
183     }
184     else if (in.size() == 1)
185     {
186         InternalType * arg = in[0];
187         typed_list _out;
188         if (arg->isString())
189         {
190             std::vector<std::wstring> wstFields;
191             String * pString = arg->getAs<types::String>();
192             for (int i = 0; i < pString->getSize(); ++i)
193             {
194                 std::wstring wstField(pString->get(i));
195                 if (this->exists(wstField))
196                 {
197                     wstFields.push_back(wstField);
198                 }
199                 else
200                 {
201                     wchar_t szError[bsiz];
202                     os_swprintf(szError, bsiz, _W("Field \"%ls\" does not exists\n").c_str(), wstField.c_str());
203                     throw ast::InternalError(szError, 999, e.getLocation());
204                 }
205             }
206
207             _out = extractFields(wstFields);
208
209             out.swap(_out);
210             return true;
211         }
212     }
213
214     return ArrayOf<SingleStruct*>::invoke(in, opt, _iRetCount, out, e);
215 }
216
217 Struct* Struct::set(int _iRows, int _iCols, SingleStruct* _pIT)
218 {
219     if (_iRows < getRows() && _iCols < getCols())
220     {
221         return set(_iCols * getRows() + _iRows, _pIT);
222     }
223     return NULL;
224 }
225
226 Struct* Struct::set(int _iRows, int _iCols, const SingleStruct* _pIT)
227 {
228     if (_iRows < getRows() && _iCols < getCols())
229     {
230         return set(_iCols * getRows() + _iRows, _pIT);
231     }
232     return NULL;
233 }
234
235 Struct* Struct::set(int _iIndex, SingleStruct* _pIT)
236 {
237     typedef Struct* (Struct::*set_t)(int, SingleStruct*);
238     Struct* pIT = checkRef(this, (set_t)&Struct::set, _iIndex, _pIT);
239     if (pIT != this)
240     {
241         return pIT;
242     }
243
244     if (_iIndex < getSize())
245     {
246         if (m_bDisableCloneInCopyValue && m_pRealData[_iIndex] == _pIT)
247         {
248             return this;
249         }
250
251         InternalType* pOld = m_pRealData[_iIndex];
252
253         m_pRealData[_iIndex] = copyValue(_pIT);
254         if (m_bDisableCloneInCopyValue == false)
255         {
256             //only in clone mode
257             m_pRealData[_iIndex]->IncreaseRef();
258         }
259
260         if (pOld != NULL)
261         {
262             pOld->DecreaseRef();
263             pOld->killMe();
264         }
265
266         return this;
267     }
268     return NULL;
269 }
270
271 Struct* Struct::set(int _iIndex, const SingleStruct* _pIT)
272 {
273     typedef Struct* (Struct::*set_t)(int, const SingleStruct*);
274     Struct* pIT = checkRef(this, (set_t)&Struct::set, _iIndex, _pIT);
275     if (pIT != this)
276     {
277         return pIT;
278     }
279
280     if (_iIndex < getSize())
281     {
282         InternalType* pOld = m_pRealData[_iIndex];
283
284         m_pRealData[_iIndex] = const_cast<SingleStruct*>(_pIT)->clone();
285
286         if (pOld != NULL)
287         {
288             pOld->DecreaseRef();
289             pOld->killMe();
290         }
291
292         return this;
293     }
294     return NULL;
295 }
296
297 Struct* Struct::set(SingleStruct** _pIT)
298 {
299     typedef Struct* (Struct::*set_t)(SingleStruct**);
300     Struct* pIT = checkRef(this, (set_t)&Struct::set, _pIT);
301     if (pIT != this)
302     {
303         return pIT;
304     }
305
306     for (int i = 0 ; i < getSize() ; i++)
307     {
308         if (set(i, _pIT[i]) == NULL)
309         {
310             return NULL;
311         }
312     }
313     return this;
314 }
315
316 String* Struct::getFieldNames()
317 {
318     if (getSize() != 0)
319     {
320         return get(0)->getFieldNames();
321     }
322     else
323     {
324         return NULL;
325     }
326 }
327
328 bool Struct::exists(const std::wstring& _sKey)
329 {
330     if (getSize() != 0)
331     {
332         return get(0)->exists(_sKey);
333     }
334     else
335     {
336         return false;
337     }
338 }
339
340 bool Struct::operator==(const InternalType& it)
341 {
342     if (const_cast<InternalType &>(it).isStruct() == false)
343     {
344         return false;
345     }
346
347     Struct* pStr = const_cast<InternalType &>(it).getAs<Struct>();
348
349     for (int i = 0 ; i < getDims() ; i++)
350     {
351         if (pStr->getDimsArray()[i] != getDimsArray()[i])
352         {
353             return false;
354         }
355     }
356
357     for (int i = 0 ; i < getSize() ; i++)
358     {
359         if (*get(i) != *pStr->get(i))
360         {
361             return false;
362         }
363     }
364     return true;
365 }
366
367 bool Struct::operator!=(const InternalType& it)
368 {
369     return !(*this == it);
370 }
371
372 SingleStruct* Struct::getNullValue()
373 {
374     return new SingleStruct();
375 }
376
377 Struct* Struct::createEmpty(int _iDims, int* _piDims, bool /*_bComplex*/)
378 {
379     Struct* pStr = new Struct(_iDims, _piDims);
380     pStr->setCloneInCopyValue(!m_bDisableCloneInCopyValue);
381     return pStr;
382 }
383
384 SingleStruct* Struct::copyValue(SingleStruct* _pData)
385 {
386     SingleStruct* pStr = NULL;
387     if (m_bDisableCloneInCopyValue)
388     {
389         pStr = _pData;
390         pStr->IncreaseRef();
391         //std::wcout << L"copyValueWithoutClone -> " << pStr << L" : " << pStr->getRef() << std::endl;
392     }
393     else
394     {
395         pStr = _pData->clone();
396     }
397
398     return pStr;
399 }
400
401 void Struct::deleteAll()
402 {
403     for (int i = 0 ; i < getSize() ; i++)
404     {
405         m_pRealData[i]->DecreaseRef();
406         m_pRealData[i]->killMe();
407     }
408     delete[] m_pRealData;
409     m_pRealData = NULL;
410 }
411
412 void Struct::deleteImg()
413 {
414     return;
415 }
416
417 bool Struct::isEmpty()
418 {
419     if (getDims() == 2 && getRows() == 0 && getCols() == 0)
420     {
421         return true;
422     }
423     return false;
424 }
425
426 SingleStruct** Struct::allocData(int _iSize)
427 {
428     SingleStruct** pData = new SingleStruct*[_iSize];
429     for (int i = 0 ; i < _iSize ; i++)
430     {
431         pData[i] = NULL;
432     }
433     return pData;
434 }
435
436 bool Struct::subMatrixToString(std::wostringstream& /*ostr*/, int* /*_piDims*/, int /*_iDims*/)
437 {
438     return true;
439 }
440
441 Struct* Struct::addField(const std::wstring& _sKey)
442 {
443     Struct* pIT = checkRef(this, &Struct::addField, _sKey);
444     if (pIT != this)
445     {
446         return pIT;
447     }
448
449     if (getSize() == 0)
450     {
451         //change dimension to 1x1 and add field
452         resize(1, 1);
453     }
454
455     for (int i = 0 ; i < getSize() ; i++)
456     {
457         get(i)->addField(_sKey);
458     }
459
460     return this;
461 }
462
463 Struct* Struct::addFieldFront(const std::wstring& _sKey)
464 {
465     Struct* pIT = checkRef(this, &Struct::addFieldFront, _sKey);
466     if (pIT != this)
467     {
468         return pIT;
469     }
470
471     if (getSize() == 0)
472     {
473         //change dimension to 1x1 and add field
474         resize(1, 1);
475     }
476
477     for (int i = 0 ; i < getSize() ; i++)
478     {
479         get(i)->addFieldFront(_sKey);
480     }
481
482     return this;
483 }
484
485 Struct* Struct::removeField(const std::wstring& _sKey)
486 {
487     Struct* pIT = checkRef(this, &Struct::removeField, _sKey);
488     if (pIT != this)
489     {
490         return pIT;
491     }
492
493     for (int j = 0; j < getSize(); j++)
494     {
495         get(j)->removeField(_sKey);
496     }
497
498     return this;
499 }
500
501 bool Struct::toString(std::wostringstream& ostr)
502 {
503     if (getSize() == 0)
504     {
505         ostr << L"0x0 struct array with no field.";
506     }
507     else if (getSize() == 1)
508     {
509         SingleStruct* pSS =  get(0);
510         String* pwstFields =  pSS->getFieldNames();
511         if (pwstFields->getSize() == 0)
512         {
513             ostr << L"1x1 struct array with no field.";
514         }
515
516         for (int i = 0 ; i < pwstFields->getSize() ; i++)
517         {
518             std::wstring wstField(pwstFields->get(i));
519             InternalType* pIT = pSS->get(wstField);
520
521             //                ostr << L"  " << wstField << ": ";
522             ostr << L"  " << wstField << L": ";
523             ostr << pIT->toStringInLine();
524             ostr << std::endl;
525         }
526         pwstFields->killMe();;
527     }
528     else
529     {
530         ostr << L"  ";
531         for (int i = 0 ; i < m_iDims ; i++)
532         {
533             if (i > 0)
534             {
535                 ostr << L"x";
536             }
537             ostr << m_piDims[i];
538         }
539         ostr << L" struct array with ";
540
541         String* pwstFields = getFieldNames();
542         ostr <<  L"fields:" << std::endl;
543         for (int i = 0 ; i < pwstFields->getSize() ; i++)
544         {
545             ostr << L"    " << pwstFields->get(i) << std::endl;
546         }
547         pwstFields->killMe();
548     }
549
550     return true;
551 }
552
553 List* Struct::extractFieldWithoutClone(const std::wstring& _wstField)
554 {
555     List* pL = new List();
556     for (int j = 0 ; j < getSize() ; j++)
557     {
558         pL->set(j, get(j)->get(_wstField));
559     }
560
561     return pL;
562 }
563
564 typed_list Struct::extractFields(std::vector<std::wstring> _wstFields)
565 {
566     typed_list ResultList;
567
568     for (int i = 0 ; i < (int)_wstFields.size() ; i++)
569     {
570         ResultList.push_back(extractField(_wstFields[i]));
571     }
572
573     return ResultList;
574 }
575
576 InternalType * Struct::extractField(const std::wstring & wstField)
577 {
578     if (wstField == L"dims")
579     {
580         Int32 * pDims = new Int32(1, getDims());
581         for (int j = 0 ; j < getDims() ; j++)
582         {
583             pDims->set(j, getDimsArray()[j]);
584         }
585
586         return pDims;
587     }
588     else
589     {
590         if (getSize() == 1)
591         {
592             return get(0)->get(wstField);
593         }
594         else
595         {
596             List * pL = new List();
597             for (int j = 0 ; j < getSize() ; j++)
598             {
599                 pL->append(get(j)->get(wstField));
600             }
601
602             return pL;
603         }
604     }
605 }
606
607 typed_list Struct::extractFields(typed_list* _pArgs)
608 {
609     typed_list ResultList;
610
611     int iDims           = (int)_pArgs->size();
612     typed_list pArg;
613
614     int* piMaxDim       = new int[iDims];
615     int* piCountDim     = new int[iDims];
616
617     int iSeqCount = checkIndexesArguments(this, _pArgs, &pArg, piMaxDim, piCountDim);
618     delete[] piMaxDim;
619     delete[] piCountDim;
620
621     if (iSeqCount == 0)
622     {
623         //free pArg content
624         cleanIndexesArguments(_pArgs, &pArg);
625         ResultList.push_back(createEmptyDouble());
626         return ResultList;
627     }
628
629     Double* pIndex = pArg[0]->getAs<Double>();
630
631     for (int i = 0 ; i < iSeqCount ; i++)
632     {
633         int iIndex = (int)pIndex->get(i);
634
635         if (iIndex == 1)
636         {
637             //struct fields name
638             String* pS = getFieldNames();
639             String* pFields = NULL;
640             if (pS)
641             {
642                 pFields = new String(1, pS->getSize() + 2);
643                 for (int j = 0; j < pS->getSize(); j++)
644                 {
645                     pFields->set(2 + j, pS->get(j));
646                 }
647
648                 pS->killMe();
649             }
650             else
651             {
652                 pFields = new String(1, 2);
653             }
654
655             pFields->set(0, L"st");
656             pFields->set(1, L"dims");
657
658             ResultList.push_back(pFields);
659         }
660         else if (iIndex == 2)
661         {
662             //struct dims
663             Int32* pDims = new Int32(1, getDims());
664             for (int j = 0 ; j < getDims() ; j++)
665             {
666                 pDims->set(j, getDimsArray()[j]);
667             }
668
669             ResultList.push_back(pDims);
670         }
671         else if (getSize() == 0)
672         {
673             break;
674         }
675         else if (iIndex > (int)get(0)->getNumFields() + 2)
676         {
677             break;
678         }
679         else if (getSize() == 1)
680         {
681             //return elements
682             const std::vector<InternalType*> & pData = get(0)->getData();
683             ResultList.push_back(pData[iIndex - 3]->clone());
684         }
685         else
686         {
687             //return each elements for sub structs in a list
688             List* pL = new List();
689
690             for (int j = 0 ; j < getSize() ; j++)
691             {
692                 //-2 for fieldlist and dims, -1 for indexed at 0
693                 const std::vector<InternalType*> & pData = get(j)->getData();
694                 pL->append(pData[iIndex - 3]->clone());
695             }
696
697             ResultList.push_back(pL);
698         }
699     }
700
701     //free pArg content
702     cleanIndexesArguments(_pArgs, &pArg);
703     return ResultList;
704 }
705
706 Struct* Struct::resize(int _iNewRows, int _iNewCols)
707 {
708     int piDims[2] = {_iNewRows, _iNewCols};
709     return resize(piDims, 2);
710 }
711
712 Struct* Struct::resize(int* _piDims, int _iDims)
713 {
714     typedef Struct* (Struct::*resize_t)(int*, int);
715     Struct* pIT = checkRef(this, (resize_t)&Struct::resize, _piDims, _iDims);
716     if (pIT != this)
717     {
718         return pIT;
719     }
720
721     m_bDisableCloneInCopyValue = true;
722     Struct* pSRes = ArrayOf<SingleStruct*>::resize(_piDims, _iDims)->getAs<Struct>();
723     m_bDisableCloneInCopyValue = false;
724     if (pSRes)
725     {
726         // insert field(s) only in new element(s) of current struct
727         String* pFields = getFieldNames();
728         for (int iterField = 0; iterField < pFields->getSize(); iterField++)
729         {
730             for (int iterStruct = 0; iterStruct < getSize(); iterStruct++)
731             {
732                 get(iterStruct)->addField(pFields->get(iterField));
733             }
734         }
735
736         pFields->killMe();
737     }
738
739     return pSRes;
740 }
741
742 InternalType* Struct::insertWithoutClone(typed_list* _pArgs, InternalType* _pSource)
743 {
744     //std::wcout << L"insertWithoutClone start" << std::endl;
745     m_bDisableCloneInCopyValue = true;
746     InternalType* pIT = insert(_pArgs, _pSource);
747     _pSource->IncreaseRef();
748     //std::wcout << L"insertWithoutClone -> " << _pSource << L" : " << _pSource->getRef() << std::endl;
749     m_bDisableCloneInCopyValue = false;
750     //std::wcout << L"insertWithoutClone end" << std::endl;
751     return pIT;
752 }
753
754 InternalType* Struct::extractWithoutClone(typed_list* _pArgs)
755 {
756     //std::wcout << L"extractWithoutClone start" << std::endl;
757     m_bDisableCloneInCopyValue = true;
758     InternalType* pIT = extract(_pArgs);
759     m_bDisableCloneInCopyValue = false;
760     //std::wcout << L"extractWithoutClone end" << std::endl;
761     return pIT;
762 }
763
764 void Struct::setCloneInCopyValue(bool _val)
765 {
766     m_bDisableCloneInCopyValue = !_val;
767 }
768
769 void Struct::deleteData(SingleStruct* data)
770 {
771     if (data)
772     {
773         data->killMe();
774     }
775 }
776
777 Struct* Struct::createEmpty()
778 {
779     return new Struct();
780 }
781 }