867532633e32d8ba57434457ff7ba58f27b31f7d
[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     if (in.size() == 0)
179     {
180         out.push_back(this);
181         return true;
182     }
183     else if (in.size() == 1)
184     {
185         InternalType * arg = in[0];
186         std::vector<InternalType *> _out;
187         if (arg->isString())
188         {
189             std::vector<std::wstring> wstFields;
190             String * pString = arg->getAs<types::String>();
191             for (int i = 0; i < pString->getSize(); ++i)
192             {
193                 std::wstring wstField(pString->get(i));
194                 if (this->exists(wstField))
195                 {
196                     wstFields.push_back(wstField);
197                 }
198                 else
199                 {
200                     wchar_t szError[bsiz];
201                     os_swprintf(szError, bsiz, _W("Field \"%ls\" does not exists\n").c_str(), wstField.c_str());
202                     throw ast::InternalError(szError, 999, e.getLocation());
203                 }
204             }
205
206             _out = extractFields(wstFields);
207             if (_out.size() == 1)
208             {
209                 InternalType * pIT = _out[0];
210                 if (pIT->isList() && pIT->getAs<List>()->getSize() == 1)
211                 {
212                     out.push_back(pIT->getAs<List>()->get(0));
213                     return true;
214                 }
215             }
216
217             out.swap(_out);
218             return true;
219         }
220     }
221
222     return ArrayOf<SingleStruct*>::invoke(in, opt, _iRetCount, out, e);
223 }
224
225 Struct* Struct::set(int _iRows, int _iCols, SingleStruct* _pIT)
226 {
227     if (_iRows < getRows() && _iCols < getCols())
228     {
229         return set(_iCols * getRows() + _iRows, _pIT);
230     }
231     return NULL;
232 }
233
234 Struct* Struct::set(int _iRows, int _iCols, const SingleStruct* _pIT)
235 {
236     if (_iRows < getRows() && _iCols < getCols())
237     {
238         return set(_iCols * getRows() + _iRows, _pIT);
239     }
240     return NULL;
241 }
242
243 Struct* Struct::set(int _iIndex, SingleStruct* _pIT)
244 {
245     typedef Struct* (Struct::*set_t)(int, SingleStruct*);
246     Struct* pIT = checkRef(this, (set_t)&Struct::set, _iIndex, _pIT);
247     if (pIT != this)
248     {
249         return pIT;
250     }
251
252     if (_iIndex < getSize())
253     {
254         if (m_bDisableCloneInCopyValue && m_pRealData[_iIndex] == _pIT)
255         {
256             return this;
257         }
258
259         InternalType* pOld = m_pRealData[_iIndex];
260
261         m_pRealData[_iIndex] = copyValue(_pIT);
262         if (m_bDisableCloneInCopyValue == false)
263         {
264             //only in clone mode
265             m_pRealData[_iIndex]->IncreaseRef();
266         }
267
268         if (pOld != NULL)
269         {
270             pOld->DecreaseRef();
271             pOld->killMe();
272         }
273
274         return this;
275     }
276     return NULL;
277 }
278
279 Struct* Struct::set(int _iIndex, const SingleStruct* _pIT)
280 {
281     typedef Struct* (Struct::*set_t)(int, const SingleStruct*);
282     Struct* pIT = checkRef(this, (set_t)&Struct::set, _iIndex, _pIT);
283     if (pIT != this)
284     {
285         return pIT;
286     }
287
288     if (_iIndex < getSize())
289     {
290         InternalType* pOld = m_pRealData[_iIndex];
291
292         m_pRealData[_iIndex] = const_cast<SingleStruct*>(_pIT)->clone();
293
294         if (pOld != NULL)
295         {
296             pOld->DecreaseRef();
297             pOld->killMe();
298         }
299
300         return this;
301     }
302     return NULL;
303 }
304
305 Struct* Struct::set(SingleStruct** _pIT)
306 {
307     typedef Struct* (Struct::*set_t)(SingleStruct**);
308     Struct* pIT = checkRef(this, (set_t)&Struct::set, _pIT);
309     if (pIT != this)
310     {
311         return pIT;
312     }
313
314     for (int i = 0 ; i < getSize() ; i++)
315     {
316         if (set(i, _pIT[i]) == NULL)
317         {
318             return NULL;
319         }
320     }
321     return this;
322 }
323
324 String* Struct::getFieldNames()
325 {
326     if (getSize() != 0)
327     {
328         return get(0)->getFieldNames();
329     }
330     else
331     {
332         return NULL;
333     }
334 }
335
336 bool Struct::exists(const std::wstring& _sKey)
337 {
338     if (getSize() != 0)
339     {
340         return get(0)->exists(_sKey);
341     }
342     else
343     {
344         return false;
345     }
346 }
347
348 bool Struct::operator==(const InternalType& it)
349 {
350     if (const_cast<InternalType &>(it).isStruct() == false)
351     {
352         return false;
353     }
354
355     Struct* pStr = const_cast<InternalType &>(it).getAs<Struct>();
356
357     for (int i = 0 ; i < getDims() ; i++)
358     {
359         if (pStr->getDimsArray()[i] != getDimsArray()[i])
360         {
361             return false;
362         }
363     }
364
365     for (int i = 0 ; i < getSize() ; i++)
366     {
367         if (*get(i) != *pStr->get(i))
368         {
369             return false;
370         }
371     }
372     return true;
373 }
374
375 bool Struct::operator!=(const InternalType& it)
376 {
377     return !(*this == it);
378 }
379
380 SingleStruct* Struct::getNullValue()
381 {
382     return new SingleStruct();
383 }
384
385 Struct* Struct::createEmpty(int _iDims, int* _piDims, bool /*_bComplex*/)
386 {
387     Struct* pStr = new Struct(_iDims, _piDims);
388     pStr->setCloneInCopyValue(!m_bDisableCloneInCopyValue);
389     return pStr;
390 }
391
392 SingleStruct* Struct::copyValue(SingleStruct* _pData)
393 {
394     SingleStruct* pStr = NULL;
395     if (m_bDisableCloneInCopyValue)
396     {
397         pStr = _pData;
398         pStr->IncreaseRef();
399         //std::wcout << L"copyValueWithoutClone -> " << pStr << L" : " << pStr->getRef() << std::endl;
400     }
401     else
402     {
403         pStr = _pData->clone();
404     }
405
406     return pStr;
407 }
408
409 void Struct::deleteAll()
410 {
411     for (int i = 0 ; i < getSize() ; i++)
412     {
413         m_pRealData[i]->DecreaseRef();
414         m_pRealData[i]->killMe();
415     }
416     delete[] m_pRealData;
417     m_pRealData = NULL;
418 }
419
420 void Struct::deleteImg()
421 {
422     return;
423 }
424
425 bool Struct::isEmpty()
426 {
427     if (getDims() == 2 && getRows() == 0 && getCols() == 0)
428     {
429         return true;
430     }
431     return false;
432 }
433
434 SingleStruct** Struct::allocData(int _iSize)
435 {
436     SingleStruct** pData = new SingleStruct*[_iSize];
437     for (int i = 0 ; i < _iSize ; i++)
438     {
439         pData[i] = NULL;
440     }
441     return pData;
442 }
443
444 bool Struct::subMatrixToString(std::wostringstream& /*ostr*/, int* /*_piDims*/, int /*_iDims*/)
445 {
446     return true;
447 }
448
449 Struct* Struct::addField(const std::wstring& _sKey)
450 {
451     Struct* pIT = checkRef(this, &Struct::addField, _sKey);
452     if (pIT != this)
453     {
454         return pIT;
455     }
456
457     if (getSize() == 0)
458     {
459         //change dimension to 1x1 and add field
460         resize(1, 1);
461     }
462
463     for (int i = 0 ; i < getSize() ; i++)
464     {
465         get(i)->addField(_sKey);
466     }
467
468     return this;
469 }
470
471 Struct* Struct::addFieldFront(const std::wstring& _sKey)
472 {
473     Struct* pIT = checkRef(this, &Struct::addFieldFront, _sKey);
474     if (pIT != this)
475     {
476         return pIT;
477     }
478
479     if (getSize() == 0)
480     {
481         //change dimension to 1x1 and add field
482         resize(1, 1);
483     }
484
485     for (int i = 0 ; i < getSize() ; i++)
486     {
487         get(i)->addFieldFront(_sKey);
488     }
489
490     return this;
491 }
492
493 Struct* Struct::removeField(const std::wstring& _sKey)
494 {
495     Struct* pIT = checkRef(this, &Struct::removeField, _sKey);
496     if (pIT != this)
497     {
498         return pIT;
499     }
500
501     for (int j = 0; j < getSize(); j++)
502     {
503         get(j)->removeField(_sKey);
504     }
505
506     return this;
507 }
508
509 bool Struct::toString(std::wostringstream& ostr)
510 {
511     if (getSize() == 0)
512     {
513         ostr << L"0x0 struct array with no field.";
514     }
515     else if (getSize() == 1)
516     {
517         SingleStruct* pSS =  get(0);
518         String* pwstFields =  pSS->getFieldNames();
519         if (pwstFields->getSize() == 0)
520         {
521             ostr << L"1x1 struct array with no field.";
522         }
523
524         for (int i = 0 ; i < pwstFields->getSize() ; i++)
525         {
526             std::wstring wstField(pwstFields->get(i));
527             InternalType* pIT = pSS->get(wstField);
528
529             //                ostr << L"  " << wstField << ": ";
530             ostr << L"  " << wstField << L": ";
531             ostr << pIT->toStringInLine();
532             ostr << std::endl;
533         }
534         pwstFields->killMe();;
535     }
536     else
537     {
538         ostr << L"  ";
539         for (int i = 0 ; i < m_iDims ; i++)
540         {
541             if (i > 0)
542             {
543                 ostr << L"x";
544             }
545             ostr << m_piDims[i];
546         }
547         ostr << L" struct array with ";
548
549         String* pwstFields = getFieldNames();
550         ostr <<  L"fields:" << std::endl;
551         for (int i = 0 ; i < pwstFields->getSize() ; i++)
552         {
553             ostr << L"    " << pwstFields->get(i) << std::endl;
554         }
555         pwstFields->killMe();
556     }
557
558     return true;
559 }
560
561 List* Struct::extractFieldWithoutClone(const std::wstring& _wstField)
562 {
563     List* pL = new List();
564     for (int j = 0 ; j < getSize() ; j++)
565     {
566         pL->set(j, get(j)->get(_wstField));
567     }
568
569     return pL;
570 }
571
572 std::vector<InternalType*> Struct::extractFields(std::vector<std::wstring> _wstFields)
573 {
574     std::vector<InternalType*> ResultList;
575
576     for (int i = 0 ; i < (int)_wstFields.size() ; i++)
577     {
578         ResultList.push_back(extractField(_wstFields[i]));
579     }
580
581     return ResultList;
582 }
583
584 InternalType * Struct::extractField(const std::wstring & wstField)
585 {
586     if (wstField == L"dims")
587     {
588         Int32 * pDims = new Int32(1, getDims());
589         for (int j = 0 ; j < getDims() ; j++)
590         {
591             pDims->set(j, getDimsArray()[j]);
592         }
593
594         return pDims;
595     }
596     else
597     {
598         if (getSize() == 1)
599         {
600             return get(0)->get(wstField);
601         }
602         else
603         {
604             List * pL = new List();
605             for (int j = 0 ; j < getSize() ; j++)
606             {
607                 pL->append(get(j)->get(wstField));
608             }
609
610             return pL;
611         }
612     }
613 }
614
615 std::vector<InternalType*> Struct::extractFields(typed_list* _pArgs)
616 {
617     std::vector<InternalType*> ResultList;
618
619     int iDims           = (int)_pArgs->size();
620     typed_list pArg;
621
622     int* piMaxDim       = new int[iDims];
623     int* piCountDim     = new int[iDims];
624
625     int iSeqCount = checkIndexesArguments(this, _pArgs, &pArg, piMaxDim, piCountDim);
626     delete[] piMaxDim;
627     delete[] piCountDim;
628
629     if (iSeqCount == 0)
630     {
631         //free pArg content
632         cleanIndexesArguments(_pArgs, &pArg);
633         ResultList.push_back(createEmptyDouble());
634         return ResultList;
635     }
636
637     Double* pIndex = pArg[0]->getAs<Double>();
638
639     for (int i = 0 ; i < iSeqCount ; i++)
640     {
641         int iIndex = (int)pIndex->get(i);
642
643         if (iIndex == 1)
644         {
645             //struct fields name
646             String* pS = getFieldNames();
647             String* pFields = NULL;
648             if (pS)
649             {
650                 pFields = new String(1, pS->getSize() + 2);
651                 for (int j = 0; j < pS->getSize(); j++)
652                 {
653                     pFields->set(2 + j, pS->get(j));
654                 }
655
656                 pS->killMe();
657             }
658             else
659             {
660                 pFields = new String(1, 2);
661             }
662
663             pFields->set(0, L"st");
664             pFields->set(1, L"dims");
665
666             ResultList.push_back(pFields);
667         }
668         else if (iIndex == 2)
669         {
670             //struct dims
671             Int32* pDims = new Int32(1, getDims());
672             for (int j = 0 ; j < getDims() ; j++)
673             {
674                 pDims->set(j, getDimsArray()[j]);
675             }
676
677             ResultList.push_back(pDims);
678         }
679         else if (getSize() == 0)
680         {
681             break;
682         }
683         else if (iIndex > (int)get(0)->getNumFields() + 2)
684         {
685             break;
686         }
687         else if (getSize() == 1)
688         {
689             //return elements
690             const std::vector<InternalType*> & pData = get(0)->getData();
691             ResultList.push_back(pData[iIndex - 3]->clone());
692         }
693         else
694         {
695             //return each elements for sub structs in a list
696             List* pL = new List();
697
698             for (int j = 0 ; j < getSize() ; j++)
699             {
700                 //-2 for fieldlist and dims, -1 for indexed at 0
701                 const std::vector<InternalType*> & pData = get(j)->getData();
702                 pL->append(pData[iIndex - 3]->clone());
703             }
704
705             ResultList.push_back(pL);
706         }
707     }
708
709     //free pArg content
710     cleanIndexesArguments(_pArgs, &pArg);
711     return ResultList;
712 }
713
714 Struct* Struct::resize(int _iNewRows, int _iNewCols)
715 {
716     int piDims[2] = {_iNewRows, _iNewCols};
717     return resize(piDims, 2);
718 }
719
720 Struct* Struct::resize(int* _piDims, int _iDims)
721 {
722     typedef Struct* (Struct::*resize_t)(int*, int);
723     Struct* pIT = checkRef(this, (resize_t)&Struct::resize, _piDims, _iDims);
724     if (pIT != this)
725     {
726         return pIT;
727     }
728
729     m_bDisableCloneInCopyValue = true;
730     Struct* pSRes = ArrayOf<SingleStruct*>::resize(_piDims, _iDims)->getAs<Struct>();
731     m_bDisableCloneInCopyValue = false;
732     if (pSRes)
733     {
734         // insert field(s) only in new element(s) of current struct
735         String* pFields = getFieldNames();
736         for (int iterField = 0; iterField < pFields->getSize(); iterField++)
737         {
738             for (int iterStruct = 0; iterStruct < getSize(); iterStruct++)
739             {
740                 get(iterStruct)->addField(pFields->get(iterField));
741             }
742         }
743
744         pFields->killMe();
745     }
746
747     return pSRes;
748 }
749
750 InternalType* Struct::insertWithoutClone(typed_list* _pArgs, InternalType* _pSource)
751 {
752     //std::wcout << L"insertWithoutClone start" << std::endl;
753     m_bDisableCloneInCopyValue = true;
754     InternalType* pIT = insert(_pArgs, _pSource);
755     _pSource->IncreaseRef();
756     //std::wcout << L"insertWithoutClone -> " << _pSource << L" : " << _pSource->getRef() << std::endl;
757     m_bDisableCloneInCopyValue = false;
758     //std::wcout << L"insertWithoutClone end" << std::endl;
759     return pIT;
760 }
761
762 InternalType* Struct::extractWithoutClone(typed_list* _pArgs)
763 {
764     //std::wcout << L"extractWithoutClone start" << std::endl;
765     m_bDisableCloneInCopyValue = true;
766     InternalType* pIT = extract(_pArgs);
767     m_bDisableCloneInCopyValue = false;
768     //std::wcout << L"extractWithoutClone end" << std::endl;
769     return pIT;
770 }
771
772 void Struct::setCloneInCopyValue(bool _val)
773 {
774     m_bDisableCloneInCopyValue = !_val;
775 }
776
777 void Struct::deleteData(SingleStruct* data)
778 {
779     if (data)
780     {
781         data->killMe();
782     }
783 }
784
785 Struct* Struct::createEmpty()
786 {
787     return new Struct();
788 }
789 }