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