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