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