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