Improve performance for loop and insertion
[scilab.git] / scilab / modules / ast / src / cpp / types / types_tools.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
13 #include "alltypes.hxx"
14 #include "types_tools.hxx"
15 #include "overload.hxx"
16 #include "execvisitor.hxx"
17 extern "C"
18 {
19 #include "elem_common.h"
20 #include "os_string.h"
21 }
22
23 namespace types
24 {
25 template<typename T>
26 void getIndexes(T* val, std::vector<int>& vec)
27 {
28     typename T::type* p = val->get();
29     int size = val->getSize();
30     for (int i = 0; i < size; ++i)
31     {
32         vec.push_back(static_cast<int>(p[i]));
33     }
34 }
35
36 template<typename T>
37 double getIndex(T* val)
38 {
39     typename T::type* p = val->get();
40     return static_cast<double>(p[0]);
41 }
42
43 double getIndex(InternalType* val)
44 {
45     switch (val->getType())
46     {
47         //scalar
48         case InternalType::ScilabDouble:
49         {
50             return getIndex(val->getAs<Double>());
51         }
52         case InternalType::ScilabInt8:
53         {
54             return getIndex(val->getAs<Int8>());
55         }
56         case InternalType::ScilabInt16:
57         {
58             return getIndex(val->getAs<Int16>());
59         }
60         case InternalType::ScilabInt32:
61         {
62             return getIndex(val->getAs<Int32>());
63         }
64         case InternalType::ScilabInt64:
65         {
66             return getIndex(val->getAs<Int64>());
67         }
68         case InternalType::ScilabUInt8:
69         {
70             return getIndex(val->getAs<UInt8>());
71         }
72         case InternalType::ScilabUInt16:
73         {
74             return getIndex(val->getAs<UInt16>());
75         }
76         case InternalType::ScilabUInt32:
77         {
78             return getIndex(val->getAs<UInt32>());
79         }
80         case InternalType::ScilabUInt64:
81         {
82             return getIndex(val->getAs<UInt64>());
83         }
84     }
85
86     return 0;
87 }
88
89 //get only scalar index
90 bool getScalarIndex(GenericType* _pRef, typed_list* _pArgsIn, int* index)
91 {
92     //input size must be equal to ref dims
93     int dimsRef = _pRef->getDims();
94     int dimsIn = static_cast<int>(_pArgsIn->size());
95
96     //same dims and less than internal limit
97     if (dimsIn != 1 && dimsIn != dimsRef || dimsIn > MAX_DIMS)
98     {
99         return false;
100     }
101
102     int* pdims = _pRef->getDimsArray();
103     int ind[MAX_DIMS];
104     for (int i = 0; i < dimsIn; ++i)
105     {
106         InternalType* in = (*_pArgsIn)[i];
107         //input arg type must be scalar double, int8, int16, ...
108         if (in->isGenericType() && in->getAs<GenericType>()->isScalar())
109         {
110             ind[i] = static_cast<int>(getIndex(in)) - 1;
111             if (ind[i] == -1)
112             {
113                 return false;
114             }
115         }
116         else
117         {
118             //failed, so use entire process
119             return false;
120         }
121     }
122
123     int idx = ind[0];
124     if (dimsIn > 1 && idx >= pdims[0])
125     {
126         return false;
127     }
128
129     for (int i = 1; i < dimsIn; ++i)
130     {
131         if (ind[i] >= pdims[i])
132         {
133             return false;
134         }
135         idx += ind[i] * pdims[i - 1];
136     }
137
138     *index = idx;
139     return true;
140 }
141
142 static double evalute(InternalType* pIT, int sizeRef)
143 {
144     double real;
145     double img;
146     if (pIT->getId() == InternalType::IdScalarPolynom)
147     {
148         SinglePoly* pSP = pIT->getAs<Polynom>()->get()[0];
149         pSP->evaluate(sizeRef, 0, &real, &img);
150     }
151     else
152     {
153         real = getIndex(pIT);
154     }
155
156     return real;
157 }
158 //get index from implicit or colon index + scalar
159 bool getImplicitIndex(GenericType* _pRef, typed_list* _pArgsIn, std::vector<int>& index)
160 {
161     int dimsRef = _pRef->getDims();
162     int dimsIn = static_cast<int>(_pArgsIn->size());
163     bool viewAsVector = dimsIn == 1;
164     //same dims and less than internal limit
165     if (dimsIn != 1 && dimsIn != dimsRef || dimsIn > MAX_DIMS)
166     {
167         return false;
168     }
169
170     int* pdims = _pRef->getDimsArray();
171     //input arg type must be computable ( double, $, :, ... )
172     std::list<std::vector<int>> lstIdx;
173     int finalSize = 1;
174     for (int i = 0; i < dimsIn; ++i)
175     {
176         InternalType* in = (*_pArgsIn)[i];
177         if (in->isGenericType() && in->getAs<GenericType>()->isScalar())
178         {
179             int idx = static_cast<int>(getIndex(in)) - 1;
180             if (idx == -1)
181             {
182                 return false;
183             }
184
185             lstIdx.emplace_back(1, idx);
186         }
187         else if (in->isColon())
188         {
189             vector<int> idx(2);
190             idx[0] = -1;
191             idx[1] = viewAsVector ? _pRef->getSize() : pdims[i];
192             lstIdx.push_back(idx);
193             finalSize *= idx[1];
194         }
195         else if (in->isImplicitList())
196         {
197             ImplicitList* pIL = in->getAs<ImplicitList>();
198             int sizeRef = viewAsVector ? _pRef->getSize() : pdims[i];
199             double start = evalute(pIL->getStart(), sizeRef);
200             double step = evalute(pIL->getStep(), sizeRef);
201             double end = evalute(pIL->getEnd(), sizeRef);
202
203             //printf("%.2f : %.2f : %.2f\n", start, step, end);
204
205             int size = (end - start) / step + 1;
206             vector<int> idx(size);
207
208             int* pi = idx.data();
209             pi[0] = start - 1; //0-indexed
210             for (int j = 1; j < size; ++j)
211             {
212                 pi[j] = pi[j - 1] + step;
213             }
214
215             lstIdx.push_back(idx);
216             finalSize *= size;
217         }
218         else
219         {
220             return false;
221         }
222     }
223
224     index.resize(finalSize, 0);
225     //printf("finalSize : %d\n", finalSize);
226     //compute tuples
227     int previousSize = 1;
228     int currentDim = 0;
229     int previousDims = 1;
230     while (lstIdx.empty() == false)
231     {
232         std::vector<int>& v = lstIdx.front();
233         int currentSize = v.size();
234         const int* pv = v.data();
235
236         bool colon = false;
237         if (pv[0] == -1 && currentSize == 2)
238         {
239             currentSize = pv[1];
240             int occ = finalSize / (currentSize * previousSize);
241             for (int n = 0; n < occ; ++n)
242             {
243                 int idx = currentSize * previousSize * n;
244                 for (int m = 0; m < currentSize; ++m)
245                 {
246                     if (dimsIn > 1 && m >= pdims[currentDim])
247                     {
248                         return false;
249                     }
250                     int idx2 = idx + previousSize * m;
251                     int idx3 = previousDims * m;
252                     for (int j = 0; j < previousSize; ++j)
253                     {
254                         index[idx2 + j] += idx3;
255                         //printf("\tindex[%d] = %d\n", idx2 + i, previousSize * v[m]);
256                     }
257                 }
258             }
259         }
260         else
261         {
262             //printf("currentSize : %d\n", currentSize);
263             //printf("previousSize : %d\n", previousSize);
264             //printf("n : %d\n", finalSize / (currentSize * previousSize));
265             int occ = finalSize / (currentSize * previousSize);
266             for (int n = 0; n < occ; ++n)
267             {
268                 int idx = currentSize * previousSize * n;
269                 for (int m = 0; m < currentSize; ++m)
270                 {
271                     if (dimsIn > 1 && pv[m] >= pdims[currentDim])
272                     {
273                         return false;
274                     }
275                     int idx2 = idx + previousSize * m;
276                     int idx3 = previousDims * pv[m];
277                     for (int j = 0; j < previousSize; ++j)
278                     {
279                         index[idx2 + j] += idx3;
280                         //printf("\tindex[%d] = %d\n", idx2 + i, previousSize * v[m]);
281                     }
282                 }
283             }
284         }
285
286         previousSize *= currentSize;
287         previousDims *= pdims[currentDim];
288         ++currentDim;
289         //remove used vector
290         lstIdx.pop_front();
291     }
292
293     return true;
294 }
295
296 //check argument types and compute, dimensions, count of combinations, max indexes
297 int checkIndexesArguments(InternalType* _pRef, typed_list* _pArgsIn, typed_list* _pArgsOut, int* _piMaxDim, int* _piCountDim)
298 {
299     int iDims = static_cast<int>(_pArgsIn->size());
300     int iSeqCount = 1;
301     bool bUndefine = false;
302
303     for (int i = 0; i < iDims; i++)
304     {
305         bool bDeleteNeeded = false;
306         InternalType* pIT = (*_pArgsIn)[i];
307         Double *pCurrentArg = NULL;
308
309         if (pIT->isDouble())
310         {
311             pCurrentArg = pIT->getAs<Double>();
312             if (pCurrentArg->isEmpty())
313             {
314                 return 0;
315             }
316
317             if (pCurrentArg->isIdentity())
318             {
319                 //extract with eye() <=> :
320                 pIT = new Colon();
321                 bDeleteNeeded = true;
322             }
323             else if (pIT->isDeletable())
324             {
325                 // Clone pIT when this ref is equal to zero
326                 // will prevent double delete.
327                 pCurrentArg = pIT->clone()->getAs<Double>();
328             }
329
330             //check valid values neg or complex
331             if (pCurrentArg->isComplex())
332             {
333                 if (pCurrentArg->isDeletable())
334                 {
335                     pCurrentArg->killMe();
336                 }
337                 pCurrentArg = NULL;
338             }
339
340             if (pCurrentArg)
341             {
342                 int size = pCurrentArg->getSize();
343                 double* dbl = pCurrentArg->get();
344                 for (int j = 0; j < size; ++j)
345                 {
346                     if (dbl[j] < 0)
347                     {
348                         if (pCurrentArg->isDeletable())
349                         {
350                             pCurrentArg->killMe();
351                         }
352                         pCurrentArg = NULL;
353                         break;
354                     }
355                 }
356             }
357         }
358
359         //previous  if can update pIT to Colon
360         if (pIT->isColon() || pIT->isImplicitList())
361         {
362             //: or a:b:c
363             ImplicitList* pIL = pIT->getAs<ImplicitList>()->clone()->getAs<ImplicitList>();
364             if (pIL->isComputable() == false)
365             {
366                 //: or $
367                 if (_pRef == NULL)
368                 {
369                     //not enough information to compute indexes.
370                     _pArgsOut->push_back(NULL);
371                     bUndefine = true;
372                     pIL->killMe();;
373                     continue;
374                 }
375                 //evalute polynom with "MaxDim"
376                 int iMaxDim = _pRef->getAs<GenericType>()->getVarMaxDim(i, iDims);
377 #if defined(_SCILAB_DEBUGREF_)
378                 Double* pdbl = new Double(iMaxDim);
379 #else
380                 Double dbl(iMaxDim);
381 #endif
382                 if (pIL->getStart()->isPoly())
383                 {
384                     Polynom *poPoly = pIL->getStart()->getAs<types::Polynom>();
385 #if defined(_SCILAB_DEBUGREF_)
386                     pIL->setStart(poPoly->evaluate(pdbl));
387 #else
388                     pIL->setStart(poPoly->evaluate(&dbl));
389 #endif
390                 }
391                 if (pIL->getStep()->isPoly())
392                 {
393                     Polynom *poPoly = pIL->getStep()->getAs<types::Polynom>();
394 #if defined(_SCILAB_DEBUGREF_)
395                     pIL->setStep(poPoly->evaluate(pdbl));
396 #else
397                     pIL->setStep(poPoly->evaluate(&dbl));
398 #endif
399                 }
400                 if (pIL->getEnd()->isPoly())
401                 {
402                     Polynom *poPoly = pIL->getEnd()->getAs<types::Polynom>();
403 #if defined(_SCILAB_DEBUGREF_)
404                     pIL->setEnd(poPoly->evaluate(pdbl));
405 #else
406                     pIL->setEnd(poPoly->evaluate(&dbl));
407 #endif
408                 }
409
410 #if defined(_SCILAB_DEBUGREF_)
411                 pdbl->killMe();
412 #endif
413             }
414
415
416             pCurrentArg = pIL->extractFullMatrix()->getAs<Double>();
417             pIL->killMe();
418         }
419         else if (pIT->isString())
420         {
421             String* pStr = pIT->getAs<String>();
422             if (_pRef->isStruct())
423             {
424                 Struct* pStruct = _pRef->getAs<Struct>();
425
426                 if (_pArgsIn->size() != 1 || pStr->isScalar() == false)
427                 {
428                     bUndefine = true;
429                     continue;
430                 }
431
432                 wchar_t* pFieldName = pStr->get(0);
433
434                 // pCurrent arg is indexed to 1 unlike the return of "getFieldIndex"
435                 int iIndex = pStruct->get(0)->getFieldIndex(pFieldName) + 1;
436                 if (iIndex == -1)
437                 {
438                     bUndefine = true;
439                     continue;
440                 }
441
442                 pCurrentArg = new Double((double)iIndex);
443             }
444             else if (_pRef->isTList())
445             {
446                 // List can't be extract by field and MList must call overload
447                 TList* pTL = _pRef->getAs<TList>();
448                 pCurrentArg = new Double(pStr->getDims(), pStr->getDimsArray());
449                 double* pdbl = pCurrentArg->get();
450                 for (int i = 0; i < pStr->getSize(); i++)
451                 {
452                     wchar_t* pFieldName = pStr->get(i);
453                     int iIndex = pTL->getIndexFromString(pFieldName);
454                     if (iIndex == -1)
455                     {
456                         bUndefine = true;
457                         continue;
458                     }
459                     pdbl[i] = (double)(iIndex + 1);
460                 }
461             }
462             else if (_pRef->isList())
463             {
464                 bUndefine = true;
465                 break;
466             }
467             else if (_pRef->isCell())
468             {
469             }
470         }
471         else if (pIT->isPoly())
472         {
473             //$
474             Polynom* pMP = pIT->getAs<types::Polynom>();
475             int iMaxDim = 0;
476             //if pRef == NULL, use 0 insteadof, to allow a($+1) on new variable
477             if (_pRef)
478             {
479                 iMaxDim = _pRef->getAs<GenericType>()->getVarMaxDim(i, iDims);
480             }
481
482 #ifdef _SCILAB_DEBUGREF_
483             Double* pdbl = new Double(iMaxDim); // $
484             pCurrentArg = pMP->evaluate(pdbl);
485             pdbl->killMe();
486 #else
487             Double dbl(iMaxDim); // $
488             pCurrentArg = pMP->evaluate(&dbl);
489 #endif
490         }
491         else if (pIT->isBool())
492         {
493             //[T F F T F]
494             Bool *pB = pIT->getAs<types::Bool>();
495             int *piB = pB->get();
496             const int size = pB->getSize();
497
498             //find true item count
499             int iItemCount = 0;
500             for (int j = 0; j < size; j++)
501             {
502                 if (piB[j])
503                 {
504                     iItemCount++;
505                 }
506             }
507
508             //allow new Double variable
509             Double* pDbl = new Double(1, iItemCount);
510             double* pdbl = pDbl->getReal();
511
512             int j = 0;
513             for (int l = 0; l < size; l++)
514             {
515                 if (piB[l])
516                 {
517                     pdbl[j++] = l + 1;
518                 }
519             }
520             pCurrentArg = pDbl;
521         }
522
523         if (bDeleteNeeded)
524         {
525             pIT->killMe();
526         }
527
528         if (pCurrentArg)
529         {
530             const int iCountDim = pCurrentArg->getSize();
531             _piMaxDim[i] = 0;
532             for (int j = 0; j < iCountDim; j++)
533             {
534                 //checks if size < size(int)
535                 if (pCurrentArg->get(j) >= INT_MAX)
536                 {
537                     wchar_t szError[bsiz];
538                     os_swprintf(szError, bsiz, _W("variable size exceeded : less than %d expected.\n").c_str(), INT_MAX);
539                     throw ast::ScilabError(szError);
540                 }
541
542                 int d = static_cast<int>(pCurrentArg->get(j));
543                 if (d > _piMaxDim[i])
544                 {
545                     _piMaxDim[i] = d;
546                 }
547             }
548
549             iSeqCount *= iCountDim;
550             if (_piCountDim)
551             {
552                 _piCountDim[i] = iCountDim;
553             }
554         }
555         else
556         {
557             wchar_t szError[bsiz];
558             os_swprintf(szError, bsiz, _W("Invalid index.\n").c_str());
559
560             delete[] _piMaxDim;
561             delete[] _piCountDim;
562             cleanIndexesArguments(_pArgsIn, _pArgsOut);
563
564             throw ast::ScilabError(szError);
565         }
566         _pArgsOut->push_back(pCurrentArg);
567
568     }
569
570
571     //return 0 to force extract to create an empty matrix
572     if (_pRef &&  _pRef->isDouble() && _pRef->getAs<Double>()->isEmpty())
573     {
574         return 0;
575     }
576
577     //returns a negative value if at least one parameter is undefined
578     //case with : or $ for creation by insertion
579     return (!bUndefine ? iSeqCount : -iSeqCount);
580 }
581
582 void cleanIndexesArguments(typed_list* _pArgsOrig, typed_list* _pArgsNew)
583 {
584     if (_pArgsNew)
585     {
586         //free pArg content
587         for (int iArg = 0; iArg < _pArgsNew->size(); iArg++)
588         {
589             if ((*_pArgsNew)[iArg] != (*_pArgsOrig)[iArg])
590             {
591                 if ((*_pArgsNew)[iArg])
592                 {
593                     (*_pArgsNew)[iArg]->killMe();
594                 }
595             }
596         }
597
598         _pArgsNew->clear();
599     }
600 }
601
602 void getIndexesWithDims(int _iIndex, int* _piIndexes, int* _piDims, int _iDims)
603 {
604     int iMul = 1;
605     for (int i = 0; i < _iDims; i++)
606     {
607         _piIndexes[i] = (int)(_iIndex / iMul) % _piDims[i];
608         iMul *= _piDims[i];
609     }
610
611     //matrix [2,4,3]
612     //index = 12 ( 0,2,1) = 1 * 4 * 2 + 2 * 2 + 0 = 12
613     //loop 1
614     // (12 / 1) % 2 -> 0
615     //loop 2
616     // (12 / 2) % 4 -> 2
617     //loop 3
618     // (12 / 8) % 3 -> 1
619
620     //matrix [3,4,3]
621     //index = 22
622     //loop 1
623     // (22 / 1) % 3 -> 1
624     //loop 2
625     // (22 / 3) % 4 -> 3
626     //loop 3
627     // (22 / 12) % 3 -> 1
628
629     //matrix [3,4,3]
630     //index = 35
631     //loop 1
632     // (35 / 1) % 3 -> 2
633     //loop 2
634     // (35 / 3) % 4 -> 3
635     //loop 3
636     // (35 / 12) % 3 -> 2
637 }
638
639
640 int getIndexWithDims(int* _piIndexes, int* _piDims, int _iDims)
641 {
642     int idx = 0;
643     int iMult = 1;
644     for (int i = 0; i < _iDims; i++)
645     {
646         idx += _piIndexes[i] * iMult;
647         iMult *= _piDims[i];
648     }
649     return idx;
650 }
651
652 types::Function::ReturnValue VariableToString(types::InternalType* pIT, const wchar_t* wcsVarName)
653 {
654     if (pIT->hasToString() == false)
655     {
656         types::Function::ReturnValue ret = types::Function::Error;
657         //call overload %type_p
658         types::typed_list in;
659         types::typed_list out;
660         ast::ExecVisitor exec;
661
662         pIT->IncreaseRef();
663         in.push_back(pIT);
664
665         try
666         {
667             ret = Overload::generateNameAndCall(L"p", in, 1, out, &exec);
668             pIT->DecreaseRef();
669             return ret;
670         }
671         catch (ast::ScilabError &e)
672         {
673             pIT->DecreaseRef();
674             throw e;
675         }
676     }
677     else
678     {
679         std::wostringstream ostr;
680         if (pIT->isFunction())
681         {
682             pIT->getAs<types::Function>()->toString(ostr);
683         }
684         else if (pIT->isList() || pIT->isCallable())
685         {
686             ostr << wcsVarName;
687         }
688
689         //to manage lines information
690         int iLines = ConfigVariable::getConsoleLines();
691
692         bool bFinish = false;
693         do
694         {
695             //block by block
696             bFinish = pIT->toString(ostr);
697             if (ConfigVariable::isError())
698             {
699                 ConfigVariable::resetError();
700                 ostr.str(L"");
701                 return types::Function::Error;
702             }
703
704             if (bFinish == false && iLines != 0)
705             {
706                 //show message on prompt
707                 bFinish = linesmore() == 1;
708             }
709
710             scilabForcedWriteW(ostr.str().c_str());
711             ostr.str(L"");
712         }
713         while (bFinish == false);
714
715         pIT->clearPrintState();
716         return types::Function::OK;
717     }
718 }
719 }