1
/***************************************************************************
2
basic_fun.cpp - basic GDL library function
5
copyright : (C) 2002 by Marc Schellens (exceptions see below)
6
email : m_schellens@users.sf.net
8
strtok_fun, getenv_fun, tag_names_fun, stregex_fun:
9
(C) 2004 by Peter Messmer
11
***************************************************************************/
13
/***************************************************************************
15
* This program is free software; you can redistribute it and/or modify *
16
* it under the terms of the GNU General Public License as published by *
17
* the Free Software Foundation; either version 2 of the License, or *
18
* (at your option) any later version. *
20
***************************************************************************/
22
#include "includefirst.hpp"
25
// http://sourceforge.net/forum/forum.php?thread_id=3292183&forum_id=338691
32
#include <regex.h> // stregex
35
# include <crt_externs.h>
36
# define environ (*_NSGetEnviron())
41
#if defined(__FreeBSD__) || defined(__sun__) || defined(__OpenBSD__)
42
extern "C" char **environ;
45
#include "datatypes.hpp"
48
#include "dinterpreter.hpp"
49
#include "basic_pro.hpp"
50
#include "terminfo.hpp"
51
#include "typedefs.hpp"
57
#include <sys/utsname.h>
59
/* max regexp error message length */
60
#define MAX_REGEXPERR_LENGTH 80
65
using namespace antlr;
67
// assumes all parameters from pOffs till end are dim
68
void arr( EnvT* e, dimension& dim, SizeT pOffs=0)
71
int nParam=e->NParam()-pOffs;
74
e->Throw( "Incorrect number of arguments.");
76
const string BadDims="Array dimensions must be greater than 0.";
81
BaseGDL* par = e->GetParDefined( pOffs);
84
int ret = par->Scalar2index( newDim);
86
if (ret < 0) throw GDLException(BadDims);
88
if( ret > 0) { // single argument
89
if (newDim < 1) throw GDLException(BadDims);
93
if( ret == 0) { // array argument
95
static_cast<DLongGDL*>(par->Convert2(LONG, BaseGDL::COPY));
96
auto_ptr<DLongGDL> ind_guard( ind);
99
for(SizeT i =0; i < par->N_Elements(); ++i){
100
if ((*ind)[i] < 1) throw GDLException(BadDims);
105
e->Throw( "arr: should never arrive here.");
109
// max number checked in interpreter
110
SizeT endIx=nParam+pOffs;
111
for( SizeT i=pOffs; i<endIx; i++)
113
BaseGDL* par=e->GetParDefined( i);
116
int ret=par->Scalar2index( newDim);
117
if( ret < 1 || newDim == 0) throw GDLException(BadDims);
122
BaseGDL* bytarr( EnvT* e)
128
throw GDLException( "Array dimensions must be greater than 0");
130
if( e->KeywordSet(0)) return new DByteGDL(dim, BaseGDL::NOZERO);
131
return new DByteGDL(dim);
133
// catch( GDLException& ex)
135
// e->Throw( ex.getMessage());
138
BaseGDL* intarr( EnvT* e)
144
throw GDLException( "Array dimensions must be greater than 0");
146
if( e->KeywordSet(0)) return new DIntGDL(dim, BaseGDL::NOZERO);
147
return new DIntGDL(dim);
149
// catch( GDLException& ex)
151
// e->Throw( "INTARR: "+ex.getMessage());
154
BaseGDL* uintarr( EnvT* e)
160
throw GDLException( "Array dimensions must be greater than 0");
162
if( e->KeywordSet(0)) return new DUIntGDL(dim, BaseGDL::NOZERO);
163
return new DUIntGDL(dim);
165
// catch( GDLException& ex)
167
// e->Throw( "UINTARR: "+ex.getMessage());
170
BaseGDL* lonarr( EnvT* e)
176
throw GDLException( "Array dimensions must be greater than 0");
178
if( e->KeywordSet(0)) return new DLongGDL(dim, BaseGDL::NOZERO);
179
return new DLongGDL(dim);
181
catch( GDLException& ex)
183
e->Throw( "LONARR: "+ex.getMessage());
186
BaseGDL* ulonarr( EnvT* e)
192
throw GDLException( "Array dimensions must be greater than 0");
194
if( e->KeywordSet(0)) return new DULongGDL(dim, BaseGDL::NOZERO);
195
return new DULongGDL(dim);
197
catch( GDLException& ex)
199
e->Throw( "ULONARR: "+ex.getMessage());
203
BaseGDL* lon64arr( EnvT* e)
209
throw GDLException( "Array dimensions must be greater than 0");
211
if( e->KeywordSet(0)) return new DLong64GDL(dim, BaseGDL::NOZERO);
212
return new DLong64GDL(dim);
214
catch( GDLException& ex)
216
e->Throw( "LON64ARR: "+ex.getMessage());
219
BaseGDL* ulon64arr( EnvT* e)
225
throw GDLException( "Array dimensions must be greater than 0");
227
if( e->KeywordSet(0)) return new DULong64GDL(dim, BaseGDL::NOZERO);
228
return new DULong64GDL(dim);
230
catch( GDLException& ex)
232
e->Throw( "ULON64ARR: "+ex.getMessage());
235
BaseGDL* fltarr( EnvT* e)
241
throw GDLException( "Array dimensions must be greater than 0");
243
if( e->KeywordSet(0)) return new DFloatGDL(dim, BaseGDL::NOZERO);
244
return new DFloatGDL(dim);
246
catch( GDLException& ex)
248
e->Throw( "FLTARR: "+ex.getMessage());
251
BaseGDL* dblarr( EnvT* e)
257
throw GDLException( "Array dimensions must be greater than 0");
259
if( e->KeywordSet(0)) return new DDoubleGDL(dim, BaseGDL::NOZERO);
260
return new DDoubleGDL(dim);
262
catch( GDLException& ex)
264
e->Throw( "DBLARR: "+ex.getMessage());
267
BaseGDL* strarr( EnvT* e)
273
throw GDLException( "Array dimensions must be greater than 0");
275
if( e->KeywordSet(0))
276
e->Throw( "Keyword parameters not allowed in call.");
277
return new DStringGDL(dim);
279
catch( GDLException& ex)
281
e->Throw( "STRARR: "+ex.getMessage());
284
BaseGDL* complexarr( EnvT* e)
290
throw GDLException( "Array dimensions must be greater than 0");
292
if( e->KeywordSet(0)) return new DComplexGDL(dim, BaseGDL::NOZERO);
293
return new DComplexGDL(dim);
295
catch( GDLException& ex)
297
e->Throw( "COMPLEXARR: "+ex.getMessage());
300
BaseGDL* dcomplexarr( EnvT* e)
307
if( e->KeywordSet(0)) return new DComplexDblGDL(dim, BaseGDL::NOZERO);
308
return new DComplexDblGDL(dim);
310
catch( GDLException& ex)
312
e->Throw( "DCOMPLEXARR: "+ex.getMessage());
315
BaseGDL* ptrarr( EnvT* e)
321
throw GDLException( "Array dimensions must be greater than 0");
325
// if( e->KeywordSet(0))
326
// ret= new DPtrGDL(dim);//, BaseGDL::NOZERO);
328
// if( e->KeywordSet(1))
329
// ret= new DPtrGDL(dim, BaseGDL::NOZERO);
331
// return new DPtrGDL(dim);
332
if( !e->KeywordSet(1))
333
return new DPtrGDL(dim);
335
ret= new DPtrGDL(dim, BaseGDL::NOZERO);
337
SizeT nEl=ret->N_Elements();
338
SizeT sIx=e->NewHeap(nEl);
339
// #pragma omp parallel if (nEl >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl))
342
for( SizeT i=0; i<nEl; i++)
347
catch( GDLException& ex)
349
e->Throw( "PTRARR: "+ex.getMessage());
352
BaseGDL* objarr( EnvT* e)
358
throw GDLException( "Array dimensions must be greater than 0");
360
// reference counting if( e->KeywordSet(0)) return new DObjGDL(dim, BaseGDL::NOZERO);
361
return new DObjGDL(dim);
363
catch( GDLException& ex)
365
e->Throw( "OBJARR: "+ex.getMessage());
369
BaseGDL* ptr_new( EnvT* e)
371
int nParam=e->NParam();
375
// new ptr from undefined variable is allowed as well
376
BaseGDL* p= e->GetPar( 0);
379
DPtr heapID= e->NewHeap();
380
return new DPtrGDL( heapID);
383
if( e->KeywordSet(0)) // NO_COPY
385
BaseGDL** p= &e->GetPar( 0);
387
// e->Throw( "Parameter undefined: "+
388
// e->GetParString(0));
390
DPtr heapID= e->NewHeap( 1, *p);
392
return new DPtrGDL( heapID);
396
BaseGDL* p= e->GetParDefined( 0);
398
DPtr heapID= e->NewHeap( 1, p->Dup());
399
return new DPtrGDL( heapID);
404
if( e->KeywordSet(1)) // ALLOCATE_HEAP
406
DPtr heapID= e->NewHeap();
407
return new DPtrGDL( heapID);
411
return new DPtrGDL( 0); // null ptr
416
BaseGDL* ptr_valid( EnvT* e)
418
int nParam=e->NParam();
420
if( e->KeywordPresent( 1)) // COUNT
422
e->SetKW( 1, new DLongGDL( e->Interpreter()->HeapSize()));
427
return e->Interpreter()->GetAllHeap();
430
BaseGDL* p = e->GetPar( 0);
433
return new DByteGDL( 0);
436
if( e->KeywordSet( 0)) // CAST
438
DLongGDL* pL = dynamic_cast<DLongGDL*>( p);
439
auto_ptr<DLongGDL> pL_guard;
442
pL = static_cast<DLongGDL*>(p->Convert2(LONG,BaseGDL::COPY));
446
SizeT nEl = pL->N_Elements();
447
DPtrGDL* ret = new DPtrGDL( pL->Dim()); // zero
448
GDLInterpreter* interpreter = e->Interpreter();
449
for( SizeT i=0; i<nEl; ++i)
451
if( interpreter->PtrValid( (*pL)[ i]))
452
(*ret)[ i] = (*pL)[ i];
457
DPtrGDL* pPtr = dynamic_cast<DPtrGDL*>( p);
460
return new DByteGDL( p->Dim()); // zero
463
SizeT nEl = pPtr->N_Elements();
464
DByteGDL* ret = new DByteGDL( pPtr->Dim()); // zero
465
GDLInterpreter* interpreter = e->Interpreter();
466
for( SizeT i=0; i<nEl; ++i)
468
if( interpreter->PtrValid( (*pPtr)[ i]))
474
BaseGDL* obj_valid( EnvT* e)
476
int nParam=e->NParam();
478
if( e->KeywordPresent( 1)) // COUNT
480
e->SetKW( 1, new DLongGDL( e->Interpreter()->ObjHeapSize()));
485
return e->Interpreter()->GetAllObjHeap();
488
BaseGDL* p = e->GetPar( 0);
491
return new DByteGDL( 0);
494
if( e->KeywordSet( 0)) // CAST
496
DLongGDL* pL = dynamic_cast<DLongGDL*>( p);
497
auto_ptr<DLongGDL> pL_guard;
500
pL = static_cast<DLongGDL*>(p->Convert2(LONG,BaseGDL::COPY));
505
SizeT nEl = pL->N_Elements();
506
DObjGDL* ret = new DObjGDL( pL->Dim()); // zero
507
GDLInterpreter* interpreter = e->Interpreter();
508
for( SizeT i=0; i<nEl; ++i)
510
if( interpreter->ObjValid( (*pL)[ i]))
511
(*ret)[ i] = (*pL)[ i];
516
DObjGDL* pObj = dynamic_cast<DObjGDL*>( p);
519
return new DByteGDL( p->Dim()); // zero
522
SizeT nEl = pObj->N_Elements();
523
DByteGDL* ret = new DByteGDL( pObj->Dim()); // zero
524
GDLInterpreter* interpreter = e->Interpreter();
525
for( SizeT i=0; i<nEl; ++i)
527
if( interpreter->ObjValid( (*pObj)[ i]))
533
BaseGDL* obj_new( EnvT* e)
535
StackGuard<EnvStackT> guard( e->Interpreter()->CallStack());
537
int nParam=e->NParam();
541
return new DObjGDL( 0);
545
e->AssureScalarPar<DStringGDL>( 0, objName);
547
// this is a struct name -> convert to UPPERCASE
548
objName=StrUpCase(objName);
550
DStructDesc* objDesc=e->Interpreter()->GetStruct( objName, e->CallingNode());
552
DStructGDL* objStruct= new DStructGDL( objDesc, dimension());
554
DObj objID= e->NewObjHeap( 1, objStruct); // owns objStruct
556
BaseGDL* newObj = new DObjGDL( objID); // the object
559
// call INIT function
560
DFun* objINIT= objDesc->GetFun( "INIT");
563
// morph to obj environment and push it onto the stack again
564
e->PushNewEnvUD( objINIT, 1, &newObj);
566
BaseGDL* res=e->Interpreter()->call_fun( objINIT->GetTree());
568
if( res == NULL || (!res->Scalar()) || res->False())
571
return new DObjGDL( 0);
576
e->FreeObjHeap( objID); // newObj might be changed
584
BaseGDL* bindgen( EnvT* e)
590
throw GDLException( "Array dimensions must be greater than 0");
592
return new DByteGDL(dim, BaseGDL::INDGEN);
594
catch( GDLException& ex)
596
e->Throw( "BINDGEN: "+ex.getMessage());
599
// keywords not supported yet
600
BaseGDL* indgen( EnvT* e)
607
static int kwIx1 = e->KeywordIx("BYTE");
608
if (e->KeywordSet(kwIx1)){ type = BYTE; }
610
static int kwIx2 = e->KeywordIx("COMPLEX");
611
if (e->KeywordSet(kwIx2)){ type = COMPLEX; }
613
static int kwIx3 = e->KeywordIx("DCOMPLEX");
614
if (e->KeywordSet(kwIx3)){ type = COMPLEXDBL; }
616
static int kwIx4 = e->KeywordIx("DOUBLE");
617
if (e->KeywordSet(kwIx4)){ type = DOUBLE; }
619
static int kwIx5 = e->KeywordIx("FLOAT");
620
if (e->KeywordSet(kwIx5)){ type = FLOAT; }
622
static int kwIx6 = e->KeywordIx("L64");
623
if (e->KeywordSet(kwIx6)){ type = LONG64; }
625
static int kwIx7 = e->KeywordIx("LONG");
626
if (e->KeywordSet(kwIx7)){ type = LONG; }
628
static int kwIx8 = e->KeywordIx("STRING");
629
if (e->KeywordSet(kwIx8)){ type = STRING; }
631
static int kwIx9 = e->KeywordIx("UINT");
632
if (e->KeywordSet(kwIx9)){ type = UINT; }
634
static int kwIx10 = e->KeywordIx("UL64");
635
if (e->KeywordSet(kwIx10)){ type = ULONG64; }
637
static int kwIx11 = e->KeywordIx("ULONG");
638
if (e->KeywordSet(kwIx11)){ type = ULONG; }
642
// Seeing if the user passed in a TYPE code
643
static int kwIx12 = e->KeywordIx("TYPE");
644
if ( e->KeywordPresent(kwIx12)){
646
e->AssureLongScalarKW(kwIx12, temp_long);
647
type = static_cast<DType>(temp_long);
652
throw GDLException( "Array dimensions must be greater than 0");
656
case INT: return new DIntGDL(dim, BaseGDL::INDGEN);
657
case BYTE: return new DByteGDL(dim, BaseGDL::INDGEN);
658
case COMPLEX: return new DComplexGDL(dim, BaseGDL::INDGEN);
659
case COMPLEXDBL: return new DComplexDblGDL(dim, BaseGDL::INDGEN);
660
case DOUBLE: return new DDoubleGDL(dim, BaseGDL::INDGEN);
661
case FLOAT: return new DFloatGDL(dim, BaseGDL::INDGEN);
662
case LONG64: return new DLong64GDL(dim, BaseGDL::INDGEN);
663
case LONG: return new DLongGDL(dim, BaseGDL::INDGEN);
665
DULongGDL* iGen = new DULongGDL(dim, BaseGDL::INDGEN);
666
return iGen->Convert2(STRING);
668
case UINT: return new DUIntGDL(dim, BaseGDL::INDGEN);
669
case ULONG64: return new DULong64GDL(dim, BaseGDL::INDGEN);
670
case ULONG: return new DULongGDL(dim, BaseGDL::INDGEN);
672
e->Throw( "Invalid type code specified.");
676
catch( GDLException& ex)
678
e->Throw( ex.getMessage());
682
BaseGDL* uindgen( EnvT* e)
688
throw GDLException( "Array dimensions must be greater than 0");
690
return new DUIntGDL(dim, BaseGDL::INDGEN);
692
catch( GDLException& ex)
694
e->Throw( "UINDGEN: "+ex.getMessage());
697
BaseGDL* sindgen( EnvT* e)
703
throw GDLException( "Array dimensions must be greater than 0");
705
DULongGDL* iGen = new DULongGDL(dim, BaseGDL::INDGEN);
706
return iGen->Convert2( STRING);
708
catch( GDLException& ex)
710
e->Throw( "SINDGEN: "+ex.getMessage());
713
BaseGDL* lindgen( EnvT* e)
718
return new DLongGDL(dim, BaseGDL::INDGEN);
720
catch( GDLException& ex)
722
e->Throw( "LINDGEN: "+ex.getMessage());
725
BaseGDL* ulindgen( EnvT* e)
731
throw GDLException( "Array dimensions must be greater than 0");
733
return new DULongGDL(dim, BaseGDL::INDGEN);
735
catch( GDLException& ex)
737
e->Throw( "ULINDGEN: "+ex.getMessage());
740
BaseGDL* l64indgen( EnvT* e)
746
throw GDLException( "Array dimensions must be greater than 0");
748
return new DLong64GDL(dim, BaseGDL::INDGEN);
750
catch( GDLException& ex)
752
e->Throw( "L64INDGEN: "+ex.getMessage());
755
BaseGDL* ul64indgen( EnvT* e)
761
throw GDLException( "Array dimensions must be greater than 0");
763
return new DULong64GDL(dim, BaseGDL::INDGEN);
765
catch( GDLException& ex)
767
e->Throw( "UL64INDGEN: "+ex.getMessage());
770
BaseGDL* findgen( EnvT* e)
776
throw GDLException( "Array dimensions must be greater than 0");
778
return new DFloatGDL(dim, BaseGDL::INDGEN);
780
catch( GDLException& ex)
782
e->Throw( "FINDGEN: "+ex.getMessage());
785
BaseGDL* dindgen( EnvT* e)
791
throw GDLException( "Array dimensions must be greater than 0");
793
return new DDoubleGDL(dim, BaseGDL::INDGEN);
795
catch( GDLException& ex)
797
e->Throw( "DINDGEN: "+ex.getMessage());
800
BaseGDL* cindgen( EnvT* e)
806
throw GDLException( "Array dimensions must be greater than 0");
808
return new DComplexGDL(dim, BaseGDL::INDGEN);
810
catch( GDLException& ex)
812
e->Throw( "CINDGEN: "+ex.getMessage());
815
BaseGDL* dcindgen( EnvT* e)
821
throw GDLException( "Array dimensions must be greater than 0");
823
return new DComplexDblGDL(dim, BaseGDL::INDGEN);
825
catch( GDLException& ex)
827
e->Throw( "DCINDGEN: "+ex.getMessage());
831
BaseGDL* n_elements( EnvT* e)
833
SizeT nParam=e->NParam(1);
836
// e->Throw( "Incorrect number of arguments.");
838
BaseGDL* p0=e->GetPar( 0);
840
if( p0 == NULL) return new DLongGDL( 0);
842
return new DLongGDL( p0->N_Elements());
845
template< typename ComplexGDL, typename Complex, typename Float>
846
BaseGDL* complex_fun_template( EnvT* e)
848
SizeT nParam=e->NParam( 1);
853
BaseGDL* p0=e->GetParDefined( 0);
854
BaseGDL* p1=e->GetParDefined( 1);
855
auto_ptr<Float> p0Float( static_cast<Float*>
856
(p0->Convert2( Float::t,BaseGDL::COPY)));
857
auto_ptr<Float> p1Float( static_cast<Float*>
858
(p1->Convert2( Float::t,BaseGDL::COPY)));
859
if( p0Float->Rank() == 0)
861
ComplexGDL* res = new ComplexGDL( p1Float->Dim(),
864
SizeT nE=p1Float->N_Elements();
865
// #pragma omp parallel if (nE >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nE))
868
for( SizeT i=0; i<nE; i++)
870
(*res)[i]=Complex( (*p0Float)[0], (*p1Float)[i]);
875
else if( p1Float->Rank() == 0)
877
ComplexGDL* res = new ComplexGDL( p0Float->Dim(),
880
SizeT nE=p0Float->N_Elements();
881
// #pragma omp parallel if (nE >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nE))
884
for( SizeT i=0; i<nE; i++)
886
(*res)[i]=Complex( (*p0Float)[i], (*p1Float)[0]);
891
else if( p0Float->N_Elements() >= p1Float->N_Elements())
893
ComplexGDL* res = new ComplexGDL( p1Float->Dim(),
896
SizeT nE=p1Float->N_Elements();
897
// #pragma omp parallel if (nE >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nE))
900
for( SizeT i=0; i<nE; i++)
902
(*res)[i]=Complex( (*p0Float)[i], (*p1Float)[i]);
909
ComplexGDL* res = new ComplexGDL( p0Float->Dim(),
912
SizeT nE=p0Float->N_Elements();
913
// #pragma omp parallel if (nE >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nE))
916
for( SizeT i=0; i<nE; i++)
918
(*res)[i]=Complex( (*p0Float)[i], (*p1Float)[i]);
926
// SA: see tracker item 3151760
927
BaseGDL* p0 = e->GetParDefined( 0);
928
if (ComplexGDL::t == p0->Type() && e->GlobalPar(0)) return p0;
929
return p0->Convert2( ComplexGDL::t, BaseGDL::COPY);
932
else // COMPLEX( expr, offs, dim1,..,dim8)
934
BaseGDL* p0 = e->GetParDefined( 0);
935
// *** WRONG: with offs data is converted bytewise
936
auto_ptr<Float> p0Float(static_cast<Float*>
937
(p0->Convert2( Float::t,
940
e->AssureLongScalarPar( 1, offs);
945
SizeT nElCreate=dim.NDimElements();
947
SizeT nElSource=p0->N_Elements();
949
if( (offs+2*nElCreate) > nElSource)
950
e->Throw( "Specified offset to"
951
" array is out of range: "+e->GetParString(0));
953
ComplexGDL* res=new ComplexGDL( dim, BaseGDL::NOZERO);
955
// #pragma omp parallel if (nElCreate >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nElCreate))
958
for( SizeT i=0; i<nElCreate; i++)
960
SizeT srcIx=2*i+offs;
961
(*res)[i]=Complex( (*p0Float)[srcIx], (*p0Float)[srcIx+1]);
968
BaseGDL* complex_fun( EnvT* e)
970
return complex_fun_template< DComplexGDL, DComplex, DFloatGDL>( e);
972
BaseGDL* dcomplex_fun( EnvT* e)
974
return complex_fun_template< DComplexDblGDL, DComplexDbl, DDoubleGDL>( e);
977
template< class TargetClass>
978
BaseGDL* type_fun( EnvT* e)
980
SizeT nParam=e->NParam(1);
984
BaseGDL* p0=e->GetParDefined( 0);
986
assert( dynamic_cast< EnvUDT*>( e->Caller()) != NULL);
988
// type_fun( expr) just convert
989
if( static_cast< EnvUDT*>( e->Caller())->GetIOError() != NULL)
990
return p0->Convert2( TargetClass::t,
991
BaseGDL::COPY_THROWIOERROR);
992
// SA: see tracker item no. 3151760
993
else if (TargetClass::t == p0->Type() && e->GlobalPar(0))
996
return p0->Convert2( TargetClass::t, BaseGDL::COPY);
999
BaseGDL* p0=e->GetNumericParDefined( 0);
1001
// BYTE( expr, offs, dim1,..,dim8)
1003
e->AssureLongScalarPar( 1, offs);
1010
TargetClass* res=new TargetClass( dim, BaseGDL::NOZERO);
1012
SizeT nByteCreate=res->NBytes(); // net size of new data
1014
SizeT nByteSource=p0->NBytes(); // net size of src
1016
if( offs < 0 || (offs+nByteCreate) > nByteSource)
1019
e->Throw( "Specified offset to"
1020
" expression is out of range: "+e->GetParString(0));
1023
//*** POSSIBLE ERROR because of alignment here
1024
void* srcAddr = static_cast<void*>( static_cast<char*>(p0->DataAddr()) +
1026
void* dstAddr = static_cast<void*>(&(*res)[0]);
1027
memcpy( dstAddr, srcAddr, nByteCreate);
1029
// char* srcAddr = reinterpret_cast<char*>(p0->DataAddr());
1030
// char* dstAddr = reinterpret_cast<char*>(&(*res)[0]);
1031
// copy( srcAddr, srcAddr+nByteCreate, dstAddr);
1036
BaseGDL* byte_fun( EnvT* e)
1038
return type_fun<DByteGDL>( e);
1040
BaseGDL* uint_fun( EnvT* e)
1042
return type_fun<DUIntGDL>( e);
1044
BaseGDL* long_fun( EnvT* e)
1046
return type_fun<DLongGDL>( e);
1048
BaseGDL* ulong_fun( EnvT* e)
1050
return type_fun<DULongGDL>( e);
1052
BaseGDL* long64_fun( EnvT* e)
1054
return type_fun<DLong64GDL>( e);
1056
BaseGDL* ulong64_fun( EnvT* e)
1058
return type_fun<DULong64GDL>( e);
1060
BaseGDL* float_fun( EnvT* e)
1062
return type_fun<DFloatGDL>( e);
1064
BaseGDL* double_fun( EnvT* e)
1066
return type_fun<DDoubleGDL>( e);
1068
// STRING function behaves different
1069
BaseGDL* string_fun( EnvT* e)
1071
SizeT nParam=e->NParam();
1074
e->Throw( "Incorrect number of arguments.");
1076
bool printKey = e->KeywordSet( 4);
1079
// SA: handling special VMS-compatibility syntax, e.g.: string(1,'$(F)')
1080
// (if nor FORMAT neither PRINT defined, >1 parameter, last param is scalar string
1081
// which begins with "$(" or "(" but is not "()" then last param [minus "$"] is treated as FORMAT)
1082
bool vmshack = false;
1083
if (!printKey && (e->GetKW(0) == NULL) && nParam > 1)
1086
BaseGDL* par = e->GetParDefined(nParam - 1);
1087
if (par->Type() == STRING && par->Scalar())
1089
int dollar = (*static_cast<DStringGDL*>(par))[0].compare(0,2,"$(");
1090
if (dollar == 0 || ((*static_cast<DStringGDL*>(par))[0].compare(0,1,"(") == 0 && (*static_cast<DStringGDL*>(par))[0] != "()"))
1092
e->SetKeyword("FORMAT", new DStringGDL(
1093
(*static_cast<DStringGDL*>(par))[0].c_str() + (dollar == 0 ? 1 : 0)
1099
BaseGDL* format_kw = e->GetKW( 0);
1100
bool formatKey = format_kw != NULL;
1102
if (formatKey && format_kw->Type() == STRING && (*static_cast<DStringGDL*>(format_kw))[0] == "") formatKey = false;
1104
if( printKey || formatKey) // PRINT or FORMAT
1109
if( printKey) // otherwise: FORMAT -> width is ignored
1111
// for /PRINT always a terminal width of 80 is assumed
1112
width = 80;//TermWidth();
1118
e->ShiftParNumbering(1);
1120
print_os( &os, e, parOffset, width);
1123
e->ShiftParNumbering(-1);
1131
if( os.good()) buf.push_back( line);
1134
SizeT bufSize = buf.size();
1136
e->Throw( "Internal error: print buffer empty.");
1140
DStringGDL* retVal =
1141
new DStringGDL( dimension( bufSize), BaseGDL::NOZERO);
1143
for( SizeT i=0; i<bufSize; ++i)
1144
(*retVal)[ i] = buf[ i];
1149
return new DStringGDL( buf[0]);
1153
if( nParam == 1) // nParam == 1 -> conversion
1155
BaseGDL* p0 = e->GetParDefined( 0);
1156
// SA: see tracker item no. 3151760
1157
if (p0->Type() == STRING && e->GlobalPar(0)) return p0;
1158
return p0->Convert2( STRING, BaseGDL::COPY);
1160
else // concatenation
1163
for( SizeT i=0; i<nParam; ++i)
1165
BaseGDL* p = e->GetParDefined( i);
1166
DStringGDL* sP = static_cast<DStringGDL*>
1167
( p->Convert2(STRING,
1168
BaseGDL::COPY_BYTE_AS_INT));
1170
SizeT nEl = sP->N_Elements();
1171
for( SizeT e=0; e<nEl; ++e)
1175
// IDL here breaks the string into tty-width substrings
1176
return new DStringGDL( s);
1181
BaseGDL* fix_fun( EnvT* e)
1183
DIntGDL* type = e->IfDefGetKWAs<DIntGDL>( 0);
1185
int typ = (*type)[0];
1188
// SA: slow yet simple solution using BYTE->INT->BYTE conversion
1189
return (e->KeywordSet(1) && e->GetPar(0)->Type() == STRING)
1190
? type_fun<DIntGDL>( e)->Convert2(BYTE, BaseGDL::CONVERT)
1191
: type_fun<DByteGDL>( e);
1193
if (typ == 0 || typ == INT) return type_fun<DIntGDL>( e);
1194
if (typ == UINT) return type_fun<DUIntGDL>( e);
1195
if (typ == LONG) return type_fun<DLongGDL>( e);
1196
if (typ == ULONG) return type_fun<DULongGDL>( e);
1197
if (typ == LONG64) return type_fun<DLong64GDL>( e);
1198
if (typ == ULONG64) return type_fun<DULong64GDL>( e);
1199
if (typ == FLOAT) return type_fun<DFloatGDL>( e);
1200
if (typ == DOUBLE) return type_fun<DDoubleGDL>( e);
1201
if (typ == COMPLEX) return type_fun<DComplexGDL>( e);
1202
if (typ == COMPLEXDBL) return type_fun<DComplexDblGDL>( e);
1205
// SA: calling STRING() with correct parameters
1206
static int stringIx = LibFunIx("STRING");
1207
EnvT* newEnv= new EnvT(e, libFunList[stringIx], NULL);
1208
newEnv->SetNextPar(&e->GetPar(0)); // pass as global
1209
if (e->KeywordSet(1) && e->GetPar(0)->Type() == BYTE)
1210
newEnv->SetKeyword("PRINT", new DIntGDL(1));
1211
e->Interpreter()->CallStack().push_back( newEnv);
1212
return static_cast<DLibFun*>(newEnv->GetPro())->Fun()(newEnv);
1214
e->Throw( "Improper TYPE value.");
1216
return type_fun<DIntGDL>( e);
1219
BaseGDL* call_function( EnvT* e)
1221
StackGuard<EnvStackT> guard( e->Interpreter()->CallStack());
1223
int nParam=e->NParam();
1225
e->Throw( "No function specified.");
1228
e->AssureScalarPar<DStringGDL>( 0, callF);
1230
// this is a function name -> convert to UPPERCASE
1231
callF = StrUpCase( callF);
1233
// first search library funcedures
1234
int funIx=LibFunIx( callF);
1237
e->PushNewEnv( libFunList[ funIx], 1);
1240
EnvT* newEnv = static_cast<EnvT*>(e->Interpreter()->CallStack().back());
1241
return static_cast<DLibFun*>(newEnv->GetPro())->Fun()(newEnv);
1245
funIx = GDLInterpreter::GetFunIx( callF);
1247
e->PushNewEnvUD( funList[ funIx], 1);
1250
EnvUDT* newEnv = static_cast<EnvUDT*>(e->Interpreter()->CallStack().back());
1251
return e->Interpreter()->
1252
call_fun(static_cast<DSubUD*>(newEnv->GetPro())->GetTree());
1256
BaseGDL* call_method_function( EnvT* e)
1258
StackGuard<EnvStackT> guard( e->Interpreter()->CallStack());
1260
int nParam=e->NParam();
1262
e->Throw( "Name and object reference"
1263
" must be specified.");
1266
e->AssureScalarPar<DStringGDL>( 0, callP);
1268
// this is a procedure name -> convert to UPPERCASE
1269
callP = StrUpCase( callP);
1271
DStructGDL* oStruct = e->GetObjectPar( 1);
1273
DFun* method= oStruct->Desc()->GetFun( callP);
1276
e->Throw( "Method not found: "+callP);
1278
e->PushNewEnv( method, 2, &e->GetPar( 1));
1281
return e->Interpreter()->call_fun( method->GetTree());
1286
BaseGDL* execute( EnvT* e)
1288
int nParam=e->NParam( 1);
1290
bool quietCompile = false;
1293
BaseGDL* p1 = e->GetParDefined( 1);
1296
e->Throw( "Expression must be scalar in this context: "+
1297
e->GetParString(1));
1299
quietCompile = p1->True();
1302
if (e->GetParDefined(0)->Rank() != 0)
1303
e->Throw("Expression must be scalar in this context: "+e->GetParString(0));
1306
e->AssureScalarPar<DStringGDL>( 0, line);
1308
// remove current environment (own one)
1309
assert( dynamic_cast<EnvUDT*>(e->Caller()) != NULL);
1310
EnvUDT* caller = static_cast<EnvUDT*>(e->Caller());
1311
e->Interpreter()->CallStack().pop_back();
1314
istringstream istr(line+"\n");
1318
GDLLexer lexer(istr, "", caller->CompileOpt());
1319
GDLParser& parser=lexer.Parser();
1321
parser.interactive();
1323
theAST=parser.getAST();
1325
catch( GDLException& ex)
1327
if( !quietCompile) GDLInterpreter::ReportCompileError( ex);
1328
return new DIntGDL( 0);
1330
catch( ANTLRException ex)
1332
if( !quietCompile) cerr << "EXECUTE: Lexer/Parser exception: " <<
1333
ex.getMessage() << endl;
1334
return new DIntGDL( 0);
1337
if( theAST == NULL) return new DIntGDL( 1);
1342
GDLTreeParser treeParser( caller);
1344
treeParser.interactive(theAST);
1346
trAST=treeParser.getAST();
1348
catch( GDLException& ex)
1350
if( !quietCompile) GDLInterpreter::ReportCompileError( ex);
1351
return new DIntGDL( 0);
1354
catch( ANTLRException ex)
1356
if( !quietCompile) cerr << "EXECUTE: Compiler exception: " <<
1357
ex.getMessage() << endl;
1358
return new DIntGDL( 0);
1361
if( trAST == NULL) return new DIntGDL( 1);
1363
int nForLoopsIn = caller->NForLoops();
1366
ProgNodeP progAST = ProgNode::NewProgNode( trAST);
1367
auto_ptr< ProgNode> progAST_guard( progAST);
1369
int nForLoops = ProgNode::NumberForLoops( progAST, nForLoopsIn);
1370
caller->ResizeForLoops( nForLoops);
1372
progAST->setLine( e->GetLineNumber());
1374
RetCode retCode = caller->Interpreter()->execute( progAST);
1376
caller->ResizeForLoops( nForLoopsIn);
1378
if( retCode == RC_OK)
1379
return new DIntGDL( 1);
1381
return new DIntGDL( 0);
1383
catch( GDLException& ex)
1385
caller->ResizeForLoops( nForLoopsIn);
1386
// are we throwing to target environment?
1387
// if( ex.GetTargetEnv() == NULL)
1388
if( !quietCompile) cerr << "EXECUTE: " <<
1389
ex.getMessage() << endl;
1390
return new DIntGDL( 0);
1392
catch( ANTLRException ex)
1394
caller->ResizeForLoops( nForLoopsIn);
1396
if( !quietCompile) cerr << "EXECUTE: Interpreter exception: " <<
1397
ex.getMessage() << endl;
1398
return new DIntGDL( 0);
1401
return new DIntGDL( 0); // control flow cannot reach here - compiler shut up
1404
BaseGDL* assoc( EnvT* e)
1406
SizeT nParam=e->NParam( 2);
1409
e->AssureLongScalarPar( 0, lun);
1411
bool stdLun = check_lun( e, lun);
1413
e->Throw( "File unit does not allow"
1414
" this operation. Unit: "+i2s( lun));
1417
if( nParam >= 3) e->AssureLongScalarPar( 2, offset);
1419
BaseGDL* arr = e->GetParDefined( 1);
1421
if( arr->StrictScalar())
1422
e->Throw( "Scalar variable not allowed in this"
1423
" context: "+e->GetParString(1));
1425
return arr->AssocVar( lun, offset);
1428
// gdl_ naming because of weired namespace problem in MSVC
1429
BaseGDL* gdl_logical_and( EnvT* e)
1431
SizeT nParam=e->NParam();
1434
"Incorrect number of arguments.");
1436
BaseGDL* e1=e->GetParDefined( 0);//, "LOGICAL_AND");
1437
BaseGDL* e2=e->GetParDefined( 1);//, "LOGICAL_AND");
1439
ULong nEl1 = e1->N_Elements();
1440
ULong nEl2 = e2->N_Elements();
1442
Data_<SpDByte>* res;
1448
res= new Data_<SpDByte>( e2->Dim(), BaseGDL::NOZERO);
1449
// #pragma omp parallel if (nEl2 >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl2))
1452
for( SizeT i=0; i < nEl2; i++)
1453
(*res)[i] = e2->LogTrue( i) ? 1 : 0;
1458
return new Data_<SpDByte>( e2->Dim());
1461
else if( e2->Scalar())
1465
res= new Data_<SpDByte>( e1->Dim(), BaseGDL::NOZERO);
1466
// #pragma omp parallel if (nEl1 >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl1))
1469
for( SizeT i=0; i < nEl1; i++)
1470
(*res)[i] = e1->LogTrue( i) ? 1 : 0;
1475
return new Data_<SpDByte>( e1->Dim());
1478
else if( nEl2 < nEl1)
1480
res= new Data_<SpDByte>( e2->Dim(), BaseGDL::NOZERO);
1481
// #pragma omp parallel if (nEl2 >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl2))
1484
for( SizeT i=0; i < nEl2; i++)
1485
(*res)[i] = (e1->LogTrue( i) && e2->LogTrue( i)) ? 1 : 0;
1488
else // ( nEl2 >= nEl1)
1490
res= new Data_<SpDByte>( e1->Dim(), BaseGDL::NOZERO);
1491
// #pragma omp parallel if (nEl1 >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl1))
1494
for( SizeT i=0; i < nEl1; i++)
1495
(*res)[i] = (e1->LogTrue( i) && e2->LogTrue( i)) ? 1 : 0;
1501
// gdl_ naming because of weired namespace problem in MSVC
1502
BaseGDL* gdl_logical_or( EnvT* e)
1504
SizeT nParam=e->NParam();
1507
"Incorrect number of arguments.");
1509
BaseGDL* e1=e->GetParDefined( 0);//, "LOGICAL_OR");
1510
BaseGDL* e2=e->GetParDefined( 1);//, "LOGICAL_OR");
1512
ULong nEl1 = e1->N_Elements();
1513
ULong nEl2 = e2->N_Elements();
1515
Data_<SpDByte>* res;
1521
res= new Data_<SpDByte>( e2->Dim(), BaseGDL::NOZERO);
1522
// #pragma omp parallel if (nEl2 >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl2))
1525
for( SizeT i=0; i < nEl2; i++)
1531
res= new Data_<SpDByte>( e2->Dim(), BaseGDL::NOZERO);
1532
// #pragma omp parallel if (nEl2 >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl2))
1535
for( SizeT i=0; i < nEl2; i++)
1536
(*res)[i] = e2->LogTrue( i) ? 1 : 0;
1540
else if( e2->Scalar())
1544
res= new Data_<SpDByte>( e1->Dim(), BaseGDL::NOZERO);
1545
// #pragma omp parallel if (nEl1 >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl1))
1548
for( SizeT i=0; i < nEl1; i++)
1554
res= new Data_<SpDByte>( e1->Dim(), BaseGDL::NOZERO);
1555
// #pragma omp parallel if (nEl1 >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl1))
1558
for( SizeT i=0; i < nEl1; i++)
1559
(*res)[i] = e1->LogTrue( i) ? 1 : 0;
1563
else if( nEl2 < nEl1)
1565
res= new Data_<SpDByte>( e2->Dim(), BaseGDL::NOZERO);
1566
// #pragma omp parallel if (nEl2 >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl2))
1569
for( SizeT i=0; i < nEl2; i++)
1570
(*res)[i] = (e1->LogTrue( i) || e2->LogTrue( i)) ? 1 : 0;
1573
else // ( nEl2 >= nEl1)
1575
res= new Data_<SpDByte>( e1->Dim(), BaseGDL::NOZERO);
1576
// #pragma omp parallel if (nEl1 >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl1))
1579
for( SizeT i=0; i < nEl1; i++)
1580
(*res)[i] = (e1->LogTrue( i) || e2->LogTrue( i)) ? 1 : 0;
1586
BaseGDL* logical_true( EnvT* e)
1588
SizeT nParam=e->NParam();
1591
"Incorrect number of arguments.");
1593
BaseGDL* e1=e->GetParDefined( 0);//, "LOGICAL_TRUE");
1595
ULong nEl1 = e1->N_Elements();
1597
Data_<SpDByte>* res = new Data_<SpDByte>( e1->Dim(), BaseGDL::NOZERO);
1598
// #pragma omp parallel if (nEl1 >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl1))
1601
for( SizeT i=0; i < nEl1; i++)
1602
(*res)[i] = e1->LogTrue( i) ? 1 : 0;
1607
BaseGDL* replicate( EnvT* e)
1609
SizeT nParam=e->NParam();
1611
e->Throw( "Incorrect number of arguments.");
1615
BaseGDL* p0=e->GetParDefined( 0);//, "REPLICATE");
1617
e->Throw( "Expression must be a scalar in this context: "+
1618
e->GetParString(0));
1620
return p0->New( dim, BaseGDL::INIT);
1623
BaseGDL* strtrim( EnvT* e)
1625
SizeT nParam = e->NParam( 1);//, "STRTRIM");
1627
BaseGDL* p0 = e->GetPar( 0);
1630
"Variable is undefined: "+
1631
e->GetParString(0));
1632
DStringGDL* p0S = static_cast<DStringGDL*>
1633
(p0->Convert2(STRING,BaseGDL::COPY));
1638
BaseGDL* p1 = e->GetPar( 1);
1641
"Variable is undefined: "+e->GetParString(1));
1644
"Expression must be a "
1645
"scalar in this context: "+
1646
e->GetParString(1));
1647
DLongGDL* p1L = static_cast<DLongGDL*>
1648
(p1->Convert2(LONG,BaseGDL::COPY));
1654
if( mode < 0 || mode > 2)
1659
"Value of <"+ p1->TypeStr() +
1661
")> is out of allowed range.");
1665
SizeT nEl = p0S->N_Elements();
1667
if( mode == 2) // both
1669
TRACEOMP( __FILE__, __LINE__)
1670
#pragma omp parallel if ((nEl*10) >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= (nEl*10)))
1673
for( SizeT i=0; i<nEl; ++i)
1675
unsigned long first= (*p0S)[ i].find_first_not_of(" \t");
1676
if( first == (*p0S)[ i].npos)
1682
unsigned long last = (*p0S)[ i].find_last_not_of(" \t");
1683
(*p0S)[ i] = (*p0S)[ i].substr(first,last-first+1);
1688
else if( mode == 1) // leading
1690
TRACEOMP( __FILE__, __LINE__)
1691
#pragma omp parallel if ((nEl*10) >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= (nEl*10)))
1694
for( SizeT i=0; i<nEl; ++i)
1696
unsigned long first= (*p0S)[ i].find_first_not_of(" \t");
1697
if( first == (*p0S)[ i].npos)
1703
(*p0S)[ i] = (*p0S)[ i].substr(first);
1710
TRACEOMP( __FILE__, __LINE__)
1711
#pragma omp parallel if ((nEl*10) >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= (nEl*10)))
1714
for( SizeT i=0; i<nEl; ++i)
1716
unsigned long last = (*p0S)[ i].find_last_not_of(" \t");
1717
if( last == (*p0S)[ i].npos)
1723
(*p0S)[ i] = (*p0S)[ i].substr(0,last+1);
1731
BaseGDL* strcompress( EnvT* e)
1735
DStringGDL* p0S = e->GetParAs<DStringGDL>( 0);
1737
bool removeAll = e->KeywordSet(0);
1739
DStringGDL* res = new DStringGDL( p0S->Dim(), BaseGDL::NOZERO);
1741
SizeT nEl = p0S->N_Elements();
1742
TRACEOMP( __FILE__, __LINE__)
1743
#pragma omp parallel if ((nEl*10) >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= (nEl*10)))
1746
for( SizeT i=0; i<nEl; ++i)
1748
(*res)[ i] = StrCompress((*p0S)[ i], removeAll);
1754
BaseGDL* strpos( EnvT* e)
1756
SizeT nParam = e->NParam( 2);//, "STRPOS");
1758
bool reverseOffset = e->KeywordSet(0); // REVERSE_OFFSET
1759
bool reverseSearch = e->KeywordSet(1); // REVERSE_SEARCH
1761
DStringGDL* p0S = e->GetParAs<DStringGDL>( 0);
1763
DString searchString;
1764
// e->AssureScalarPar<DStringGDL>( 1, searchString);
1765
DStringGDL* sStr = e->GetParAs<DStringGDL>( 1);
1766
if( !sStr->Scalar( searchString))
1767
e->Throw( "Search string must be a scalar or one element array: "+
1768
e->GetParString( 1));
1770
unsigned long pos = string::npos;
1773
BaseGDL* p2 = e->GetParDefined(2);
1774
// if( p2 != NULL) //e->AssureLongScalarPar( 2,posDLong);
1776
const SizeT pIx = 2;
1777
BaseGDL* p = e->GetParDefined( pIx);
1778
DLongGDL* lp = static_cast<DLongGDL*>(p->Convert2( LONG, BaseGDL::COPY));
1779
auto_ptr<DLongGDL> guard_lp( lp);
1781
if( !lp->Scalar( scalar))
1782
throw GDLException("Parameter must be a scalar in this context: "+
1783
e->GetParString(pIx));
1787
DLongGDL* res = new DLongGDL( p0S->Dim(), BaseGDL::NOZERO);
1789
SizeT nSrcStr = p0S->N_Elements();
1790
TRACEOMP( __FILE__, __LINE__)
1791
#pragma omp parallel if ((nSrcStr*10) >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= (nSrcStr*10)))
1794
for( long i=0; i<nSrcStr; ++i)
1796
(*res)[ i] = StrPos((*p0S)[ i], searchString, pos,
1797
reverseOffset, reverseSearch);
1803
BaseGDL* strmid( EnvT* e)
1805
e->NParam( 2);//, "STRMID");
1807
bool reverse = e->KeywordSet(0);
1809
DStringGDL* p0S = e->GetParAs<DStringGDL>( 0);
1810
DLongGDL* p1L = e->GetParAs<DLongGDL>( 1);
1812
BaseGDL* p2 = e->GetPar( 2);
1813
DLongGDL* p2L = NULL;
1814
if( p2 != NULL) p2L = e->GetParAs<DLongGDL>( 2);
1817
bool sc1 = p1L->Scalar( scVal1);
1819
DLong scVal2 = numeric_limits<DLong>::max();
1824
sc2 = p2L->Scalar( scalar);
1831
stride = p1L->Dim( 0);
1832
if( stride != p2L->Dim( 0))
1834
"Starting offset and length arguments "
1835
"have incompatible first dimension.");
1839
// at least one scalar, p2L possibly NULL
1841
stride = p1L->Dim( 0);
1843
stride = max( p1L->Dim( 0), p2L->Dim( 0));
1845
stride = (stride > 0)? stride : 1;
1848
dimension resDim( p0S->Dim());
1852
DStringGDL* res = new DStringGDL( resDim, BaseGDL::NOZERO);
1854
SizeT nEl1 = p1L->N_Elements();
1855
SizeT nEl2 = (sc2)? 1 : p2L->N_Elements();
1857
SizeT nSrcStr = p0S->N_Elements();
1858
TRACEOMP( __FILE__, __LINE__)
1859
#pragma omp parallel if ((nSrcStr*10) >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= (nSrcStr*10))) default( shared)
1862
for( long i=0; i<nSrcStr; ++i)
1864
for( long ii=0; ii<stride; ++ii)
1866
SizeT destIx = i * stride + ii;
1867
DLong actFirst = (sc1)? scVal1 : (*p1L)[ destIx % nEl1];
1868
DLong actLen = (sc2)? scVal2 : (*p2L)[ destIx % nEl2];
1870
(*res)[ destIx] = "";//StrMid((*p0S)[ i], actFirst, actLen, reverse);
1872
(*res)[ destIx] = StrMid((*p0S)[ i], actFirst, actLen, reverse);
1879
BaseGDL* strlowcase( EnvT* e)
1881
e->NParam( 1);//, "STRLOWCASE");
1883
DStringGDL* p0S = e->GetParAs<DStringGDL>( 0);
1885
DStringGDL* res = new DStringGDL( p0S->Dim(), BaseGDL::NOZERO);
1887
SizeT nEl = p0S->N_Elements();
1888
TRACEOMP( __FILE__, __LINE__)
1889
#pragma omp parallel if ((nEl*10) >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= (nEl*10)))
1892
for( SizeT i=0; i<nEl; ++i)
1894
(*res)[ i] = StrLowCase((*p0S)[ i]);
1900
BaseGDL* strupcase( EnvT* e)
1902
e->NParam( 1);//, "STRUPCASE");
1904
DStringGDL* p0S = e->GetParAs<DStringGDL>( 0);
1906
DStringGDL* res = new DStringGDL( p0S->Dim(), BaseGDL::NOZERO);
1908
SizeT nEl = p0S->N_Elements();
1909
TRACEOMP( __FILE__, __LINE__)
1910
#pragma omp parallel if ((nEl*10) >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= (nEl*10)))
1913
for( SizeT i=0; i<nEl; ++i)
1915
(*res)[ i] = StrUpCase((*p0S)[ i]);
1921
BaseGDL* strlen( EnvT* e)
1923
e->NParam( 1);//, "STRLEN");
1925
DStringGDL* p0S = e->GetParAs<DStringGDL>( 0);
1927
DLongGDL* res = new DLongGDL( p0S->Dim(), BaseGDL::NOZERO);
1929
SizeT nEl = p0S->N_Elements();
1930
// #pragma omp parallel if (nEl >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl))
1933
for( SizeT i=0; i<nEl; ++i)
1935
(*res)[ i] = (*p0S)[ i].length();
1941
BaseGDL* strjoin( EnvT* e)
1943
SizeT nParam = e->NParam( 1);
1945
DStringGDL* p0S = e->GetParAs<DStringGDL>( 0);
1946
SizeT nEl = p0S->N_Elements();
1950
e->AssureStringScalarPar( 1, delim);
1952
bool single = e->KeywordSet( 0); // SINGLE
1956
DStringGDL* res = new DStringGDL( (*p0S)[0]);
1957
DString& scl = (*res)[0];
1959
for( SizeT i=1; i<nEl; ++i)
1960
scl += delim + (*p0S)[i];
1965
dimension resDim( p0S->Dim());
1968
SizeT stride = resDim.Stride( 1);
1972
DStringGDL* res = new DStringGDL( resDim, BaseGDL::NOZERO);
1973
for( SizeT src=0, dst=0; src<nEl; ++dst)
1975
(*res)[ dst] = (*p0S)[ src++];
1976
for(SizeT l=1; l<stride; ++l)
1977
(*res)[ dst] += delim + (*p0S)[ src++];
1983
BaseGDL* where( EnvT* e)
1985
SizeT nParam = e->NParam( 1);//, "WHERE");
1987
BaseGDL* p0 = e->GetParDefined( 0);//, "WHERE");
1989
SizeT nEl = p0->N_Elements();
1993
DLong* ixList = p0->Where( e->KeywordPresent( 0), count);
1994
ArrayGuard<DLong> guard( ixList);
1995
SizeT nCount = nEl - count;
1997
if( e->KeywordPresent( 0)) // COMPLEMENT
2001
e->SetKW( 0, new DLongGDL( -1));
2005
DLongGDL* cIxList = new DLongGDL( dimension( &nCount, 1),
2008
SizeT cIx = nEl - 1;
2009
// #pragma omp parallel if (nCount >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nCount))
2012
for( SizeT i=0; i<nCount; ++i)
2013
(*cIxList)[ i] = ixList[ cIx - i];
2014
// (*cIxList)[ i] = ixList[ --cIx];
2016
e->SetKW( 0, cIxList);
2020
if( e->KeywordPresent( 1)) // NCOMPLEMENT
2022
e->SetKW( 1, new DLongGDL( nCount));
2027
e->SetPar( 1, new DLongGDL( count));
2030
if( count == 0) return new DLongGDL( -1);
2032
return new DLongGDL( ixList, count);
2034
// DLongGDL* res = new DLongGDL( dimension( &count, 1),
2035
// BaseGDL::NOZERO);
2036
// for( SizeT i=0; i<count; ++i)
2037
// (*res)[ i] = ixList[ i];
2042
BaseGDL* n_params( EnvT* e)
2044
EnvUDT* caller = static_cast<EnvUDT*>(e->Caller());
2045
if( caller == NULL) return new DLongGDL( 0);
2046
DLong nP = caller->NParam();
2047
if( caller->IsObject())
2048
return new DLongGDL( nP-1); // "self" is not counted
2049
return new DLongGDL( nP);
2052
BaseGDL* keyword_set( EnvT* e)
2054
e->NParam( 1);//, "KEYWORD_SET");
2056
BaseGDL* p0 = e->GetPar( 0);
2057
if( p0 == NULL) return new DIntGDL( 0);
2058
if( !p0->Scalar()) return new DIntGDL( 1);
2059
if( p0->Type() == STRUCT) return new DIntGDL( 1);
2060
if( p0->LogTrue()) return new DIntGDL( 1);
2061
return new DIntGDL( 0);
2064
// passing 2nd argument by value is slightly better for float and double,
2065
// but incur some overhead for the complex class.
2066
template<class T> inline void AddOmitNaN(T& dest, T value)
2068
if (isfinite(value))
2070
// #pragma omp atomic
2074
template<class T> inline void AddOmitNaNCpx(T& dest, T value)
2076
// #pragma omp atomic
2077
dest += T(isfinite(value.real())? value.real() : 0,
2078
isfinite(value.imag())? value.imag() : 0);
2080
template<> inline void AddOmitNaN(DComplex& dest, DComplex value)
2081
{ AddOmitNaNCpx<DComplex>(dest, value); }
2082
template<> inline void AddOmitNaN(DComplexDbl& dest, DComplexDbl value)
2083
{ AddOmitNaNCpx<DComplexDbl>(dest, value); }
2085
template<class T> inline void NaN2Zero(T& value)
2086
{ if (!isfinite(value)) value = 0; }
2087
template<class T> inline void NaN2ZeroCpx(T& value)
2089
value = T(isfinite(value.real())? value.real() : 0,
2090
isfinite(value.imag())? value.imag() : 0);
2092
template<> inline void NaN2Zero(DComplex& value)
2093
{ NaN2ZeroCpx< DComplex>(value); }
2094
template<> inline void NaN2Zero(DComplexDbl& value)
2095
{ NaN2ZeroCpx< DComplexDbl>(value); }
2097
// total over all elements
2099
BaseGDL* total_template( T* src, bool omitNaN)
2101
if (!omitNaN) return new T(src->Sum());
2102
typename T::Ty sum = 0;
2103
SizeT nEl = src->N_Elements();
2104
TRACEOMP( __FILE__, __LINE__)
2105
#pragma omp parallel if (nEl >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl)) shared(sum)
2108
for ( SizeT i=0; i<nEl; ++i)
2110
AddOmitNaN(sum, (*src)[ i]);
2116
// cumulative over all dims
2117
template<typename T>
2118
BaseGDL* total_cu_template( T* res, bool omitNaN)
2120
SizeT nEl = res->N_Elements();
2123
// #pragma omp parallel if (nEl >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl))
2126
for( SizeT i=0; i<nEl; ++i)
2127
NaN2Zero((*res)[i]);
2130
for( SizeT i=1,ii=0; i<nEl; ++i,++ii)
2131
(*res)[i] += (*res)[ii];
2135
// total over one dim
2136
template< typename T>
2137
BaseGDL* total_over_dim_template( T* src,
2138
const dimension& srcDim,
2142
SizeT nEl = src->N_Elements();
2144
// get dest dim and number of summations
2145
dimension destDim = srcDim;
2146
SizeT nSum = destDim.Remove( sumDimIx);
2148
T* res = new T( destDim); // zero fields
2150
// sumStride is also the number of linear src indexing
2151
SizeT sumStride = srcDim.Stride( sumDimIx);
2152
SizeT outerStride = srcDim.Stride( sumDimIx + 1);
2153
SizeT sumLimit = nSum * sumStride;
2155
for( SizeT o=0; o < nEl; o += outerStride)
2156
for( SizeT i=0; i < sumStride; ++i)
2159
SizeT oiLimit = sumLimit + oi;
2162
for( SizeT s=oi; s<oiLimit; s += sumStride)
2163
AddOmitNaN((*res)[ rIx], (*src)[ s]);
2167
for( SizeT s=oi; s<oiLimit; s += sumStride)
2168
(*res)[ rIx] += (*src)[ s];
2175
// cumulative over one dim
2176
template< typename T>
2177
BaseGDL* total_over_dim_cu_template( T* res,
2181
SizeT nEl = res->N_Elements();
2182
const dimension& resDim = res->Dim();
2185
for( SizeT i=0; i<nEl; ++i)
2186
NaN2Zero((*res)[i]);
2188
SizeT cumStride = resDim.Stride( sumDimIx);
2189
SizeT outerStride = resDim.Stride( sumDimIx + 1);
2190
for( SizeT o=0; o < nEl; o += outerStride)
2192
SizeT cumLimit = o+outerStride;
2193
for( SizeT i=o+cumStride, ii=o; i<cumLimit; ++i, ++ii)
2194
(*res)[ i] += (*res)[ ii];
2200
BaseGDL* total( EnvT* e)
2202
SizeT nParam = e->NParam( 1);//, "TOTAL");
2204
BaseGDL* p0 = e->GetParDefined( 0);//, "TOTAL");
2206
SizeT nEl = p0->N_Elements();
2208
e->Throw( "Variable is undefined: "+e->GetParString(0));
2210
if( p0->Type() == STRING)
2211
e->Throw( "String expression not allowed "
2212
"in this context: "+e->GetParString(0));
2214
static int cumIx = e->KeywordIx( "CUMULATIVE");
2215
static int intIx = e->KeywordIx("INTEGER");
2216
static int doubleIx = e->KeywordIx( "DOUBLE");
2217
static int nanIx = e->KeywordIx( "NAN");
2218
static int preserveIx = e->KeywordIx( "PRESERVE_TYPE");
2220
bool cumulative = e->KeywordSet( cumIx);
2221
bool intRes = e->KeywordSet( intIx);
2222
bool doubleRes = e->KeywordSet( doubleIx);
2223
bool nan = e->KeywordSet( nanIx);
2224
bool preserve = e->KeywordSet( preserveIx);
2228
e->AssureLongScalarPar( 1, sumDim);
2238
case BYTE: return total_template<DByteGDL>(static_cast<DByteGDL*>(p0), false);
2239
case INT: return total_template<DIntGDL>(static_cast<DIntGDL*>(p0), false);
2240
case UINT: return total_template<DUIntGDL>(static_cast<DUIntGDL*>(p0), false);
2241
case LONG: return total_template<DLongGDL>(static_cast<DLongGDL*>(p0), false);
2242
case ULONG: return total_template<DULongGDL>(static_cast<DULongGDL*>(p0), false);
2243
case LONG64: return total_template<DLong64GDL>(static_cast<DLong64GDL*>(p0), false);
2244
case ULONG64: return total_template<DULong64GDL>(static_cast<DULong64GDL*>(p0), false);
2245
case FLOAT: return total_template<DFloatGDL>(static_cast<DFloatGDL*>(p0), nan);
2246
case DOUBLE: return total_template<DDoubleGDL>(static_cast<DDoubleGDL*>(p0), nan);
2247
case COMPLEX: return total_template<DComplexGDL>(static_cast<DComplexGDL*>(p0), nan);
2248
case COMPLEXDBL: return total_template<DComplexDblGDL>(static_cast<DComplexDblGDL*>(p0), nan);
2249
default: assert(false);
2253
// Integer parts by Erin Sheldon
2254
// In IDL total(), the INTEGER keyword takes precedence
2257
// We use LONG64 unless the input is ULONG64
2258
if ( p0->Type() == LONG64 )
2260
return total_template<DLong64GDL>
2261
( static_cast<DLong64GDL*>(p0), nan );
2263
if ( p0->Type() == ULONG64 )
2265
return total_template<DULong64GDL>
2266
( static_cast<DULong64GDL*>(p0), nan );
2270
DLong64GDL* p0L64 = static_cast<DLong64GDL*>
2271
(p0->Convert2( LONG64, BaseGDL::COPY));
2272
auto_ptr<DLong64GDL> guard( p0L64);
2273
return total_template<DLong64GDL>( p0L64, nan);
2275
} // integer results
2278
if( p0->Type() == DOUBLE)
2280
return total_template<DDoubleGDL>
2281
( static_cast<DDoubleGDL*>(p0), nan);
2283
if( p0->Type() == COMPLEXDBL)
2285
return total_template<DComplexDblGDL>
2286
( static_cast<DComplexDblGDL*>(p0), nan);
2291
if( p0->Type() == FLOAT)
2293
return total_template<DFloatGDL>
2294
( static_cast<DFloatGDL*>(p0), nan);
2296
if( p0->Type() == COMPLEX)
2298
return total_template<DComplexGDL>
2299
( static_cast<DComplexGDL*>(p0), nan);
2301
DFloatGDL* p0F = static_cast<DFloatGDL*>
2302
(p0->Convert2( FLOAT,BaseGDL::COPY));
2303
auto_ptr<DFloatGDL> guard( p0F);
2304
return total_template<DFloatGDL>( p0F, false);
2306
if( p0->Type() == COMPLEX)
2308
DComplexDblGDL* p0D = static_cast<DComplexDblGDL*>
2309
(p0->Convert2( COMPLEXDBL,BaseGDL::COPY));
2310
auto_ptr<DComplexDblGDL> p0D_guard( p0D);
2311
return total_template<DComplexDblGDL>( p0D, nan);
2314
DDoubleGDL* p0D = static_cast<DDoubleGDL*>
2315
(p0->Convert2( DOUBLE, BaseGDL::COPY));
2316
auto_ptr<DDoubleGDL> p0D_guard( p0D);
2317
return total_template<DDoubleGDL>( p0D, nan);
2325
case BYTE: return total_cu_template<DByteGDL>(static_cast<DByteGDL*>(p0)->Dup(), false);
2326
case INT: return total_cu_template<DIntGDL>(static_cast<DIntGDL*>(p0)->Dup(), false);
2327
case UINT: return total_cu_template<DUIntGDL>(static_cast<DUIntGDL*>(p0)->Dup(), false);
2328
case LONG: return total_cu_template<DLongGDL>(static_cast<DLongGDL*>(p0)->Dup(), false);
2329
case ULONG: return total_cu_template<DULongGDL>(static_cast<DULongGDL*>(p0)->Dup(), false);
2330
case LONG64: return total_cu_template<DLong64GDL>(static_cast<DLong64GDL*>(p0)->Dup(), false);
2331
case ULONG64: return total_cu_template<DULong64GDL>(static_cast<DULong64GDL*>(p0)->Dup(), false);
2332
case FLOAT: return total_cu_template<DFloatGDL>(static_cast<DFloatGDL*>(p0)->Dup(), nan);
2333
case DOUBLE: return total_cu_template<DDoubleGDL>(static_cast<DDoubleGDL*>(p0)->Dup(), nan);
2334
case COMPLEX: return total_cu_template<DComplexGDL>(static_cast<DComplexGDL*>(p0)->Dup(), nan);
2335
case COMPLEXDBL: return total_cu_template<DComplexDblGDL>(static_cast<DComplexDblGDL*>(p0)->Dup(), nan);
2336
default: assert(false);
2340
// INTEGER keyword takes precedence
2343
// We use LONG64 unless the input is ULONG64
2344
if ( p0->Type() == LONG64 )
2346
return total_cu_template<DLong64GDL>
2347
( static_cast<DLong64GDL*>(p0)->Dup(), nan );
2349
if ( p0->Type() == ULONG64 )
2351
return total_cu_template<DULong64GDL>
2352
( static_cast<DULong64GDL*>(p0)->Dup(), nan );
2355
// Convert to Long64
2356
return total_cu_template<DLong64GDL>
2357
( static_cast<DLong64GDL*>
2358
(p0->Convert2( LONG64, BaseGDL::COPY)), nan);
2360
} // integer results
2363
// special case as DOUBLE type overrides /DOUBLE
2364
if( p0->Type() == DOUBLE)
2366
return total_cu_template< DDoubleGDL>
2367
( static_cast<DDoubleGDL*>(p0)->Dup(), nan);
2369
if( p0->Type() == COMPLEXDBL)
2371
return total_cu_template< DComplexDblGDL>
2372
( static_cast<DComplexDblGDL*>(p0)->Dup(), nan);
2379
// special case for FLOAT has no advantage here
2380
if( p0->Type() == COMPLEX)
2382
return total_cu_template< DComplexGDL>
2383
( static_cast<DComplexGDL*>(p0)->Dup(), nan);
2385
return total_cu_template< DFloatGDL>
2386
( static_cast<DFloatGDL*>( p0->Convert2(FLOAT,
2387
BaseGDL::COPY)), nan);
2389
if( p0->Type() == COMPLEX)
2391
return total_cu_template< DComplexDblGDL>
2392
( static_cast<DComplexDblGDL*>(p0->Convert2( COMPLEXDBL,
2393
BaseGDL::COPY)), nan);
2395
return total_cu_template< DDoubleGDL>
2396
( static_cast<DDoubleGDL*>(p0->Convert2( DOUBLE,
2397
BaseGDL::COPY)), nan);
2401
// total over sumDim
2402
dimension srcDim = p0->Dim();
2403
SizeT srcRank = srcDim.Rank();
2405
if( sumDim < 1 || sumDim > srcRank)
2407
"Array must have "+i2s(sumDim)+
2408
" dimensions: "+e->GetParString(0));
2416
case BYTE: return total_over_dim_template<DByteGDL>(static_cast<DByteGDL*>(p0), srcDim, sumDim-1, false);
2417
case INT: return total_over_dim_template<DIntGDL>(static_cast<DIntGDL*>(p0), srcDim, sumDim-1, false);
2418
case UINT: return total_over_dim_template<DUIntGDL>(static_cast<DUIntGDL*>(p0), srcDim, sumDim-1, false);
2419
case LONG: return total_over_dim_template<DLongGDL>(static_cast<DLongGDL*>(p0), srcDim, sumDim-1, false);
2420
case ULONG: return total_over_dim_template<DULongGDL>(static_cast<DULongGDL*>(p0), srcDim, sumDim-1, false);
2421
case LONG64: return total_over_dim_template<DLong64GDL>(static_cast<DLong64GDL*>(p0), srcDim, sumDim-1, false);
2422
case ULONG64: return total_over_dim_template<DULong64GDL>(static_cast<DULong64GDL*>(p0), srcDim, sumDim-1, false);
2423
case FLOAT: return total_over_dim_template<DFloatGDL>(static_cast<DFloatGDL*>(p0), srcDim, sumDim-1, nan);
2424
case DOUBLE: return total_over_dim_template<DDoubleGDL>(static_cast<DDoubleGDL*>(p0), srcDim, sumDim-1, nan);
2425
case COMPLEX: return total_over_dim_template<DComplexGDL>(static_cast<DComplexGDL*>(p0), srcDim, sumDim-1, nan);
2426
case COMPLEXDBL: return total_over_dim_template<DComplexDblGDL>(static_cast<DComplexDblGDL*>(p0), srcDim, sumDim-1, nan);
2427
default: assert(false);
2431
// INTEGER keyword takes precedence
2434
// We use LONG64 unless the input is ULONG64
2435
if ( p0->Type() == LONG64 )
2437
return total_over_dim_template<DLong64GDL>
2438
( static_cast<DLong64GDL*>(p0), srcDim, sumDim-1, nan );
2440
if ( p0->Type() == ULONG64 )
2442
return total_over_dim_template<DULong64GDL>
2443
( static_cast<DULong64GDL*>(p0), srcDim, sumDim-1, nan );
2447
DLong64GDL* p0L64 = static_cast<DLong64GDL*>
2448
(p0->Convert2( LONG64, BaseGDL::COPY));
2450
auto_ptr<DLong64GDL> p0L64_guard( p0L64);
2451
return total_over_dim_template<DLong64GDL>
2452
( p0L64, srcDim, sumDim-1, nan);
2454
} // integer results
2457
if( p0->Type() == DOUBLE)
2459
return total_over_dim_template< DDoubleGDL>
2460
( static_cast<DDoubleGDL*>(p0), srcDim, sumDim-1, nan);
2462
if( p0->Type() == COMPLEXDBL)
2464
return total_over_dim_template< DComplexDblGDL>
2465
( static_cast<DComplexDblGDL*>(p0), srcDim, sumDim-1, nan);
2469
if( p0->Type() == FLOAT)
2471
return total_over_dim_template< DFloatGDL>
2472
( static_cast<DFloatGDL*>(p0), srcDim, sumDim-1, nan);
2474
if( p0->Type() == COMPLEX)
2476
return total_over_dim_template< DComplexGDL>
2477
( static_cast<DComplexGDL*>(p0), srcDim, sumDim-1, nan);
2479
// default for NOT /DOUBLE
2480
DFloatGDL* p0F = static_cast<DFloatGDL*>
2481
(p0->Convert2( FLOAT,BaseGDL::COPY));
2482
auto_ptr<DFloatGDL> p0F_guard( p0F);
2483
// p0F_guard.reset( p0F);
2484
return total_over_dim_template< DFloatGDL>
2485
( p0F, srcDim, sumDim-1, false);
2487
if( p0->Type() == COMPLEX)
2489
DComplexDblGDL* p0D = static_cast<DComplexDblGDL*>
2490
(p0->Convert2( COMPLEXDBL,BaseGDL::COPY));
2491
auto_ptr<DComplexDblGDL> p0D_guard( p0D);
2492
// p0D_guard.reset( p0D);
2493
return total_over_dim_template< DComplexDblGDL>
2494
( p0D, srcDim, sumDim-1, nan);
2496
// default for /DOUBLE
2497
DDoubleGDL* p0D = static_cast<DDoubleGDL*>
2498
(p0->Convert2( DOUBLE,BaseGDL::COPY));
2499
auto_ptr<DDoubleGDL> p0D_guard( p0D);
2500
//p0D_guard.reset( p0D);
2501
return total_over_dim_template< DDoubleGDL>( p0D, srcDim, sumDim-1,nan);
2509
case BYTE: return total_over_dim_cu_template<DByteGDL>(static_cast<DByteGDL*>(p0)->Dup(), sumDim-1, false);
2510
case INT: return total_over_dim_cu_template<DIntGDL>(static_cast<DIntGDL*>(p0)->Dup(), sumDim-1, false);
2511
case UINT: return total_over_dim_cu_template<DUIntGDL>(static_cast<DUIntGDL*>(p0)->Dup(), sumDim-1, false);
2512
case LONG: return total_over_dim_cu_template<DLongGDL>(static_cast<DLongGDL*>(p0)->Dup(), sumDim-1, false);
2513
case ULONG: return total_over_dim_cu_template<DULongGDL>(static_cast<DULongGDL*>(p0)->Dup(), sumDim-1, false);
2514
case LONG64: return total_over_dim_cu_template<DLong64GDL>(static_cast<DLong64GDL*>(p0)->Dup(), sumDim-1, false);
2515
case ULONG64: return total_over_dim_cu_template<DULong64GDL>(static_cast<DULong64GDL*>(p0)->Dup(), sumDim-1, false);
2516
case FLOAT: return total_over_dim_cu_template<DFloatGDL>(static_cast<DFloatGDL*>(p0)->Dup(), sumDim-1, nan);
2517
case DOUBLE: return total_over_dim_cu_template<DDoubleGDL>(static_cast<DDoubleGDL*>(p0)->Dup(), sumDim-1, nan);
2518
case COMPLEX: return total_over_dim_cu_template<DComplexGDL>(static_cast<DComplexGDL*>(p0)->Dup(), sumDim-1, nan);
2519
case COMPLEXDBL: return total_over_dim_cu_template<DComplexDblGDL>(static_cast<DComplexDblGDL*>(p0)->Dup(), sumDim-1, nan);
2520
default: assert(false);
2524
// INTEGER keyword takes precedence
2527
// We use LONG64 unless the input is ULONG64
2528
if ( p0->Type() == LONG64 )
2530
return total_over_dim_cu_template<DLong64GDL>
2531
( static_cast<DLong64GDL*>(p0)->Dup(), sumDim-1, nan );
2533
if ( p0->Type() == ULONG64 )
2535
return total_over_dim_cu_template<DULong64GDL>
2536
( static_cast<DULong64GDL*>(p0)->Dup(), sumDim-1, nan );
2539
// Convert to Long64
2540
return total_over_dim_cu_template<DLong64GDL>
2541
( static_cast<DLong64GDL*>
2542
(p0->Convert2( LONG64, BaseGDL::COPY)), sumDim-1, nan);
2544
} // integer results
2547
if( p0->Type() == DOUBLE)
2549
return total_over_dim_cu_template< DDoubleGDL>
2550
( static_cast<DDoubleGDL*>(p0)->Dup(), sumDim-1, nan);
2552
if( p0->Type() == COMPLEXDBL)
2554
return total_over_dim_cu_template< DComplexDblGDL>
2555
( static_cast<DComplexDblGDL*>(p0)->Dup(), sumDim-1, nan);
2559
// special case for FLOAT has no advantage here
2560
if( p0->Type() == COMPLEX)
2562
return total_over_dim_cu_template< DComplexGDL>
2563
( static_cast<DComplexGDL*>(p0)->Dup(), sumDim-1, nan);
2565
// default for NOT /DOUBLE
2566
return total_over_dim_cu_template< DFloatGDL>
2567
( static_cast<DFloatGDL*>( p0->Convert2( FLOAT,
2568
BaseGDL::COPY)), sumDim-1, nan);
2570
if( p0->Type() == COMPLEX)
2572
return total_over_dim_cu_template< DComplexDblGDL>
2573
( static_cast<DComplexDblGDL*>(p0->Convert2( COMPLEXDBL,
2574
BaseGDL::COPY)), sumDim-1, nan);
2576
// default for /DOUBLE
2577
return total_over_dim_cu_template< DDoubleGDL>
2578
( static_cast<DDoubleGDL*>(p0->Convert2( DOUBLE,
2579
BaseGDL::COPY)), sumDim-1, nan);
2584
// passing 2nd argument by value is slightly better for float and double,
2585
// but incur some overhead for the complex class.
2586
template<class T> inline void MultOmitNaN(T& dest, T value)
2588
if (isfinite(value))
2590
// #pragma omp atomic
2594
template<class T> inline void MultOmitNaNCpx(T& dest, T value)
2596
dest *= T(isfinite(value.real())? value.real() : 1,
2597
isfinite(value.imag())? value.imag() : 1);
2599
template<> inline void MultOmitNaN(DComplex& dest, DComplex value)
2600
{ MultOmitNaNCpx<DComplex>(dest, value); }
2601
template<> inline void MultOmitNaN(DComplexDbl& dest, DComplexDbl value)
2602
{ MultOmitNaNCpx<DComplexDbl>(dest, value); }
2604
template<class T> inline void Nan2One(T& value)
2605
{ if (!isfinite(value)) value = 1; }
2606
template<class T> inline void Nan2OneCpx(T& value)
2608
value = T(isfinite(value.real())? value.real() : 1,
2609
isfinite(value.imag())? value.imag() : 1);
2611
template<> inline void Nan2One(DComplex& value)
2612
{ Nan2OneCpx< DComplex>(value); }
2613
template<> inline void Nan2One(DComplexDbl& value)
2614
{ Nan2OneCpx< DComplexDbl>(value); }
2616
// product over all elements
2618
BaseGDL* product_template( T* src, bool omitNaN)
2620
typename T::Ty sum = 1;
2621
SizeT nEl = src->N_Elements();
2624
TRACEOMP( __FILE__, __LINE__)
2625
#pragma omp parallel if (nEl >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl)) shared(sum)
2627
#pragma omp for reduction(*:sum)
2628
for ( SizeT i=0; i<nEl; ++i)
2636
TRACEOMP( __FILE__, __LINE__)
2637
#pragma omp parallel if (nEl >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl)) shared(sum)
2639
#pragma omp for reduction(*:sum)
2640
for ( SizeT i=0; i<nEl; ++i)
2642
MultOmitNaN( sum, (*src)[ i]);
2650
BaseGDL* product_template( DComplexGDL* src, bool omitNaN)
2652
DComplexGDL::Ty sum = 1;
2653
SizeT nEl = src->N_Elements();
2656
for ( SizeT i=0; i<nEl; ++i)
2663
for ( SizeT i=0; i<nEl; ++i)
2665
MultOmitNaN( sum, (*src)[ i]);
2668
return new DComplexGDL( sum);
2672
BaseGDL* product_template( DComplexDblGDL* src, bool omitNaN)
2674
DComplexDblGDL::Ty sum = 1;
2675
SizeT nEl = src->N_Elements();
2678
for ( SizeT i=0; i<nEl; ++i)
2685
for ( SizeT i=0; i<nEl; ++i)
2687
MultOmitNaN( sum, (*src)[ i]);
2690
return new DComplexDblGDL( sum);
2693
// cumulative over all dims
2694
template<typename T>
2695
BaseGDL* product_cu_template( T* res, bool omitNaN)
2697
SizeT nEl = res->N_Elements();
2700
for( SizeT i=0; i<nEl; ++i)
2701
Nan2One( (*res)[i]);
2703
for( SizeT i=1,ii=0; i<nEl; ++i,++ii)
2704
(*res)[i] *= (*res)[ii];
2708
// product over one dim
2709
template< typename T>
2710
BaseGDL* product_over_dim_template( T* src,
2711
const dimension& srcDim,
2715
SizeT nEl = src->N_Elements();
2717
// get dest dim and number of summations
2718
dimension destDim = srcDim;
2719
SizeT nSum = destDim.Remove( sumDimIx);
2721
T* res = new T( destDim, BaseGDL::NOZERO);
2723
// sumStride is also the number of linear src indexing
2724
SizeT sumStride = srcDim.Stride( sumDimIx);
2725
SizeT outerStride = srcDim.Stride( sumDimIx + 1);
2726
SizeT sumLimit = nSum * sumStride;
2728
for( SizeT o=0; o < nEl; o += outerStride)
2729
for( SizeT i=0; i < sumStride; ++i)
2733
SizeT oiLimit = sumLimit + oi;
2736
for( SizeT s=oi; s<oiLimit; s += sumStride)
2737
MultOmitNaN((*res)[ rIx], (*src)[ s]);
2741
for( SizeT s=oi; s<oiLimit; s += sumStride)
2742
(*res)[ rIx] *= (*src)[ s];
2749
// cumulative over one dim
2750
template< typename T>
2751
BaseGDL* product_over_dim_cu_template( T* res,
2755
SizeT nEl = res->N_Elements();
2756
const dimension& resDim = res->Dim();
2759
for( SizeT i=0; i<nEl; ++i)
2762
SizeT cumStride = resDim.Stride( sumDimIx);
2763
SizeT outerStride = resDim.Stride( sumDimIx + 1);
2764
for( SizeT o=0; o < nEl; o += outerStride)
2766
SizeT cumLimit = o+outerStride;
2767
for( SizeT i=o+cumStride, ii=o; i<cumLimit; ++i, ++ii)
2768
(*res)[ i] *= (*res)[ ii];
2773
BaseGDL* product( EnvT* e)
2775
SizeT nParam = e->NParam( 1);
2777
BaseGDL* p0 = e->GetParDefined( 0);
2779
SizeT nEl = p0->N_Elements();
2781
e->Throw( "Variable is undefined: "+e->GetParString(0));
2783
if( p0->Type() == STRING)
2784
e->Throw( "String expression not allowed "
2785
"in this context: "+e->GetParString(0));
2787
static int cumIx = e->KeywordIx( "CUMULATIVE");
2788
static int nanIx = e->KeywordIx( "NAN");
2789
static int intIx = e->KeywordIx("INTEGER");
2790
static int preIx = e->KeywordIx("PRESERVE_TYPE");
2791
bool KwCumul = e->KeywordSet( cumIx);
2792
bool KwNaN = e->KeywordSet( nanIx);
2793
bool KwInt = e->KeywordSet( intIx);
2794
bool KwPre = e->KeywordSet( preIx);
2799
e->AssureLongScalarPar( 1, sumDim);
2807
case BYTE: return product_template<DByteGDL>(static_cast<DByteGDL*>(p0), nanInt);
2808
case INT: return product_template<DIntGDL>(static_cast<DIntGDL*>(p0), nanInt);
2809
case UINT: return product_template<DUIntGDL>(static_cast<DUIntGDL*>(p0), nanInt);
2810
case LONG: return product_template<DLongGDL>(static_cast<DLongGDL*>(p0), nanInt);
2811
case ULONG: return product_template<DULongGDL>(static_cast<DULongGDL*>(p0), nanInt);
2812
case LONG64: return product_template<DLong64GDL>(static_cast<DLong64GDL*>(p0), nanInt);
2813
case ULONG64: return product_template<DULong64GDL>(static_cast<DULong64GDL*>(p0), nanInt);
2814
case FLOAT: return product_template<DFloatGDL>(static_cast<DFloatGDL*>(p0), KwNaN);
2815
case DOUBLE: return product_template<DDoubleGDL>(static_cast<DDoubleGDL*>(p0), KwNaN);
2816
case COMPLEX: return product_template<DComplexGDL>(static_cast<DComplexGDL*>(p0), KwNaN);
2817
case COMPLEXDBL: return product_template<DComplexDblGDL>(static_cast<DComplexDblGDL*>(p0), KwNaN);
2818
default: assert(false);
2822
// Integer parts derivated from Total code by Erin Sheldon
2823
// In IDL PRODUCT(), the INTEGER keyword takes precedence
2825
// We use LONG64 unless the input is ULONG64
2826
if ((p0->Type() == LONG64) && (!KwNaN)) {
2827
return product_template<DLong64GDL>
2828
( static_cast<DLong64GDL*>(p0), nanInt );
2830
if ((p0->Type() == ULONG64) && (!KwNaN)) {
2831
return product_template<DULong64GDL>
2832
(static_cast<DULong64GDL*>(p0), nanInt );
2835
// Convert to Long64
2836
DLong64GDL* p0L64 = static_cast<DLong64GDL*>
2837
(p0->Convert2( LONG64, BaseGDL::COPY));
2838
auto_ptr<DLong64GDL> guard( p0L64);
2840
DFloatGDL* p0f = static_cast<DFloatGDL*>
2841
(p0->Convert2( FLOAT, BaseGDL::COPY));
2842
auto_ptr<DFloatGDL> guard( p0f);
2843
for( SizeT i=0; i<nEl; ++i) {
2844
if (!isfinite((*p0f)[i])) (*p0L64)[i]=1;
2847
return product_template<DLong64GDL>( p0L64, nanInt);
2848
} // integer results
2850
if( p0->Type() == DOUBLE) {
2851
return product_template<DDoubleGDL>
2852
( static_cast<DDoubleGDL*>(p0), KwNaN);
2854
if( p0->Type() == COMPLEXDBL) {
2855
return product_template<DComplexDblGDL>
2856
( static_cast<DComplexDblGDL*>(p0), KwNaN);
2858
if( p0->Type() == COMPLEX) {
2859
DComplexDblGDL* p0D = static_cast<DComplexDblGDL*>
2860
(p0->Convert2( COMPLEXDBL,BaseGDL::COPY));
2861
auto_ptr<DComplexDblGDL> p0D_guard( p0D);
2862
//p0D_guard.reset( p0D);
2863
return product_template<DComplexDblGDL>( p0D, KwNaN);
2866
DDoubleGDL* p0D = static_cast<DDoubleGDL*>
2867
(p0->Convert2( DOUBLE, BaseGDL::COPY));
2868
auto_ptr<DDoubleGDL> p0D_guard( p0D);
2869
// p0D_guard.reset( p0D);
2870
return product_template<DDoubleGDL>( p0D, KwNaN);
2879
case BYTE: return product_cu_template<DByteGDL>(static_cast<DByteGDL*>(p0)->Dup(), nanInt);
2880
case INT: return product_cu_template<DIntGDL>(static_cast<DIntGDL*>(p0)->Dup(), nanInt);
2881
case UINT: return product_cu_template<DUIntGDL>(static_cast<DUIntGDL*>(p0)->Dup(), nanInt);
2882
case LONG: return product_cu_template<DLongGDL>(static_cast<DLongGDL*>(p0)->Dup(), nanInt);
2883
case ULONG: return product_cu_template<DULongGDL>(static_cast<DULongGDL*>(p0)->Dup(), nanInt);
2884
case LONG64: return product_cu_template<DLong64GDL>(static_cast<DLong64GDL*>(p0)->Dup(), nanInt);
2885
case ULONG64: return product_cu_template<DULong64GDL>(static_cast<DULong64GDL*>(p0)->Dup(), nanInt);
2886
case FLOAT: return product_cu_template<DFloatGDL>(static_cast<DFloatGDL*>(p0)->Dup(), KwNaN);
2887
case DOUBLE: return product_cu_template<DDoubleGDL>(static_cast<DDoubleGDL*>(p0)->Dup(), KwNaN);
2888
case COMPLEX: return product_cu_template<DComplexGDL>(static_cast<DComplexGDL*>(p0)->Dup(), KwNaN);
2889
case COMPLEXDBL: return product_cu_template<DComplexDblGDL>(static_cast<DComplexDblGDL*>(p0)->Dup(), KwNaN);
2890
default: assert(false);
2894
// Integer parts derivated from Total code by Erin Sheldon
2895
// In IDL PRODUCT(), the INTEGER keyword takes precedence
2897
// We use LONG64 unless the input is ULONG64
2898
if ((p0->Type() == LONG64) && (!KwNaN)) {
2899
return product_cu_template<DLong64GDL>
2900
( static_cast<DLong64GDL*>(p0)->Dup(), nanInt);
2902
if ((p0->Type() == ULONG64) && (!KwNaN)) {
2903
return product_cu_template<DULong64GDL>
2904
( static_cast<DULong64GDL*>(p0)->Dup(), nanInt);
2906
// Convert to Long64
2907
DLong64GDL* p0L64 = static_cast<DLong64GDL*>
2908
(p0->Convert2( LONG64, BaseGDL::COPY));
2909
auto_ptr<DLong64GDL> guard( p0L64);
2911
DFloatGDL* p0f = static_cast<DFloatGDL*>
2912
(p0->Convert2( FLOAT, BaseGDL::COPY));
2913
auto_ptr<DFloatGDL> guard( p0f);
2914
for( SizeT i=0; i<nEl; ++i) {
2915
if (!isfinite((*p0f)[i])) (*p0L64)[i]=1;
2918
return product_cu_template<DLong64GDL>
2919
((p0L64)->Dup(), nanInt);
2920
} // integer results
2922
// special case as DOUBLE type overrides /DOUBLE
2923
if (p0->Type() == DOUBLE) {
2924
return product_cu_template< DDoubleGDL>
2925
( static_cast<DDoubleGDL*>(p0)->Dup(), KwNaN);
2927
if (p0->Type() == COMPLEXDBL) {
2928
return product_cu_template< DComplexDblGDL>
2929
( static_cast<DComplexDblGDL*>(p0)->Dup(), KwNaN);
2931
if (p0->Type() == COMPLEX) {
2932
return product_cu_template< DComplexDblGDL>
2933
( static_cast<DComplexDblGDL*>
2934
(p0->Convert2( COMPLEXDBL, BaseGDL::COPY)), KwNaN);
2936
return product_cu_template< DDoubleGDL>
2937
( static_cast<DDoubleGDL*>
2938
(p0->Convert2( DOUBLE, BaseGDL::COPY)), KwNaN);
2942
// product over sumDim
2943
dimension srcDim = p0->Dim();
2944
SizeT srcRank = srcDim.Rank();
2946
if( sumDim < 1 || sumDim > srcRank)
2947
e->Throw( "Array must have "+i2s(sumDim)+
2948
" dimensions: "+e->GetParString(0));
2956
case BYTE: return product_over_dim_template<DByteGDL>(static_cast<DByteGDL*>(p0), srcDim, sumDim-1, nanInt);
2957
case INT: return product_over_dim_template<DIntGDL>(static_cast<DIntGDL*>(p0), srcDim, sumDim-1, nanInt);
2958
case UINT: return product_over_dim_template<DUIntGDL>(static_cast<DUIntGDL*>(p0), srcDim, sumDim-1, nanInt);
2959
case LONG: return product_over_dim_template<DLongGDL>(static_cast<DLongGDL*>(p0), srcDim, sumDim-1, nanInt);
2960
case ULONG: return product_over_dim_template<DULongGDL>(static_cast<DULongGDL*>(p0), srcDim, sumDim-1, nanInt);
2961
case LONG64: return product_over_dim_template<DLong64GDL>(static_cast<DLong64GDL*>(p0), srcDim, sumDim-1, nanInt);
2962
case ULONG64: return product_over_dim_template<DULong64GDL>(static_cast<DULong64GDL*>(p0), srcDim, sumDim-1, nanInt);
2963
case FLOAT: return product_over_dim_template<DFloatGDL>(static_cast<DFloatGDL*>(p0), srcDim, sumDim-1, KwNaN);
2964
case DOUBLE: return product_over_dim_template<DDoubleGDL>(static_cast<DDoubleGDL*>(p0), srcDim, sumDim-1, KwNaN);
2965
case COMPLEX: return product_over_dim_template<DComplexGDL>(static_cast<DComplexGDL*>(p0), srcDim, sumDim-1, KwNaN);
2966
case COMPLEXDBL: return product_over_dim_template<DComplexDblGDL>(static_cast<DComplexDblGDL*>(p0), srcDim, sumDim-1, KwNaN);
2967
default: assert(false);
2971
// Integer parts derivated from Total code by Erin Sheldon
2972
// In IDL PRODUCT(), the INTEGER keyword takes precedence
2974
// We use LONG64 unless the input is ULONG64
2975
if ((p0->Type() == LONG64 ) && (!KwNaN)) {
2976
return product_over_dim_template<DLong64GDL>
2977
( static_cast<DLong64GDL*>(p0), srcDim, sumDim-1, nanInt);
2979
if ((p0->Type() == ULONG64) && (!KwNaN)) {
2980
return product_over_dim_template<DULong64GDL>
2981
( static_cast<DULong64GDL*>(p0), srcDim, sumDim-1, nanInt);
2985
DLong64GDL* p0L64 = static_cast<DLong64GDL*>
2986
(p0->Convert2( LONG64, BaseGDL::COPY));
2987
auto_ptr<DLong64GDL> guard( p0L64);
2989
DFloatGDL* p0f = static_cast<DFloatGDL*>
2990
(p0->Convert2( FLOAT, BaseGDL::COPY));
2991
auto_ptr<DFloatGDL> guard( p0f);
2992
for( SizeT i=0; i<nEl; ++i) {
2993
if (!isfinite((*p0f)[i])) (*p0L64)[i]=1;
2996
return product_over_dim_template<DLong64GDL>
2997
( p0L64, srcDim, sumDim-1, nanInt);
2998
} // integer results
3000
if( p0->Type() == DOUBLE) {
3001
return product_over_dim_template< DDoubleGDL>
3002
( static_cast<DDoubleGDL*>(p0), srcDim, sumDim-1, KwNaN);
3004
if( p0->Type() == COMPLEXDBL) {
3005
return product_over_dim_template< DComplexDblGDL>
3006
( static_cast<DComplexDblGDL*>(p0), srcDim, sumDim-1, KwNaN);
3008
if( p0->Type() == COMPLEX) {
3009
DComplexDblGDL* p0D = static_cast<DComplexDblGDL*>
3010
(p0->Convert2( COMPLEXDBL,BaseGDL::COPY));
3011
auto_ptr<DComplexDblGDL> p0D_guard( p0D);
3012
// p0D_guard.reset( p0D);
3013
return product_over_dim_template< DComplexDblGDL>
3014
( p0D, srcDim, sumDim-1, KwNaN);
3017
DDoubleGDL* p0D = static_cast<DDoubleGDL*>
3018
(p0->Convert2( DOUBLE,BaseGDL::COPY));
3019
auto_ptr<DDoubleGDL> p0D_guard( p0D);
3020
//p0D_guard.reset( p0D);
3021
return product_over_dim_template< DDoubleGDL>
3022
( p0D, srcDim, sumDim-1,KwNaN);
3031
case BYTE: return product_over_dim_cu_template<DByteGDL>(static_cast<DByteGDL*>(p0)->Dup(), sumDim-1, nanInt);
3032
case INT: return product_over_dim_cu_template<DIntGDL>(static_cast<DIntGDL*>(p0)->Dup(), sumDim-1, nanInt);
3033
case UINT: return product_over_dim_cu_template<DUIntGDL>(static_cast<DUIntGDL*>(p0)->Dup(), sumDim-1, nanInt);
3034
case LONG: return product_over_dim_cu_template<DLongGDL>(static_cast<DLongGDL*>(p0)->Dup(), sumDim-1, nanInt);
3035
case ULONG: return product_over_dim_cu_template<DULongGDL>(static_cast<DULongGDL*>(p0)->Dup(), sumDim-1, nanInt);
3036
case LONG64: return product_over_dim_cu_template<DLong64GDL>(static_cast<DLong64GDL*>(p0)->Dup(), sumDim-1, nanInt);
3037
case ULONG64: return product_over_dim_cu_template<DULong64GDL>(static_cast<DULong64GDL*>(p0)->Dup(), sumDim-1, nanInt);
3038
case FLOAT: return product_over_dim_cu_template<DFloatGDL>(static_cast<DFloatGDL*>(p0)->Dup(), sumDim-1, KwNaN);
3039
case DOUBLE: return product_over_dim_cu_template<DDoubleGDL>(static_cast<DDoubleGDL*>(p0)->Dup(), sumDim-1, KwNaN);
3040
case COMPLEX: return product_over_dim_cu_template<DComplexGDL>(static_cast<DComplexGDL*>(p0)->Dup(), sumDim-1, KwNaN);
3041
case COMPLEXDBL: return product_over_dim_cu_template<DComplexDblGDL>(static_cast<DComplexDblGDL*>(p0)->Dup(), sumDim-1, KwNaN);
3042
default: assert(false);
3046
// Integer parts derivated from Total code by Erin Sheldon
3047
// In IDL PRODUCT(), the INTEGER keyword takes precedence
3049
// We use LONG64 unless the input is ULONG64
3050
if ((p0->Type() == LONG64) && (!KwNaN)) {
3051
return product_over_dim_cu_template<DLong64GDL>
3052
( static_cast<DLong64GDL*>(p0)->Dup(), sumDim-1, nanInt);
3054
if ((p0->Type() == ULONG64 ) && (!KwNaN)) {
3055
return product_over_dim_cu_template<DULong64GDL>
3056
( static_cast<DULong64GDL*>(p0)->Dup(), sumDim-1, nanInt);
3059
// Convert to Long64
3061
DFloatGDL* p0f = static_cast<DFloatGDL*>
3062
(p0->Convert2( FLOAT, BaseGDL::COPY));
3063
auto_ptr<DFloatGDL> guard( p0f);
3064
for( SizeT i=0; i<nEl; ++i) {
3065
if (!isfinite((*p0f)[i])) (*p0f)[i]=1;
3067
return product_over_dim_cu_template<DLong64GDL>
3068
( static_cast<DLong64GDL*>
3069
(p0f->Convert2( LONG64, BaseGDL::COPY)), sumDim-1, nanInt);
3071
return product_over_dim_cu_template<DLong64GDL>
3072
( static_cast<DLong64GDL*>
3073
(p0->Convert2( LONG64, BaseGDL::COPY)), sumDim-1, nanInt);
3075
} // integer results
3077
if( p0->Type() == DOUBLE) {
3078
return product_over_dim_cu_template< DDoubleGDL>
3079
( static_cast<DDoubleGDL*>(p0)->Dup(), sumDim-1, KwNaN);
3081
if( p0->Type() == COMPLEXDBL) {
3082
return product_over_dim_cu_template< DComplexDblGDL>
3083
( static_cast<DComplexDblGDL*>(p0)->Dup(), sumDim-1, KwNaN);
3085
if( p0->Type() == COMPLEX) {
3086
return product_over_dim_cu_template< DComplexDblGDL>
3087
( static_cast<DComplexDblGDL*>
3088
(p0->Convert2( COMPLEXDBL, BaseGDL::COPY)), sumDim-1, KwNaN);
3091
return product_over_dim_cu_template< DDoubleGDL>
3092
( static_cast<DDoubleGDL*>
3093
(p0->Convert2( DOUBLE, BaseGDL::COPY)), sumDim-1, KwNaN);
3097
BaseGDL* array_equal( EnvT* e)
3099
e->NParam( 2);//, "ARRAY_EQUAL");
3101
BaseGDL* p0 = e->GetParDefined( 0);//, "ARRAY_EQUAL");
3102
BaseGDL* p1 = e->GetParDefined( 1);//, "ARRAY_EQUAL");
3104
if( p0 == p1) return new DByteGDL( 1);
3106
SizeT nEl0 = p0->N_Elements();
3107
SizeT nEl1 = p1->N_Elements();
3108
if( nEl0 != nEl1 && nEl0 != 1 && nEl1 != 1)
3109
return new DByteGDL( 0);
3111
auto_ptr<BaseGDL> p0_guard;
3112
auto_ptr<BaseGDL> p1_guard;
3113
if( p0->Type() != p1->Type())
3115
if( e->KeywordSet( 0)) // NO_TYPECONV
3116
return new DByteGDL( 0);
3119
DType aTy=p0->Type();
3120
DType bTy=p1->Type();
3121
if( DTypeOrder[aTy] >= DTypeOrder[bTy])
3123
p1 = p1->Convert2( aTy, BaseGDL::COPY);
3124
p1_guard.reset( p1);
3128
p0 = p0->Convert2( bTy, BaseGDL::COPY);
3129
p0_guard.reset( p0);
3134
if( p0->ArrayEqual( p1)) return new DByteGDL( 1);
3136
return new DByteGDL( 0);
3139
BaseGDL* min_fun( EnvT* e)
3141
SizeT nParam = e->NParam( 1);
3142
BaseGDL* searchArr = e->GetParDefined( 0);
3144
bool omitNaN = e->KeywordSet( "NAN");
3146
static int subIx = e->KeywordIx("SUBSCRIPT_MAX");
3147
bool subMax = e->KeywordPresent(subIx);
3149
static int dimIx = e->KeywordIx("DIMENSION");
3150
bool dimSet = e->KeywordSet(dimIx);
3152
static int maxIx = e->KeywordIx("MAX");
3153
bool maxSet = e->KeywordPresent(maxIx);
3157
e->AssureLongScalarKW(dimIx, searchDim);
3158
if (searchDim < 0 || searchDim > searchArr->Rank())
3159
e->Throw("Illegal keyword value for DIMENSION");
3162
if (dimSet && searchArr->Rank() > 1)
3164
searchDim -= 1; // user-supplied dimensions start with 1!
3166
// here destDim is in fact the srcDim...
3167
dimension destDim = searchArr->Dim();
3168
SizeT searchStride = destDim.Stride(searchDim);
3169
SizeT outerStride = destDim.Stride(searchDim + 1);
3170
// ... and now becomes the destDim
3171
SizeT nSearch = destDim.Remove(searchDim);
3172
SizeT searchLimit = nSearch * searchStride;
3173
SizeT nEl = searchArr->N_Elements();
3175
// memory allocation
3176
BaseGDL *maxVal, *resArr = searchArr->New(destDim, BaseGDL::NOZERO);
3177
DLongGDL *minElArr, *maxElArr;
3181
e->AssureGlobalKW(maxIx); // instead of using a guard pointer
3182
maxVal = searchArr->New(destDim, BaseGDL::NOZERO);
3187
e->AssureGlobalKW(subIx); // instead of using a guard pointer
3188
maxElArr = new DLongGDL(destDim);
3193
e->AssureGlobalPar(1); // instead of using a guard pointer
3194
minElArr = new DLongGDL(destDim);
3198
for (SizeT o = 0; o < nEl; o += outerStride) for (SizeT i = 0; i < searchStride; ++i)
3201
(nParam == 2 ? &((*minElArr)[rIx]) : NULL),
3202
(subMax ? &((*maxElArr)[rIx]) : NULL),
3204
(maxSet ? &maxVal : NULL),
3205
omitNaN, o + i, searchLimit + o + i, searchStride, rIx
3210
if (nParam == 2) e->SetPar(1, minElArr);
3211
if (subMax) e->SetKW(subIx, maxElArr);
3212
if (maxSet) e->SetKW(maxIx, maxVal);
3221
if (maxSet) // MAX keyword given
3223
e->AssureGlobalKW( 0);
3224
delete e->GetKW( 0);
3226
searchArr->MinMax( &minEl, &maxEl, &res, &e->GetKW( 0), omitNaN);
3227
if (subMax) e->SetKW(subIx, new DLongGDL(maxEl));
3229
else // no MAX keyword
3234
searchArr->MinMax( &minEl, &maxEl, &res, NULL, omitNaN);
3235
e->SetKW(subIx, new DLongGDL(maxEl));
3237
else searchArr->MinMax(&minEl, NULL, &res, NULL, omitNaN);
3241
if (nParam == 2) e->SetPar(1, new DLongGDL( minEl));
3242
else SysVar::SetC( minEl);
3247
BaseGDL* max_fun( EnvT* e)
3249
SizeT nParam = e->NParam( 1);
3250
BaseGDL* searchArr = e->GetParDefined( 0);
3252
bool omitNaN = e->KeywordSet( "NAN");
3254
static int subIx = e->KeywordIx("SUBSCRIPT_MIN");
3255
bool subMin = e->KeywordPresent(subIx);
3257
static int dimIx = e->KeywordIx("DIMENSION");
3258
bool dimSet = e->KeywordSet(dimIx);
3260
static int minIx = e->KeywordIx("MIN");
3261
bool minSet = e->KeywordPresent(minIx);
3266
e->AssureLongScalarKW(dimIx, searchDim);
3267
if (searchDim < 0 || searchDim > searchArr->Rank())
3268
e->Throw("Illegal keyword value for DIMENSION");
3271
if (dimSet && searchArr->Rank() > 1)
3273
searchDim -= 1; // user-supplied dimensions start with 1!
3275
// here destDim is in fact the srcDim...
3276
dimension destDim = searchArr->Dim();
3277
SizeT searchStride = destDim.Stride(searchDim);
3278
SizeT outerStride = destDim.Stride(searchDim + 1);
3279
// ... and now becomes the destDim
3280
SizeT nSearch = destDim.Remove(searchDim);
3281
SizeT searchLimit = nSearch * searchStride;
3282
SizeT nEl = searchArr->N_Elements();
3284
// memory allocation
3285
BaseGDL *minVal, *resArr = searchArr->New(destDim, BaseGDL::NOZERO);
3286
DLongGDL *minElArr, *maxElArr;
3290
e->AssureGlobalKW(minIx); // instead of using a guard pointer
3291
minVal = searchArr->New(destDim, BaseGDL::NOZERO);
3296
e->AssureGlobalKW(subIx); // instead of using a guard pointer
3297
minElArr = new DLongGDL(destDim);
3302
e->AssureGlobalPar(1); // instead of using a guard pointer
3303
maxElArr = new DLongGDL(destDim);
3307
for (SizeT o = 0; o < nEl; o += outerStride) for (SizeT i = 0; i < searchStride; ++i)
3310
(subMin ? &((*minElArr)[rIx]) : NULL),
3311
(nParam == 2 ? &((*maxElArr)[rIx]) : NULL),
3312
(minSet ? &minVal : NULL),
3314
omitNaN, o + i, searchLimit + o + i, searchStride, rIx
3319
if (nParam == 2) e->SetPar(1, maxElArr);
3320
if (subMin) e->SetKW(subIx, minElArr);
3321
if (minSet) e->SetKW(minIx, minVal);
3330
if (minSet) // MIN keyword given
3332
e->AssureGlobalKW( 0);
3333
delete e->GetKW( 0);
3335
searchArr->MinMax( &minEl, &maxEl, &e->GetKW( 0), &res, omitNaN);
3336
if (subMin) e->SetKW(subIx, new DLongGDL(minEl));
3338
else // no MIN keyword
3343
searchArr->MinMax( &minEl, &maxEl, NULL, &res, omitNaN);
3344
e->SetKW(subIx, new DLongGDL(minEl));
3346
else searchArr->MinMax(NULL, &maxEl, NULL, &res, omitNaN);
3350
if (nParam == 2) e->SetPar(1, new DLongGDL( maxEl));
3351
else SysVar::SetC(maxEl);
3356
BaseGDL* transpose( EnvT* e)
3358
SizeT nParam=e->NParam( 1);
3360
BaseGDL* p0 = e->GetParDefined( 0);
3361
if( p0->Type() == STRUCT)
3362
e->Throw("Struct expression not allowed in this context: "+
3363
e->GetParString(0));
3365
SizeT rank = p0->Rank();
3367
e->Throw( "Expression must be an array "
3368
"in this context: "+ e->GetParString(0));
3373
BaseGDL* p1 = e->GetParDefined( 1);
3374
if( p1->N_Elements() != rank)
3375
e->Throw("Incorrect number of elements in permutation.");
3377
DUInt* perm = new DUInt[rank];
3378
auto_ptr<DUInt> perm_guard( perm);
3380
DUIntGDL* p1L = static_cast<DUIntGDL*>
3381
(p1->Convert2( UINT, BaseGDL::COPY));
3382
for( SizeT i=0; i<rank; ++i) perm[i] = (*p1L)[ i];
3385
// check permutaion vector
3386
for( SizeT i=0; i<rank; ++i)
3389
for( j=0; j<rank; ++j) if( perm[j] == i) break;
3391
e->Throw( "Incorrect permutation vector.");
3393
return p0->Transpose( perm);
3396
return p0->Transpose( NULL);
3400
// BaseGDL* matrix_multiply( EnvT* e)
3402
// SizeT nParam=e->NParam( 2);
3404
// BaseGDL* a = e->GetNumericArrayParDefined( 0);
3405
// BaseGDL* b = e->GetNumericArrayParDefined( 1);
3407
// static int aTIx = e->KeywordIx("ATRANSPOSE");
3408
// bool aT = e->KeywordPresent(aTIx);
3409
// static int bTIx = e->KeywordIx("BTRANSPOSE");
3410
// bool bT = e->KeywordPresent(bTIx);
3412
// static int strassenIx = e->KeywordIx("STRASSEN_ALGORITHM");
3413
// bool strassen = e->KeywordPresent(strassenIx);
3416
// if( p1->N_Elements() != rank)
3417
// e->Throw("Incorrect number of elements in permutation.");
3419
// DUInt* perm = new DUInt[rank];
3420
// auto_ptr<DUInt> perm_guard( perm);
3422
// DUIntGDL* p1L = static_cast<DUIntGDL*>
3423
// (p1->Convert2( UINT, BaseGDL::COPY));
3424
// for( SizeT i=0; i<rank; ++i) perm[i] = (*p1L)[ i];
3427
// // check permutaion vector
3428
// for( SizeT i=0; i<rank; ++i)
3431
// for( j=0; j<rank; ++j) if( perm[j] == i) break;
3433
// e->Throw( "Incorrect permutation vector.");
3435
// return p0->Transpose( perm);
3438
// return a->Transpose( NULL);
3441
// helper function for sort_fun, recursive
3442
// optimized version
3443
template< typename IndexT>
3444
void MergeSortOpt( BaseGDL* p0, IndexT* hhS, IndexT* h1, IndexT* h2,
3447
if( len <= 1) return;
3449
SizeT h1N = len / 2;
3450
SizeT h2N = len - h1N;
3453
MergeSortOpt(p0, hhS, h1, h2, h1N);
3456
IndexT* hhM = &hhS[h1N];
3457
MergeSortOpt(p0, hhM, h1, h2, h2N);
3460
for(i=0; i<h1N; ++i) h1[i] = hhS[ i];
3461
for(i=0; i<h2N; ++i) h2[i] = hhM[ i];
3465
for( i=0; (h1Ix < h1N) && (h2Ix < h2N); ++i)
3467
// the actual comparisson
3468
if( p0->Greater( h1[h1Ix], h2[h2Ix]))
3469
hhS[ i] = h2[ h2Ix++];
3471
hhS[ i] = h1[ h1Ix++];
3473
for(; h1Ix < h1N; ++i) hhS[ i] = h1[ h1Ix++];
3474
for(; h2Ix < h2N; ++i) hhS[ i] = h2[ h2Ix++];
3477
// helper function for sort_fun, recursive
3478
void MergeSort( BaseGDL* p0, SizeT* hh, SizeT* h1, SizeT* h2,
3479
SizeT start, SizeT end)
3481
if( start+1 >= end) return;
3483
SizeT middle = (start+end) / 2;
3485
MergeSort(p0, hh, h1, h2, start, middle);
3486
MergeSort(p0, hh, h1, h2, middle, end);
3488
SizeT h1N = middle - start;
3489
SizeT h2N = end - middle;
3491
SizeT* hhS = &hh[start];
3494
for(i=0; i<h1N; ++i) h1[i] = hhS[ i];
3495
for(i=0; i<h2N; ++i) h2[i] = hh[middle + i];
3499
for( i=0; (h1Ix < h1N) && (h2Ix < h2N); ++i)
3501
// the actual comparisson
3502
if( p0->Greater( h1[h1Ix], h2[h2Ix]))
3503
hhS[ i] = h2[ h2Ix++];
3505
hhS[ i] = h1[ h1Ix++];
3507
for(; h1Ix < h1N; ++i) hhS[ i] = h1[ h1Ix++];
3508
for(; h2Ix < h2N; ++i) hhS[ i] = h2[ h2Ix++];
3511
// sort function uses MergeSort
3512
BaseGDL* sort_fun( EnvT* e)
3516
BaseGDL* p0 = e->GetParDefined( 0);
3518
if( p0->Type() == STRUCT)
3519
e->Throw( "Struct expression not allowed in this context: "+
3520
e->GetParString(0));
3522
static int l64Ix = e->KeywordIx( "L64");
3523
bool l64 = e->KeywordSet( l64Ix);
3525
SizeT nEl = p0->N_Elements();
3528
DLongGDL* res = new DLongGDL( dimension( nEl), BaseGDL::INDGEN);
3531
if( p0->Type() == FLOAT)
3533
DFloatGDL* p0F = static_cast<DFloatGDL*>(p0);
3534
for( DLong i=nEl-1; i >= 0; --i)
3536
if( isnan((*p0F)[ i]) )//|| !isfinite((*p0F)[ i]))
3539
(*res)[i] = (*res)[nanIx];
3542
// cout << "swap " << i << " with " << nanIx << endl;
3544
// for( DLong ii=0; ii < nEl; ++ii)
3546
// cout << (*res)[ii] << " ";
3552
else if( p0->Type() == DOUBLE)
3554
DDoubleGDL* p0F = static_cast<DDoubleGDL*>(p0);
3555
for( DLong i=nEl-1; i >= 0; --i)
3557
if( isnan((*p0F)[ i]))// || !isfinite((*p0F)[ i]))
3560
(*res)[i] = (*res)[nanIx];
3565
else if( p0->Type() == COMPLEX)
3567
DComplexGDL* p0F = static_cast<DComplexGDL*>(p0);
3568
for( DLong i=nEl-1; i >= 0; --i)
3570
if( isnan((*p0F)[ i].real()) || //!isfinite((*p0F)[ i].real()) ||
3571
isnan((*p0F)[ i].imag()))// || !isfinite((*p0F)[ i].imag()) )
3574
(*res)[i] = (*res)[nanIx];
3579
else if( p0->Type() == COMPLEXDBL)
3581
DComplexDblGDL* p0F = static_cast<DComplexDblGDL*>(p0);
3582
for( DLong i=nEl-1; i >= 0; --i)
3584
if( isnan((*p0F)[ i].real()) || //!isfinite((*p0F)[ i].real()) ||
3585
isnan((*p0F)[ i].imag()))// || !isfinite((*p0F)[ i].imag()) )
3588
(*res)[i] = (*res)[nanIx];
3594
// cout << "nEl " << nEl << " nanIx " << nanIx << endl;
3596
// cout << "sorting: ";
3597
// for( DLong ii=0; ii < nEl; ++ii)
3599
// cout << (*res)[ii] << " ";
3603
DLong *hh = static_cast<DLong*>(res->DataAddr());
3605
DLong* h1 = new DLong[ nEl/2];
3606
DLong* h2 = new DLong[ (nEl+1)/2];
3607
// call the sort routine
3608
MergeSortOpt<DLong>( p0, hh, h1, h2, nEl);
3614
// leave it this way, as sorting of more than 2^31
3615
// items seems not feasible in the future we might
3616
// use MergeSortOpt<DLong64>(...) for this
3617
return res->Convert2( LONG64);
3624
BaseGDL* median( EnvT* e)
3626
SizeT nParam = e->NParam( 1);
3630
BaseGDL* p0 = e->GetParDefined( 0);
3632
if( p0->Type() == PTR)
3633
e->Throw( "Pointer expression not allowed in this context: "+
3634
e->GetParString(0));
3635
if( p0->Type() == OBJECT)
3636
e->Throw( "Object expression not allowed in this context: "+
3637
e->GetParString(0));
3638
if( p0->Type() == STRUCT)
3639
e->Throw( "Struct expression not allowed in this context: "+
3640
e->GetParString(0));
3642
if( p0->Rank() == 0)
3643
e->Throw( "Expression must be an array in this context: "+
3644
e->GetParString(0));
3646
SizeT nEl = p0->N_Elements();
3648
static int evenIx = e->KeywordIx( "EVEN");
3650
p0->Type() == DOUBLE ||
3651
p0->Type() == COMPLEXDBL ||
3652
e->KeywordSet(e->KeywordIx("DOUBLE"));
3653
DType type = dbl ? DOUBLE : FLOAT;
3654
bool noconv = (dbl && p0->Type() == DOUBLE) || (!dbl && p0->Type() == FLOAT);
3656
// DIMENSION keyword
3660
e->AssureLongScalarKWIfPresent( "DIMENSION", dim);
3662
if (dim > p0->Rank())
3663
e->Throw( "Illegal keyword value for DIMENSION.");
3668
for (SizeT i=0; i<p0->Rank(); ++i)
3671
dims[k++] = p0->Dim(i);
3673
dimension dimRes((DLong *) dims, p0->Rank()-1);
3675
? static_cast<BaseGDL*>(new DDoubleGDL(dimRes, BaseGDL::NOZERO))
3676
: static_cast<BaseGDL*>(new DFloatGDL(dimRes, BaseGDL::NOZERO));
3679
? static_cast<BaseGDL*>(new DDoubleGDL(1))
3680
: static_cast<BaseGDL*>(new DFloatGDL(1));
3684
if (nmed > 1) nEl = p0->N_Elements() / nmed;
3686
DLong *hh = new DLong[ nEl];
3687
DLong* h1 = new DLong[ nEl/2];
3688
DLong* h2 = new DLong[ (nEl+1)/2];
3690
DLong accumStride = 1;
3692
for( DLong i=0; i<dim-1; ++i) accumStride *= p0->Dim(i);
3694
BaseGDL *op1, *op2, *op3;
3695
if (dbl) op3 = new DDoubleGDL(2);
3696
else op3 = new DFloatGDL(2);
3698
// Loop over all subarray medians
3699
for (SizeT k=0; k<nmed; ++k) {
3702
for( DLong i=0; i<nEl; ++i) hh[i] = i;
3705
if( p0->Type() == FLOAT)
3707
DFloatGDL* p0F = static_cast<DFloatGDL*>(p0);
3708
for( DLong i=nEl-1; i >= 0; --i)
3710
if( isnan((*p0F)[ i]) )//|| !isfinite((*p0F)[ i]))
3716
// cout << "swap " << i << " with " << nanIx << endl;
3718
// for( DLong ii=0; ii < nEl; ++ii)
3720
// cout << hh[ii] << " ";
3726
else if( p0->Type() == DOUBLE)
3728
DDoubleGDL* p0F = static_cast<DDoubleGDL*>(p0);
3729
for( DLong i=nEl-1; i >= 0; --i)
3731
if( isnan((*p0F)[ i]))// || !isfinite((*p0F)[ i]))
3739
else if( p0->Type() == COMPLEX)
3741
DComplexGDL* p0F = static_cast<DComplexGDL*>(p0);
3742
for( DLong i=nEl-1; i >= 0; --i)
3744
if( isnan((*p0F)[ i].real()) || //!isfinite((*p0F)[ i].real()) ||
3745
isnan((*p0F)[ i].imag()))// || !isfinite((*p0F)[ i].imag()) )
3753
else if( p0->Type() == COMPLEXDBL)
3755
DComplexDblGDL* p0F = static_cast<DComplexDblGDL*>(p0);
3756
for( DLong i=nEl-1; i >= 0; --i)
3758
if( isnan((*p0F)[ i].real()) || //!isfinite((*p0F)[ i].real()) ||
3759
isnan((*p0F)[ i].imag()))// || !isfinite((*p0F)[ i].imag()) )
3768
// cout << "nEl " << nEl << " nanIx " << nanIx << endl;
3773
DLong start = accumStride * p0->Dim(dim-1) * (k / accumStride) +
3775
for( DLong i=0; i<nEl; ++i) hh[i] = start + i * accumStride;
3778
// call the sort routine
3779
MergeSortOpt<DLong>( p0, hh, h1, h2, nEl);
3780
DLong medEl = hh[ nEl/2];
3781
DLong medEl_1 = hh[ nEl/2 - 1];
3783
if( (nEl % 2) == 1 || !e->KeywordSet( evenIx)) {
3785
res = p0->NewIx(medEl)->Convert2(type, BaseGDL::CONVERT);
3789
if (dbl) (*static_cast<DDoubleGDL*>(res))[k] = (*static_cast<DDoubleGDL*>(p0))[medEl];
3790
else (*static_cast<DFloatGDL*>(res))[k] = (*static_cast<DFloatGDL*>(p0))[medEl];
3794
op1 = p0->NewIx(medEl)->Convert2(type, BaseGDL::CONVERT);
3795
if (dbl) (*static_cast<DDoubleGDL*>(res))[k] = (*static_cast<DDoubleGDL*>(op1))[0];
3796
else (*static_cast<DFloatGDL*>(res))[k] = (*static_cast<DFloatGDL*>(op1))[0];
3803
if (dbl) (*static_cast<DDoubleGDL*>(res))[k] = .5 * (
3804
(*static_cast<DDoubleGDL*>(p0))[medEl] +
3805
(*static_cast<DDoubleGDL*>(p0))[medEl_1]
3807
else (*static_cast<DFloatGDL*>(res))[k] = .5 * (
3808
(*static_cast<DFloatGDL*>(p0))[medEl] +
3809
(*static_cast<DFloatGDL*>(p0))[medEl_1]
3814
op1 = p0->NewIx(medEl)->Convert2(type, BaseGDL::CONVERT);
3815
op2 = p0->NewIx(medEl_1)->Convert2(type, BaseGDL::CONVERT);
3816
if (nmed == 1) res = op2->Add(op1)->Div(op3); // TODO: leak with res?
3819
if (dbl) (*static_cast<DDoubleGDL*>(res))[k] =
3820
(*static_cast<DDoubleGDL*>((op2->Add(op1)->Div(op3))))[0];
3821
else (*static_cast<DFloatGDL*>(res))[k] =
3822
(*static_cast<DFloatGDL*>((op2->Add(op1)->Div(op3))))[0];
3837
// with parameter Width : median filtering with no optimisation,
3838
// such as histogram algorithms.
3839
// Copyright: (C) 2008 by Nicolas Galmiche
3841
// basic checks on "vector/array" input
3842
DDoubleGDL* p0 = e->GetParAs<DDoubleGDL>( 0);
3844
if( p0->Type() == STRUCT)
3845
e->Throw( "Struct expression not allowed in this context: "+ e->GetParString(0));
3846
if( p0->Rank() == 0)
3847
e->Throw( "Expression must be an array in this context: "+ e->GetParString(0));
3850
e->Throw( "Only 1 or 2 dimensions allowed: "+ e->GetParString(0));
3852
// basic checks on "width" input
3853
DDoubleGDL* p1d = e->GetParAs<DDoubleGDL>(1);
3855
if (p1d->N_Elements() > 1 || (*p1d)[0] <=0 )
3856
e->Throw( "Width must be a positive scalar or 1 (positive) element array in this context: "+ e->GetParString(0));
3857
DLong MaxAllowedWidth=0;
3858
if (p0->Rank() == 1) MaxAllowedWidth=p0->N_Elements();
3859
if (p0->Rank() == 2) {
3860
MaxAllowedWidth=p0->Dim(0);
3861
if (p0->Dim(1) < MaxAllowedWidth) MaxAllowedWidth=p0->Dim(1);
3865
cout << "X dim " << p0->Dim(0) <<endl;
3866
cout << "y dim " << p0->Dim(1) <<endl;
3867
cout << "MaxAllowedWidth " << MaxAllowedWidth <<endl;
3869
if (!isfinite( (*p1d)[0]))
3870
e->Throw("Width must be > 1, and < dimension of array (NaN or Inf)");
3872
DLongGDL* p1 = e->GetParAs<DLongGDL>(1);
3874
DDoubleGDL *tamp = new DDoubleGDL(p0->Dim(),BaseGDL::NOZERO);
3875
DDouble min=((*p0)[0]);
3878
for (SizeT ii=0 ; ii<p0->N_Elements() ; ++ii)
3879
{(*tamp)[ii]=(*p0)[ii];
3880
if ( (*p0)[ii] < min ) min = ((*p0)[ii]);
3881
if ( (*p0)[ii] > max ) max = ((*p0)[ii]);
3884
//---------------------------- END d'acquisistion des paramètres -------------------------------------
3887
static int evenIx = e->KeywordIx( "EVEN");
3888
static int doubleIx = e->KeywordIx( "DOUBLE");
3889
static DStructGDL *Values = SysVar::Values();
3890
DDouble d_nan=(*static_cast<DDoubleGDL*>(Values->GetTag(Values->Desc()->TagIndex("D_NAN"), 0)))[0];
3891
DDouble d_infinity= (*static_cast<DDoubleGDL*>(Values->GetTag(Values->Desc()->TagIndex("D_INFINITY"), 0)))[0];
3893
//------------------------------ Init variables and allocation ---------------------------------------
3894
SizeT width=(*p1)[0];
3895
SizeT N_MaskElem= width*width;
3896
SizeT larg = p0->Stride(1);
3897
SizeT haut = p0->Stride(2)/larg;
3898
SizeT lim= static_cast<SizeT>(round(width/2));
3899
SizeT init=(lim*larg+lim);
3901
// we don't go further if dimension(s) versus not width OK
3903
if (debug == 1) {cout << "ici" <<endl;}
3905
if ( p0->Rank() == 1) {
3906
if (larg < width || width==1 ) e->Throw( "Width must be > 1, and < width of vector");
3908
if ( p0->Rank() == 2) {
3909
if (larg < width || haut < width || width==1) e->Throw("Width must be > 1, and < dimension of array");
3912
// for 2D arrays, we use the algorithm described in paper
3913
// from T. Huang, G. Yang, and G. Tang, “A Fast Two-Dimensional Median
3914
// Filtering Algorithm,” IEEE Trans. Acoust., Speech, Signal Processing,
3915
// vol. 27, no. 1, pp. 13–18, 1979.
3917
if ( (e->GetParDefined( 0)->Type() == BYTE ||
3918
e->GetParDefined( 0)->Type() == INT ||
3919
e->GetParDefined( 0)->Type() == UINT ||
3920
e->GetParDefined( 0)->Type() == LONG ||
3921
e->GetParDefined( 0)->Type() == ULONG ||
3922
e->GetParDefined( 0)->Type() == LONG64 ||
3923
e->GetParDefined( 0)->Type() == ULONG64) &&
3926
SizeT taille=static_cast<SizeT>(abs(max)-min+1);
3927
DDoubleGDL* Histo = new DDoubleGDL(taille,BaseGDL::NOZERO);
3930
for(SizeT i=0 ; i<haut-2*lim ; ++i)
3934
SizeT initial=init+i*larg-lim*larg-lim;
3935
for(SizeT pp=0 ; pp<taille;++pp)(*Histo)[pp]=0;
3936
for (SizeT ii=initial ; ii <initial+ width ; ++ii)
3938
for(SizeT yy=0;yy<width;yy++)
3939
(*Histo)[static_cast<SizeT>((*p0)[ii+yy*larg]-min)]++;
3942
while (ltmed+(*Histo)[med]<=(N_MaskElem /2))
3944
ltmed+= static_cast<SizeT>((*Histo)[med]);
3947
if (e->KeywordSet( evenIx))
3951
//if ((*Histo)[EvenMed]==1 || (ltmed!=0 && ltmed !=(N_MaskElem /2) -1))
3952
if ((*Histo)[EvenMed]==1 || (ltmed!=0 && N_MaskElem /2- ltmed!=1) )
3954
while ((*Histo)[EvenMed-1]==0)
3956
(*tamp)[init+i*larg]=((med+min)+(EvenMed-1+min))/2;
3959
(*tamp)[init+i*larg]=med+min;
3962
{(*tamp)[init+i*larg]=med+min; }
3964
for(SizeT j=init+i*larg +1; j<init+(i+1)*larg-2*lim ;++ j)
3966
SizeT initMask=j-lim*larg-lim;
3967
for(SizeT k=0;k<2*lim;++k)
3969
(*Histo)[static_cast<SizeT>((*p0)[initMask-1+k*larg]-min)]--;
3970
if ((*p0)[initMask-1+k*larg]-min<med)ltmed--;
3972
(*Histo)[static_cast<SizeT>((*p0)[initMask+k*larg+2*lim-1]-min)]++;
3973
if ((*p0)[initMask+k*larg+2*lim-1]-min<med)ltmed++;
3975
if (ltmed>N_MaskElem /2)
3977
while(ltmed>N_MaskElem /2)
3980
ltmed-=static_cast<SizeT>((*Histo)[med]);
3985
while (ltmed+(*Histo)[med]<=(N_MaskElem /2))
3987
ltmed+= static_cast<SizeT>((*Histo)[med]);
3992
if (e->KeywordSet( evenIx))
3995
if ((*Histo)[EvenMed]==1 || (ltmed!=0 &&N_MaskElem /2- ltmed!=1 ))
3997
while ((*Histo)[EvenMed-1]==0)
3999
(*tamp)[j]=((med+min)+(EvenMed-1+min))/2;
4002
{(*tamp)[j]=med+min; }
4005
{(*tamp)[j]=med+min; }
4011
for(SizeT i=0 ; i<haut-2*lim ; ++i)
4015
SizeT initial=init+i*larg-lim*larg-lim;
4016
for(SizeT pp=0 ; pp<taille;++pp)(*Histo)[pp]=0;
4017
for (SizeT ii=initial ; ii <initial+ width ; ++ii)
4019
for(SizeT yy=0;yy<width;yy++)
4020
(*Histo)[static_cast<SizeT>((*p0)[ii+yy*larg]-min)]++;
4023
while (ltmed+(*Histo)[med]<=(N_MaskElem /2))
4025
ltmed+= static_cast<SizeT>((*Histo)[med]);
4028
(*tamp)[init+i*larg]=med+min;
4030
for(SizeT j=init+i*larg +1; j<init+(i+1)*larg-2*lim ;++ j)
4033
SizeT initMask=j-lim*larg-lim;
4034
for(SizeT k=0;k<=2*lim;++k)
4036
(*Histo)[static_cast<SizeT>((*p0)[initMask-1+k*larg]-min)]--;
4037
if ((*p0)[initMask-1+k*larg]-min<med)ltmed--;
4039
(*Histo)[static_cast<SizeT>((*p0)[initMask+k*larg+2*lim]-min)]++;
4040
if ((*p0)[initMask+k*larg+2*lim]-min<med)ltmed++;
4042
if (ltmed>N_MaskElem /2)
4044
while(ltmed>N_MaskElem /2)
4047
ltmed-=static_cast<SizeT>((*Histo)[med]);
4052
while (ltmed+(*Histo)[med]<=(N_MaskElem /2))
4054
ltmed+= static_cast<SizeT>((*Histo)[med]);
4071
DDoubleGDL* Mask,*Mask1D;
4072
if ( p0->Rank() != 1 )
4074
hh = new DLong[ N_MaskElem];
4075
h1 = new DLong[ N_MaskElem/2];
4076
h2= new DLong[ (N_MaskElem+1)/2];
4077
Mask = new DDoubleGDL(N_MaskElem,BaseGDL::NOZERO);
4079
for( DLong i=0; i<N_MaskElem; ++i) hh[i] = i;
4083
hh = new DLong[ width];
4084
h1 = new DLong[ width/2];
4085
h2= new DLong[(width+1)/2];
4086
Mask1D = new DDoubleGDL(width,BaseGDL::NOZERO);
4088
for( DLong i=0; i<width; ++i) hh[i] = i;
4091
//-------------------------------- END OF VARIABLES INIT ---------------------------------------------
4093
//------------------------------ Median Filter Algorithms ---------------------------------------
4097
if ( p0->Rank() == 1 )//------------------------ For a vector with even width -------------------
4099
for (SizeT col= lim ; col<larg-lim ; ++col)
4103
for (SizeT ind=col-lim ; ind<col+lim ; ++ind)
4105
if( (*p0)[ind]!=d_infinity && (*p0)[ind]!=-d_infinity && isfinite((*p0)[ind])==0)
4109
(*Mask1D)[kk]=(*p0)[ind];
4115
if(ctl_NaN==width)(*tamp)[col]= d_nan;
4118
DLong* hhbis = new DLong[ width-ctl_NaN];
4119
DLong* h1bis = new DLong[ width-ctl_NaN/2];
4120
DLong* h2bis= new DLong[(width-ctl_NaN+1)/2];
4121
DDoubleGDL *Mask1Dbis = new DDoubleGDL(width-ctl_NaN,BaseGDL::NOZERO);
4122
for( DLong t=0; t<width-ctl_NaN; ++t) hhbis[t] = t;
4123
for( DLong ii=0; ii<width-ctl_NaN; ++ii)(*Mask1Dbis)[ii]=(*Mask1D)[ii];
4124
BaseGDL* besort=static_cast<BaseGDL*>(Mask1Dbis);
4125
MergeSortOpt<DLong>( besort, hhbis, h1bis, h2bis,(width - ctl_NaN));
4126
if (e->KeywordSet( evenIx)&& (width - ctl_NaN) % 2 == 0)
4127
(*tamp)[col]=((*Mask1Dbis)[hhbis[ (width-ctl_NaN)/2]]+(*Mask1Dbis
4128
)[hhbis [ (width - ctl_NaN-1)/2]])/2;
4130
(*tamp)[col]=(*Mask1Dbis)[hhbis[ (width- ctl_NaN)/2]];
4138
BaseGDL* besort=static_cast<BaseGDL*>(Mask1D);
4139
MergeSortOpt<DLong>( besort, hh, h1, h2,width ); // call the sort routine
4141
if (e->KeywordSet( evenIx))
4143
(*tamp)[col]=((*Mask1D)[hh[ width/2]]+(*Mask1D)[hh[ (width-1)/2]])/2;
4145
(*tamp)[col]=(*Mask1D)[hh[ width/2]];// replace value by Mask median
4150
else//------------------------ For an array with even width -------------------
4153
for(SizeT i=0 ; i<haut-2*lim ; ++i) // lines to replace
4155
for(SizeT j=init+i*larg ; j<init+(i+1)*larg-2*lim ; ++j)// elements to replace
4157
SizeT initMask=j-lim*larg-lim; // left corner of mask
4160
for(SizeT k=0;k<2*lim;++k) // lines of mask
4163
for(jj=initMask+k*larg ; jj<(initMask+k*larg)+2*lim ; ++jj) // elements of mask
4165
if( (*p0)[jj]!=d_infinity && (*p0)[jj]!=-d_infinity && isfinite((*p0)[jj])==0)
4169
(*Mask)[kk]=(*p0)[jj];
4176
if(ctl_NaN==N_MaskElem)(*tamp)[j]= d_nan;
4178
DLong* hhb = new DLong[ N_MaskElem-ctl_NaN];
4179
DLong* h1b = new DLong[ (N_MaskElem-ctl_NaN)/2];
4180
DLong* h2b = new DLong[(N_MaskElem-ctl_NaN+1)/2];
4181
DDoubleGDL *Maskb = new DDoubleGDL(N_MaskElem-ctl_NaN,BaseGDL::NOZERO);
4182
for( DLong t=0; t<N_MaskElem-ctl_NaN; ++t) hhb[t] = t;
4183
for( DLong ii=0; ii<N_MaskElem-ctl_NaN; ++ii)(*Maskb)[ii]=(*Mask)[ii];
4184
BaseGDL* besort=static_cast<BaseGDL*>(Maskb);
4185
MergeSortOpt<DLong>( besort, hhb, h1b, h2b,(N_MaskElem - ctl_NaN));
4186
if ((N_MaskElem - ctl_NaN) % 2 == 0 && e->KeywordSet( evenIx))
4187
(*tamp)[j]=((*Maskb)[hhb[ (N_MaskElem-ctl_NaN)/2]]+(*Maskb)[hhb
4191
(*tamp)[j]=(*Maskb)[hhb[ (N_MaskElem- ctl_NaN)/2]];
4199
BaseGDL* besort=static_cast<BaseGDL*>(Mask);
4200
MergeSortOpt<DLong>( besort, hh, h1, h2, N_MaskElem); // call the sort routine
4201
if (e->KeywordSet( evenIx))
4202
(*tamp)[j]=((*Mask)[hh[ N_MaskElem/2]]+(*Mask)[hh[ (N_MaskElem-1)/2]])/2;
4204
(*tamp)[j]=(*Mask)[hh[ N_MaskElem/2]];// replace value by median Mask one
4213
if ( p0->Rank() == 1 )//------------------------ For a vector with odd width -------------------
4216
for (SizeT col= lim ; col<larg-lim ; ++col)
4220
for (SizeT ind=col-lim ; ind<=col+lim ; ++ind)
4221
{if( (*p0)[ind]!=d_infinity && (*p0)[ind]!=-d_infinity && isfinite((*p0)[ind])==0)
4224
(*Mask1D)[kk]=(*p0)[ind];
4230
if(ctl_NaN==width)(*tamp)[col]= d_nan;
4232
DLong* hhbis = new DLong[ width-ctl_NaN];
4233
DLong* h1bis = new DLong[ width-ctl_NaN/2];
4234
DLong* h2bis= new DLong[(width-ctl_NaN+1)/2];
4235
DDoubleGDL *Mask1Dbis = new DDoubleGDL(width-ctl_NaN,BaseGDL::NOZERO);
4236
for( DLong t=0; t<width-ctl_NaN; ++t) hhbis[t] = t;
4237
for( DLong ii=0; ii<width-ctl_NaN; ++ii)(*Mask1Dbis)[ii]=(*Mask1D)[ii];
4238
BaseGDL* besort=static_cast<BaseGDL*>(Mask1Dbis);
4239
MergeSortOpt<DLong>( besort, hhbis, h1bis, h2bis,(width - ctl_NaN));
4240
if (e->KeywordSet( evenIx)&& (width - ctl_NaN) % 2 == 0)
4241
(*tamp)[col]=((*Mask1Dbis)[hhbis[ (width-ctl_NaN)/2]]+(*Mask1Dbis
4242
)[hhbis [ (width - ctl_NaN-1)/2]])/2;
4243
else(*tamp)[col]=(*Mask1Dbis)[hhbis[ (width- ctl_NaN)/2]];
4251
BaseGDL* besort=static_cast<BaseGDL*>(Mask1D);
4252
MergeSortOpt<DLong>( besort, hh, h1, h2,width ); // call the sort routine
4253
(*tamp)[col]=(*Mask1D)[hh[ (width)/2]]; // replace value by Mask median
4259
else //----------------------------- For an array with odd width ---------------------------------
4262
for(SizeT i=0 ; i<haut-2*lim ; ++i) // lines to replace
4265
SizeT initial=init+i*larg-lim*larg-lim;
4266
SizeT dd=0;SizeT ctl_NaN_init=0;
4267
for(SizeT yy=0;yy<width;yy++)
4269
for (SizeT ii=initial+yy*larg ; ii <initial+ yy*larg+ width; ++ii)
4272
if( (*p0)[ii]!=d_infinity && (*p0)[ii]!=-d_infinity && isfinite((*p0)[ii])==0)
4275
(*Mask)[dd]=(*p0)[ii];
4281
for(SizeT j=init+i*larg ; j<init+(i+1)*larg-2*lim ; ++j)// elements to replace
4283
SizeT initMask=j-lim*larg-lim; // left corner of mask
4286
for(SizeT k=0;k<=2*lim;++k) // lines of mask
4289
for(jj=initMask+k*larg ; jj<=(initMask+k*larg)+2*lim ; ++jj) // elements of mask
4291
if( (*p0)[jj]!=d_infinity && (*p0)[jj]!=-d_infinity && isfinite((*p0)[jj])==0)
4296
(*Mask)[kk]=(*p0)[jj];
4305
if(ctl_NaN==N_MaskElem)
4308
DLong* hhb = new DLong[ N_MaskElem-ctl_NaN];
4309
DLong* h1b = new DLong[ (N_MaskElem-ctl_NaN)/2];
4310
DLong* h2b= new DLong[(N_MaskElem-ctl_NaN+1)/2];
4311
DDoubleGDL*Maskb = new DDoubleGDL(N_MaskElem-ctl_NaN,BaseGDL::NOZERO);
4312
for( DLong t=0; t<N_MaskElem-ctl_NaN; ++t) hhb[t] = t;
4313
for( DLong ii=0; ii<N_MaskElem-ctl_NaN; ++ii)(*Maskb)[ii]=(*Mask)[ii];
4314
BaseGDL* besort=static_cast<BaseGDL*>(Maskb);
4315
MergeSortOpt<DLong>( besort, hhb, h1b, h2b,(N_MaskElem - ctl_NaN));
4316
if ((N_MaskElem - ctl_NaN) % 2 == 0 && e->KeywordSet( evenIx))
4317
(*tamp)[j]=((*Maskb)[hhb[ (N_MaskElem-ctl_NaN)/2]]+(*Maskb)[hhb
4320
else(*tamp)[j]=(*Maskb)[hhb[(N_MaskElem- ctl_NaN)/2]];
4328
BaseGDL* besort=static_cast<BaseGDL*>(Mask);
4329
MergeSortOpt<DLong>( besort, hh, h1, h2, N_MaskElem); // call the sort routine
4330
(*tamp)[j]=(*Mask)[hh[ (N_MaskElem)/2]]; // replace value by Mask median
4337
//--------------------------- END OF MEDIAN FILTER ALOGORITHMS -----------------------------------
4343
if ( e->GetParDefined( 0)->Type() == DOUBLE || p0->Type() == COMPLEXDBL ||e->KeywordSet( doubleIx) )
4345
else if (e->GetParDefined( 0)->Type() == BYTE)
4346
return tamp->Convert2(BYTE,BaseGDL::CONVERT);
4348
return tamp->Convert2(FLOAT,BaseGDL::CONVERT);
4354
BaseGDL* shift_fun( EnvT* e)
4356
SizeT nParam = e->NParam( 2);
4358
BaseGDL* p0 = e->GetParDefined( 0);
4360
SizeT nShift = nParam - 1;
4364
e->AssureLongScalarPar( 1, s1);
4366
return p0->CShift( s1);
4369
if( p0->Rank() != nShift)
4370
e->Throw( "Incorrect number of arguments.");
4372
DLong sIx[ MAXRANK];
4373
for( SizeT i=0; i< nShift; i++)
4374
e->AssureLongScalarPar( i+1, sIx[ i]);
4376
return p0->CShift( sIx);
4379
BaseGDL* arg_present( EnvT* e)
4383
if( !e->GlobalPar( 0))
4384
return new DIntGDL( 0);
4386
EnvBaseT* caller = e->Caller();
4388
return new DIntGDL( 0);
4390
BaseGDL** pp0 = &e->GetPar( 0);
4392
int ix = caller->FindGlobalKW( pp0);
4394
return new DIntGDL( 0);
4396
return new DIntGDL( 1);
4399
BaseGDL* eof_fun( EnvT* e)
4404
e->AssureLongScalarPar( 0, lun);
4406
bool stdLun = check_lun( e, lun);
4408
return new DIntGDL( 0);
4410
// nicer error message (Disregard if socket)
4411
if ( fileUnits[ lun-1].SockNum() == -1) {
4412
if( !fileUnits[ lun-1].IsOpen())
4413
throw GDLIOException( e->CallingNode(), "File unit is not open: "+i2s( lun)+".");
4415
if( fileUnits[ lun-1].Eof())
4416
return new DIntGDL( 1);
4419
string *recvBuf = &fileUnits[ lun-1].RecvBuf();
4420
if (recvBuf->size() == 0)
4421
return new DIntGDL( 1);
4423
return new DIntGDL( 0);
4426
BaseGDL* convol( EnvT* e)
4428
SizeT nParam=e->NParam( 2);
4430
BaseGDL* p0 = e->GetNumericParDefined( 0);
4431
if( p0->Rank() == 0)
4432
e->Throw( "Expression must be an array in this context: "+
4433
e->GetParString(0));
4435
BaseGDL* p1 = e->GetNumericParDefined( 1);
4436
if( p1->Rank() == 0)
4437
e->Throw( "Expression must be an array in this context: "+
4438
e->GetParString(1));
4440
if( p0->N_Elements() <= p1->N_Elements())
4441
e->Throw( "Incompatible dimensions for Array and Kernel.");
4443
// rank 1 for kernel works always
4444
if( p1->Rank() != 1)
4446
SizeT rank = p0->Rank();
4447
if( rank != p1->Rank())
4448
e->Throw( "Incompatible dimensions for Array and Kernel.");
4450
for( SizeT r=0; r<rank; ++r)
4451
if( p0->Dim( r) <= p1->Dim( r))
4452
e->Throw( "Incompatible dimensions for Array and Kernel.");
4455
// convert kernel to array type
4456
auto_ptr<BaseGDL> p1Guard;
4457
if( p0->Type() == BYTE)
4459
if( p1->Type() != INT)
4461
p1 = p1->Convert2( INT, BaseGDL::COPY);
4465
else if( p0->Type() != p1->Type())
4467
p1 = p1->Convert2( p0->Type(), BaseGDL::COPY);
4472
auto_ptr<BaseGDL> scaleGuard;
4475
scale = e->GetParDefined( 2);
4476
if( scale->Rank() > 0)
4477
e->Throw( "Expression must be a scalar in this context: "+
4478
e->GetParString(2));
4480
// p1 here handles BYTE case also
4481
if( p1->Type() != scale->Type())
4483
scale = scale->Convert2( p1->Type(),BaseGDL::COPY);
4484
scaleGuard.reset( scale);
4489
scale = p1->New( dimension(), BaseGDL::ZERO);
4493
static int centerIx = e->KeywordIx( "CENTER");
4494
if( e->KeywordPresent( centerIx))
4497
e->AssureLongScalarKW( centerIx, c);
4501
// overrides EDGE_TRUNCATE
4502
static int edge_wrapIx = e->KeywordIx( "EDGE_WRAP");
4503
bool edge_wrap = e->KeywordSet( edge_wrapIx);
4504
static int edge_truncateIx = e->KeywordIx( "EDGE_TRUNCATE");
4505
bool edge_truncate = e->KeywordSet( edge_truncateIx);
4510
else if( edge_truncate)
4513
// p0, p1 and scale have same type
4514
// p1 has rank of 1 or same rank as p0 with each dimension smaller than p0
4515
// scale is a scalar
4516
return p0->Convol( p1, scale, center, edgeMode);
4519
BaseGDL* rebin_fun( EnvT* e)
4521
SizeT nParam = e->NParam( 2);
4523
BaseGDL* p0 = e->GetNumericParDefined( 0);
4525
SizeT rank = p0->Rank();
4528
e->Throw( "Expression must be an array in this context: "+
4529
e->GetParString(0));
4531
SizeT resDimInit[ MAXRANK];
4533
DLongGDL* p1 = e->GetParAs<DLongGDL>(1);
4534
if (p1->Rank() > 0 && nParam > 2)
4535
e->Throw("The new dimensions must either be specified as an array or as a set of scalars.");
4536
SizeT np = p1->Rank() == 0 ? nParam : p1->N_Elements() + 1;
4538
for( SizeT p=1; p<np; ++p)
4541
if (p1->Rank() == 0) e->AssureLongScalarPar( p, newDim);
4542
else newDim = (*p1)[p - 1];
4545
e->Throw( "Array dimensions must be greater than 0.");
4549
SizeT oldDim = p0->Dim( p-1);
4551
if( newDim > oldDim)
4553
if( (newDim % oldDim) != 0)
4554
e->Throw( "Result dimensions must be integer factor "
4555
"of original dimensions.");
4559
if( (oldDim % newDim) != 0)
4560
e->Throw( "Result dimensions must be integer factor "
4561
"of original dimensions.");
4565
resDimInit[ p-1] = newDim;
4568
dimension resDim( resDimInit, np-1);
4570
static int sampleIx = e->KeywordIx( "SAMPLE");
4571
bool sample = e->KeywordSet( sampleIx);
4573
return p0->Rebin( resDim, sample);
4576
BaseGDL* obj_class( EnvT* e)
4578
SizeT nParam = e->NParam();
4580
static int countIx = e->KeywordIx( "COUNT");
4581
static int superIx = e->KeywordIx( "SUPERCLASS");
4583
bool super = e->KeywordSet( superIx);
4585
bool count = e->KeywordPresent( countIx);
4587
e->AssureGlobalKW( countIx);
4591
BaseGDL* p0 = e->GetParDefined( 0);
4593
if( p0->Type() != STRING && p0->Type() != OBJECT)
4594
e->Throw( "Argument must be a scalar object reference or string: "+
4595
e->GetParString(0));
4598
e->Throw( "Expression must be a scalar or 1 element "
4599
"array in this context: "+e->GetParString(0));
4601
DStructDesc* objDesc;
4603
if( p0->Type() == STRING)
4606
e->AssureScalarPar<DStringGDL>( 0, objName);
4607
objName = StrUpCase( objName);
4609
objDesc = FindInStructList( structList, objName);
4610
if( objDesc == NULL)
4613
e->SetKW( countIx, new DLongGDL( 0));
4614
return new DStringGDL( "");
4620
e->AssureScalarPar<DObjGDL>( 0, objRef);
4625
e->SetKW( countIx, new DLongGDL( 0));
4626
return new DStringGDL( "");
4629
DStructGDL* oStruct;
4631
oStruct = e->GetObjHeap( objRef);
4633
catch ( GDLInterpreter::HeapException)
4634
{ // non valid object
4636
e->SetKW( countIx, new DLongGDL( 0));
4637
return new DStringGDL( "");
4640
objDesc = oStruct->Desc(); // cannot be NULL
4646
e->SetKW( countIx, new DLongGDL( 1));
4647
return new DStringGDL( objDesc->Name());
4650
deque< string> pNames;
4651
objDesc->GetParentNames( pNames);
4653
SizeT nNames = pNames.size();
4656
e->SetKW( countIx, new DLongGDL( nNames));
4660
return new DStringGDL( "");
4663
DStringGDL* res = new DStringGDL( dimension( nNames),
4666
for( SizeT i=0; i<nNames; ++i)
4668
(*res)[i] = pNames[i];
4675
e->Throw( "Conflicting keywords.");
4677
SizeT nObj = structList.size();
4679
DStringGDL* res = new DStringGDL( dimension( nObj),
4682
for( SizeT i=0; i<nObj; ++i)
4684
(*res)[i] = structList[i]->Name();
4690
BaseGDL* obj_isa( EnvT* e)
4692
SizeT nParam = e->NParam( 2);
4694
BaseGDL* p0 = e->GetPar( 0);
4695
if( p0 == NULL || p0->Type() != OBJECT)
4696
e->Throw( "Object reference type required in this context: "+
4697
e->GetParString(0));
4700
e->AssureScalarPar<DStringGDL>( 1, className);
4701
className = StrUpCase( className);
4703
DObjGDL* pObj = static_cast<DObjGDL*>( p0);
4705
DByteGDL* res = new DByteGDL( pObj->Dim()); // zero
4707
GDLInterpreter* interpreter = e->Interpreter();
4709
SizeT nElem = pObj->N_Elements();
4710
for( SizeT i=0; i<nElem; ++i)
4712
if( interpreter->ObjValid( (*pObj)[ i]))
4714
DStructGDL* oStruct = e->GetObjHeap( (*pObj)[i]);
4715
if( oStruct->Desc()->IsParent( className))
4723
BaseGDL* n_tags( EnvT* e)
4727
BaseGDL* p0 = e->GetPar( 0);
4729
return new DLongGDL( 0);
4731
if( p0->Type() != STRUCT)
4732
return new DLongGDL( 0);
4734
DStructGDL* s = static_cast<DStructGDL*>( p0);
4736
//static int lengthIx = e->KeywordIx( "DATA_LENGTH");
4737
//bool length = e->KeywordSet( lengthIx);
4739
// we don't know now how to distinghuis the 2 following cases
4740
if(e->KeywordSet("DATA_LENGTH"))
4741
return new DLongGDL( s->Sizeof());
4743
if(e->KeywordSet("LENGTH"))
4744
return new DLongGDL( s->Sizeof());
4746
return new DLongGDL( s->Desc()->NTags());
4749
BaseGDL* bytscl( EnvT* e)
4751
SizeT nParam = e->NParam( 1);
4753
BaseGDL* p0=e->GetNumericParDefined( 0);
4755
static int minIx = e->KeywordIx( "MIN");
4756
static int maxIx = e->KeywordIx( "MAX");
4757
static int topIx = e->KeywordIx( "TOP");
4758
bool omitNaN = e->KeywordPresent( 3);
4761
if( e->GetKW( topIx) != NULL)
4762
e->AssureLongScalarKW( topIx, topL);
4763
DByte top = static_cast<DByte>(topL);
4764
DDouble dTop = static_cast<DDouble>(top);
4767
bool minSet = false;
4768
// SA: handling 3 parameters to emulate undocumented IDL behaviour
4769
// of translating second and third arguments to MIN and MAX, respectively
4770
// (parameters have precedence over keywords)
4773
e->AssureDoubleScalarPar(1, min);
4776
else if (e->GetKW(minIx) != NULL)
4778
e->AssureDoubleScalarKW(minIx, min);
4783
bool maxSet = false;
4786
e->AssureDoubleScalarPar(2, max);
4789
else if (e->GetKW(maxIx) != NULL)
4791
e->AssureDoubleScalarKW(maxIx, max);
4796
static_cast<DDoubleGDL*>(p0->Convert2( DOUBLE, BaseGDL::COPY));
4799
if( !maxSet || !minSet)
4800
dRes->MinMax( &minEl, &maxEl, NULL, NULL, omitNaN);
4802
min = (*dRes)[ minEl];
4804
max = (*dRes)[ maxEl];
4806
SizeT nEl = dRes->N_Elements();
4807
for( SizeT i=0; i<nEl; ++i)
4809
DDouble& d = (*dRes)[ i];
4810
if( d <= min) (*dRes)[ i] = 0;
4811
else if( d >= max) (*dRes)[ i] = dTop;
4814
// SA: floor is used for integer types to simulate manipulation on input data types
4815
if (IntType(p0->Type())) (*dRes)[ i] = floor(((dTop + 1.)*(d - min) - 1.) / (max-min));
4816
// SA (?): here floor is used (instead of round) to simulate IDL behaviour
4817
else (*dRes)[ i] = floor((d - min) / (max-min) * (dTop + .9999));
4821
return dRes->Convert2( BYTE);
4824
BaseGDL* strtok_fun( EnvT* e)
4826
SizeT nParam=e->NParam( 1);
4829
e->AssureStringScalarPar( 0, stringIn);
4831
DString pattern = " \t";
4833
e->AssureStringScalarPar( 1, pattern);
4836
static int extractIx = e->KeywordIx( "EXTRACT");
4837
bool extract = e->KeywordSet( extractIx);
4839
static int lengthIx = e->KeywordIx( "LENGTH");
4840
bool lengthPresent = e->KeywordPresent( lengthIx);
4842
if( extract && lengthPresent)
4843
e->Throw( "Conflicting keywords.");
4845
static int pre0Ix = e->KeywordIx( "PRESERVE_NULL");
4846
bool pre0 = e->KeywordSet( pre0Ix);
4848
static int regexIx = e->KeywordIx( "REGEX");
4849
bool regex = e->KeywordPresent( regexIx);
4850
char err_msg[MAX_REGEXPERR_LENGTH];
4853
deque<long> tokenStart;
4854
deque<long> tokenLen;
4856
int strLen = stringIn.length();
4858
DString escape = "";
4859
e->AssureStringScalarKWIfPresent( "ESCAPE", escape);
4860
deque<long> escList;
4862
while(pos != string::npos)
4864
pos = stringIn.find_first_of( escape, pos);
4865
if( pos != string::npos)
4867
escList.push_back( pos+1); // remember escaped char
4868
pos += 2; // skip escaped char
4871
deque<long>::iterator escBeg = escList.begin();
4872
deque<long>::iterator escEnd = escList.end();
4879
// If regex then compile regex
4881
if (pattern == " \t") pattern = " "; // regcomp doesn't like "\t" JMG
4882
int compRes = regcomp( ®exp, pattern.c_str(), REG_EXTENDED);
4884
regerror(compRes, ®exp, err_msg, MAX_REGEXPERR_LENGTH);
4885
e->Throw( "Error processing regular expression: "+
4886
pattern+"\n "+string(err_msg)+".");
4892
regmatch_t pmatch[1];
4894
int matchres = regexec( ®exp, stringIn.c_str()+nextE, 1, pmatch, 0);
4895
tokE = matchres? -1:pmatch[0].rm_so;
4897
tokE = stringIn.find_first_of( pattern, nextE);
4900
if( tokE == string::npos)
4902
actLen = strLen - tokB;
4903
if( actLen > 0 || pre0)
4905
tokenStart.push_back( tokB);
4906
tokenLen.push_back( actLen);
4911
if( find( escBeg, escEnd, tokE) == escEnd)
4913
if (regex) actLen = tokE; else actLen = tokE - tokB;
4914
if( actLen > 0 || pre0)
4916
tokenStart.push_back( tokB);
4917
tokenLen.push_back( actLen);
4919
if (regex) tokB += pmatch[0].rm_eo; else tokB = tokE + 1;
4921
if (regex) nextE += pmatch[0].rm_eo; else nextE = tokE + 1;
4924
if (regex) regfree( ®exp);
4926
SizeT nTok = tokenStart.size();
4932
e->AssureGlobalKW( lengthIx);
4936
dimension dim(nTok);
4937
DLongGDL* len = new DLongGDL(dim);
4938
for(int i=0; i < nTok; i++)
4939
(*len)[i] = tokenLen[i];
4941
e->SetKW( lengthIx, len);
4945
e->SetKW( lengthIx, new DLongGDL( 0));
4949
if( nTok == 0) return new DLongGDL( 0);
4951
dimension dim(nTok);
4952
DLongGDL* d = new DLongGDL(dim);
4953
for(int i=0; i < nTok; i++)
4954
(*d)[i] = tokenStart[i];
4959
if( nTok == 0) return new DStringGDL( "");
4961
dimension dim(nTok);
4962
DStringGDL *d = new DStringGDL(dim);
4963
for(int i=0; i < nTok; i++)
4965
(*d)[i] = stringIn.substr(tokenStart[i], tokenLen[i]);
4968
DString& act = (*d)[i];
4969
long escPos = act.find_first_of( escape, 0);
4970
while( escPos != string::npos)
4972
act = act.substr( 0, escPos)+act.substr( escPos+1);
4973
escPos = act.find_first_of( escape, escPos+1);
4979
BaseGDL* getenv_fun( EnvT* e)
4981
SizeT nParam=e->NParam();
4983
static int environmentIx = e->KeywordIx( "ENVIRONMENT" );
4984
bool environment = e->KeywordSet( environmentIx );
4992
e->Throw( "Incorrect number of arguments.");
4994
// determine number of environment entries
4995
for(nEnv = 0; environ[nEnv] != NULL ; ++nEnv);
4997
dimension dim( nEnv );
4998
env = new DStringGDL(dim);
5000
// copy stuff into local string array
5001
for(SizeT i=0; i < nEnv ; ++i)
5002
(*env)[i] = environ[i];
5007
e->Throw( "Incorrect number of arguments.");
5009
DStringGDL* name = e->GetParAs<DStringGDL>(0);
5010
nEnv = name->N_Elements();
5012
env = new DStringGDL( name->Dim());
5014
// copy the stuff into local string only if param found
5016
for(SizeT i=0; i < nEnv ; ++i)
5018
// handle special environment variables
5019
// GDL_TMPDIR, IDL_TMPDIR
5020
if( (*name)[i] == "GDL_TMPDIR" || (*name)[i] == "IDL_TMPDIR")
5022
resPtr = getenv((*name)[i].c_str());
5027
(*env)[i] = SysVar::Dir();
5029
AppendIfNeeded( (*env)[i], "/");
5031
else // normal environment variables
5032
if( (resPtr = getenv((*name)[i].c_str())) )
5040
BaseGDL* tag_names_fun( EnvT* e)
5042
SizeT nParam=e->NParam();
5043
DStructGDL* struc= e->GetParAs<DStructGDL>(0);
5045
static int structureNameIx = e->KeywordIx( "STRUCTURE_NAME" );
5046
bool structureName = e->KeywordSet( structureNameIx );
5048
DStringGDL* tagNames;
5052
if ((*struc).Desc()->Name() != "$truct")
5053
tagNames = new DStringGDL((*struc).Desc()->Name());
5055
tagNames = new DStringGDL("");
5058
SizeT nTags = (*struc).Desc()->NTags();
5060
tagNames = new DStringGDL(dimension(nTags));
5061
for(int i=0; i < nTags; ++i)
5062
(*tagNames)[i] = (*struc).Desc()->TagName(i);
5068
// AC 12-Oc-2011: better version for: len=len, /Extract and /Sub
5069
// but it is still not perfect
5071
BaseGDL* stregex_fun( EnvT* e)
5073
SizeT nParam=e->NParam( 2);
5075
DStringGDL* stringExpr= e->GetParAs<DStringGDL>(0);
5076
dimension dim = stringExpr->Dim();
5079
e->AssureStringScalarPar(1, pattern);
5080
if (pattern.size() <= 0)
5082
e->Throw( "Error processing regular expression: "+pattern+
5083
"\n empty (sub)expression");
5086
static int booleanIx = e->KeywordIx( "BOOLEAN" );
5087
bool booleanKW = e->KeywordSet( booleanIx );
5089
static int extractIx = e->KeywordIx( "EXTRACT" );
5090
bool extractKW = e->KeywordSet( extractIx );
5092
static int foldCaseIx = e->KeywordIx( "FOLD_CASE" );
5093
bool foldCaseKW = e->KeywordSet( foldCaseIx );
5095
//XXXpch: this is wrong, should check arg_present
5096
static int lengthIx = e->KeywordIx( "LENGTH" );
5097
bool lengthKW = e->KeywordPresent( lengthIx );
5099
static int subexprIx = e->KeywordIx( "SUBEXPR" );
5100
bool subexprKW = e->KeywordSet( subexprIx );
5102
if( booleanKW && (subexprKW || extractKW || lengthKW))
5103
e->Throw( "Conflicting keywords.");
5105
char err_msg[MAX_REGEXPERR_LENGTH];
5107
// set the compile flags
5108
int cflags = REG_EXTENDED;
5110
cflags |= REG_ICASE;
5112
cflags |= REG_NOSUB;
5114
// compile the regular expression
5116
int compRes = regcomp( ®exp, pattern.c_str(), cflags);
5117
SizeT nSubExpr = regexp.re_nsub + 1;
5119
// cout << regexp.re_nsub << endl;
5122
regerror(compRes, ®exp, err_msg, MAX_REGEXPERR_LENGTH);
5123
e->Throw( "Error processing regular expression: "+
5124
pattern+"\n "+string(err_msg)+".");
5130
result = new DByteGDL(dim);
5131
else if( extractKW && !subexprKW)
5133
// cout << "my pb ! ? dim= " << dim << endl;
5134
result = new DStringGDL(dim);
5138
// cout << "my pb 2 ? dim= " << dim << endl;
5139
dimension subExprDim = dim;
5140
subExprDim >> nSubExpr; // m_schellens: commented in, needed
5142
result = new DStringGDL(subExprDim);
5144
result = new DLongGDL(subExprDim);
5147
result = new DLongGDL(dim);
5149
DLongGDL* len = NULL;
5151
e->AssureGlobalKW( lengthIx);
5154
dimension subExprDim = dim;
5155
subExprDim >> nSubExpr; // m_schellens: commented in, needed
5156
len = new DLongGDL(subExprDim);
5160
len = new DLongGDL(dim);
5162
for( SizeT i=0; i<len->N_Elements(); ++i)
5167
if( subexprKW) nmatch = nSubExpr;
5169
regmatch_t* pmatch = new regmatch_t[nSubExpr];
5170
ArrayGuard<regmatch_t> pmatchGuard( pmatch);
5172
// cout << "dim " << dim.NDimElements() << endl;
5173
for( SizeT s=0; s<dim.NDimElements(); ++s)
5177
for( SizeT sE=0; sE<nSubExpr; ++sE)
5178
pmatch[sE].rm_so = -1;
5180
// now match towards the string
5181
int matchres = regexec( ®exp, (*stringExpr)[s].c_str(), nmatch, pmatch, eflags);
5184
if ( extractKW && subexprKW) {
5186
// Loop through subexpressions & fill output array
5187
for( SizeT i = 0; i<nSubExpr; ++i) {
5188
if (pmatch[i].rm_so != -1)
5189
(*static_cast<DStringGDL*>(result))[i+s*nSubExpr] =
5190
(*stringExpr)[s].substr( pmatch[i].rm_so, pmatch[i].rm_eo - pmatch[i].rm_so);
5191
// (*stringExpr)[i+s*nSubExpr].substr( pmatch[i].rm_so, pmatch[i].rm_eo - pmatch[i].rm_so);
5193
(*len)[i+s*nSubExpr] = pmatch[i].rm_so != -1 ? pmatch[i].rm_eo - pmatch[i].rm_so : -1;
5194
// (*len)[i+s*nSubExpr] = pmatch[i].rm_eo - pmatch[i].rm_so;
5197
else if ( subexprKW)
5199
// cout << "je ne comprends pas v2: "<< nSubExpr << endl;
5201
// Loop through subexpressions & fill output array
5202
for( SizeT i = 0; i<nSubExpr; ++i) {
5203
(* static_cast<DLongGDL*>(result))[i+s*nSubExpr] = pmatch[i].rm_so;
5205
(*len)[i+s*nSubExpr] = pmatch[i].rm_so != -1 ? pmatch[i].rm_eo - pmatch[i].rm_so : -1;
5211
(* static_cast<DByteGDL*>(result))[s] = (matchres == 0);
5212
else if ( extractKW) // !subExprKW
5215
(* static_cast<DStringGDL*>(result))[s] =
5216
(*stringExpr)[s].substr( pmatch[0].rm_so,
5217
pmatch[0].rm_eo - pmatch[0].rm_so);
5220
(*static_cast<DLongGDL*>(result))[s] = matchres ? -1 : pmatch[0].rm_so;
5223
if( lengthKW && !subexprKW)
5224
(*len)[s] = pmatch[0].rm_eo - pmatch[0].rm_so;
5230
e->SetKW( lengthIx, len);
5235
BaseGDL* routine_info( EnvT* e)
5237
SizeT nParam=e->NParam();
5239
static int functionsIx = e->KeywordIx( "FUNCTIONS" );
5240
bool functionsKW = e->KeywordSet( functionsIx );
5241
static int systemIx = e->KeywordIx( "SYSTEM" );
5242
bool systemKW = e->KeywordSet( systemIx );
5243
static int disabledIx = e->KeywordIx( "DISABLED" );
5244
bool disabledKW = e->KeywordSet( disabledIx );
5245
static int parametersIx = e->KeywordIx( "PARAMETERS" );
5246
bool parametersKW = e->KeywordSet( parametersIx );
5251
if (systemKW || disabledKW) e->Throw("Conflicting keywords.");
5252
if (nParam != 1) e->Throw("Incorrect number of arguments.");
5254
// getting the routine name from the first parameter
5256
e->AssureScalarPar<DStringGDL>(0, name);
5257
name = StrUpCase(name);
5259
DSubUD* routine = functionsKW
5260
? static_cast<DSubUD*>(funList[GDLInterpreter::GetFunIx(name)])
5261
: static_cast<DSubUD*>(proList[GDLInterpreter::GetProIx(name)]);
5262
SizeT np = routine->NPar(), nk = routine->NKey();
5264
// creating the output anonymous structure
5265
DStructDesc* stru_desc = new DStructDesc("$truct");
5267
stru_desc->AddTag("NUM_ARGS", &aLong);
5268
stru_desc->AddTag("NUM_KW_ARGS", &aLong);
5271
SpDString aStringArr(dimension((int)np));
5272
stru_desc->AddTag("ARGS", &aStringArr);
5276
SpDString aStringArr(dimension((int)nk));
5277
stru_desc->AddTag("KW_ARGS", &aStringArr);
5279
DStructGDL* stru = new DStructGDL(stru_desc, dimension());
5281
// filling the structure with information about the routine
5282
stru->InitTag("NUM_ARGS", DLongGDL(np));
5283
stru->InitTag("NUM_KW_ARGS", DLongGDL(nk));
5286
DStringGDL *pnames = new DStringGDL(dimension(np));
5287
for (SizeT p = 0; p < np; ++p) (*pnames)[p] = routine->GetVarName(nk + p);
5288
stru->InitTag("ARGS", *pnames);
5293
DStringGDL *knames = new DStringGDL(dimension(nk));
5294
for (SizeT k = 0; k < nk; ++k) (*knames)[k] = routine->GetKWName(k);
5295
stru->InitTag("KW_ARGS", *knames);
5303
// GDL does not have disabled routines
5304
if( disabledKW) return new DStringGDL("");
5306
// if( functionsKW || systemKW || nParam == 0)
5308
deque<DString> subList;
5314
SizeT n = libFunList.size();
5315
if( n == 0) return new DStringGDL("");
5317
DStringGDL* res = new DStringGDL( dimension( n), BaseGDL::NOZERO);
5318
for( SizeT i = 0; i<n; ++i)
5319
(*res)[i] = libFunList[ i]->ObjectName();
5325
SizeT n = funList.size();
5326
if( n == 0) return new DStringGDL("");
5329
for( SizeT i = 0; i<n; ++i)
5330
subList.push_back( funList[ i]->ObjectName());
5337
SizeT n = libProList.size();
5338
if( n == 0) return new DStringGDL("");
5340
DStringGDL* res = new DStringGDL( dimension( n), BaseGDL::NOZERO);
5341
for( SizeT i = 0; i<n; ++i)
5342
(*res)[i] = libProList[ i]->ObjectName();
5348
SizeT n = proList.size();
5349
if( n == 0) return new DStringGDL("");
5352
for( SizeT i = 0; i<n; ++i)
5353
subList.push_back( proList[ i]->ObjectName());
5357
sort( subList.begin(), subList.end());
5358
SizeT nS = subList.size();
5360
DStringGDL* res = new DStringGDL( dimension( nS), BaseGDL::NOZERO);
5361
for( SizeT s=0; s<nS; ++s)
5362
(*res)[ s] = subList[ s];
5368
BaseGDL* get_kbrd( EnvT* e)
5370
SizeT nParam=e->NParam();
5377
e->AssureLongScalarPar( 0, waitArg);
5387
// char c = cin.get();
5388
// DStringGDL* res = new DStringGDL( DString( i2s( c)));
5393
// char c = cin.get();
5394
// DStringGDL* res = new DStringGDL( DString( i2s( c)));
5398
// https://sourceforge.net/forum/forum.php?thread_id=3292183&forum_id=338691
5399
// TODO Implement proper SCALAR parameter handling (doWait variable?).
5401
struct termios orig, get;
5402
(void)tcgetattr(fileno(stdin), &orig);
5405
// Disable terminal echoing and set it to non-canonical mode.
5406
get.c_lflag &= ~(ECHO|ICANON);
5408
(void)tcsetattr(fileno(stdin), TCSANOW, &get);
5412
// Restore original terminal settings.
5413
(void)tcsetattr(fileno(stdin), TCSANOW, &orig);
5415
DStringGDL* res = new DStringGDL( DString( i2s( c)));
5420
BaseGDL* temporary( EnvT* e)
5422
SizeT nParam=e->NParam(1);
5424
BaseGDL** p0 = &e->GetParDefined( 0);
5428
*p0 = NULL; // make parameter undefined
5432
BaseGDL* memory( EnvT* e)
5434
SizeT nParam=e->NParam( 0);
5437
bool kw_l64 = e->KeywordSet(e->KeywordIx("L64"));
5438
// TODO: IDL-doc mentions about automatically switching to L64 if needed
5440
if (e->KeywordSet(e->KeywordIx("STRUCTURE")))
5442
// returning structure
5445
ret = new DStructGDL("IDL_MEMORY64");
5446
DStructGDL* retStru = static_cast<DStructGDL*>(ret);
5447
(retStru->GetTag(retStru->Desc()->TagIndex("CURRENT")))->InitFrom( DLong64GDL(MemStats::GetCurrent()));
5448
(retStru->GetTag(retStru->Desc()->TagIndex("NUM_ALLOC")))->InitFrom( DLong64GDL(MemStats::GetNumAlloc()));
5449
(retStru->GetTag(retStru->Desc()->TagIndex("NUM_FREE")))->InitFrom( DLong64GDL(MemStats::GetNumFree()));
5450
(retStru->GetTag(retStru->Desc()->TagIndex("HIGHWATER")))->InitFrom( DLong64GDL(MemStats::GetHighWater()));
5454
ret = new DStructGDL("IDL_MEMORY");
5455
DStructGDL* retStru = static_cast<DStructGDL*>(ret);
5456
(retStru->GetTag(retStru->Desc()->TagIndex("CURRENT")))->InitFrom( DLongGDL(MemStats::GetCurrent()));
5457
(retStru->GetTag(retStru->Desc()->TagIndex("NUM_ALLOC")))->InitFrom( DLongGDL(MemStats::GetNumAlloc()));
5458
(retStru->GetTag(retStru->Desc()->TagIndex("NUM_FREE")))->InitFrom( DLongGDL(MemStats::GetNumFree()));
5459
(retStru->GetTag(retStru->Desc()->TagIndex("HIGHWATER")))->InitFrom( DLongGDL(MemStats::GetHighWater()));
5464
bool kw_current = e->KeywordSet(e->KeywordIx("CURRENT"));
5465
bool kw_num_alloc = e->KeywordSet(e->KeywordIx("NUM_ALLOC"));
5466
bool kw_num_free = e->KeywordSet(e->KeywordIx("NUM_FREE"));
5467
bool kw_highwater = e->KeywordSet(e->KeywordIx("HIGHWATER"));
5469
// Following the IDL documentation: mutually exclusive keywords
5470
// IDL behaves different, incl. segfaults with selected kw combinations
5471
if (kw_current + kw_num_alloc + kw_num_free + kw_highwater > 1)
5472
e->Throw("CURRENT, NUM_ALLOC, NUM_FREE & HIGHWATER keywords"
5473
" are mutually exclusive");
5477
if (kw_l64) ret = new DLong64GDL(MemStats::GetCurrent());
5478
else ret = new DLongGDL(MemStats::GetCurrent());
5480
else if (kw_num_alloc)
5482
if (kw_l64) ret = new DLong64GDL(MemStats::GetNumAlloc());
5483
else ret = new DLongGDL(MemStats::GetNumAlloc());
5485
else if (kw_num_free)
5487
if (kw_l64) ret = new DLong64GDL(MemStats::GetNumFree());
5488
else ret = new DLongGDL(MemStats::GetNumFree());
5490
else if (kw_highwater)
5492
if (kw_l64) ret = new DLong64GDL(MemStats::GetHighWater());
5493
else ret = new DLongGDL(MemStats::GetHighWater());
5497
// returning 4-element array
5500
ret = new DLong64GDL(dimension(4));
5501
(*static_cast<DLong64GDL*>(ret))[0] = MemStats::GetCurrent();
5502
(*static_cast<DLong64GDL*>(ret))[1] = MemStats::GetNumAlloc();
5503
(*static_cast<DLong64GDL*>(ret))[2] = MemStats::GetNumFree();
5504
(*static_cast<DLong64GDL*>(ret))[3] = MemStats::GetHighWater();
5508
ret = new DLongGDL(dimension(4));
5509
(*static_cast<DLongGDL*>(ret))[0] = MemStats::GetCurrent();
5510
(*static_cast<DLongGDL*>(ret))[1] = MemStats::GetNumAlloc();
5511
(*static_cast<DLongGDL*>(ret))[2] = MemStats::GetNumFree();
5512
(*static_cast<DLongGDL*>(ret))[3] = MemStats::GetHighWater();
5520
inline DByte StrCmp( const string& s1, const string& s2, DLong n)
5522
if( n <= 0) return 1;
5523
if( s1.substr(0,n) == s2.substr(0,n)) return 1;
5526
inline DByte StrCmp( const string& s1, const string& s2)
5528
if( s1 == s2) return 1;
5531
inline DByte StrCmpFold( const string& s1, const string& s2, DLong n)
5533
if( n <= 0) return 1;
5534
if( StrUpCase( s1.substr(0,n)) == StrUpCase(s2.substr(0,n))) return 1;
5537
inline DByte StrCmpFold( const string& s1, const string& s2)
5539
if( StrUpCase( s1) == StrUpCase(s2)) return 1;
5543
BaseGDL* strcmp_fun( EnvT* e)
5545
SizeT nParam=e->NParam(2);
5547
DStringGDL* s0 = static_cast<DStringGDL*>( e->GetParAs< DStringGDL>( 0));
5548
DStringGDL* s1 = static_cast<DStringGDL*>( e->GetParAs< DStringGDL>( 1));
5550
DLongGDL* l2 = NULL;
5553
l2 = static_cast<DLongGDL*>( e->GetParAs< DLongGDL>( 2));
5556
static int foldIx = e->KeywordIx( "FOLD_CASE");
5557
bool fold = e->KeywordSet( foldIx );
5559
if( s0->Scalar() && s1->Scalar())
5564
return new DByteGDL( StrCmpFold( (*s0)[0], (*s1)[0]));
5566
return new DByteGDL( StrCmp( (*s0)[0], (*s1)[0]));
5570
DByteGDL* res = new DByteGDL( l2->Dim(), BaseGDL::NOZERO);
5571
SizeT nEl = l2->N_Elements();
5573
for( SizeT i=0; i<nEl; ++i)
5574
(*res)[i] = StrCmpFold( (*s0)[0], (*s1)[0], (*l2)[i]);
5576
for( SizeT i=0; i<nEl; ++i)
5577
(*res)[i] = StrCmp( (*s0)[0], (*s1)[0], (*l2)[i]);
5581
else // at least one array
5587
DByteGDL* res = new DByteGDL( s1->Dim(), BaseGDL::NOZERO);
5588
SizeT nEl = s1->N_Elements();
5590
for( SizeT i=0; i<nEl; ++i)
5591
(*res)[i] = StrCmpFold( (*s0)[0], (*s1)[i]);
5593
for( SizeT i=0; i<nEl; ++i)
5594
(*res)[i] = StrCmp( (*s0)[0], (*s1)[i]);
5597
else if( s1->Scalar())
5599
DByteGDL* res = new DByteGDL( s0->Dim(), BaseGDL::NOZERO);
5600
SizeT nEl = s0->N_Elements();
5602
for( SizeT i=0; i<nEl; ++i)
5603
(*res)[i] = StrCmpFold( (*s0)[i], (*s1)[0]);
5605
for( SizeT i=0; i<nEl; ++i)
5606
(*res)[i] = StrCmp( (*s0)[i], (*s1)[0]);
5613
if( s0->N_Elements() <= s1->N_Elements())
5615
res = new DByteGDL( s0->Dim(), BaseGDL::NOZERO);
5616
nEl = s0->N_Elements();
5620
res = new DByteGDL( s1->Dim(), BaseGDL::NOZERO);
5621
nEl = s1->N_Elements();
5624
for( SizeT i=0; i<nEl; ++i)
5625
(*res)[i] = StrCmpFold( (*s0)[i], (*s1)[i]);
5627
for( SizeT i=0; i<nEl; ++i)
5628
(*res)[i] = StrCmp( (*s0)[i], (*s1)[i]);
5636
bool l2Scalar = l2->Scalar();
5639
if( l2Scalar || s1->N_Elements() <= l2->N_Elements())
5641
res = new DByteGDL( s1->Dim(), BaseGDL::NOZERO);
5642
nEl = s1->N_Elements();
5646
res = new DByteGDL( l2->Dim(), BaseGDL::NOZERO);
5647
nEl = l2->N_Elements();
5650
for( SizeT i=0; i<nEl; ++i)
5651
(*res)[i] = StrCmpFold( (*s0)[0], (*s1)[i], (*l2)[l2Scalar?0:i]);
5653
for( SizeT i=0; i<nEl; ++i)
5654
(*res)[i] = StrCmp( (*s0)[0], (*s1)[i], (*l2)[l2Scalar?0:i]);
5657
else if( s1->Scalar())
5659
if( l2Scalar || s0->N_Elements() <= l2->N_Elements())
5661
res = new DByteGDL( s0->Dim(), BaseGDL::NOZERO);
5662
nEl = s0->N_Elements();
5666
res = new DByteGDL( l2->Dim(), BaseGDL::NOZERO);
5667
nEl = l2->N_Elements();
5670
for( SizeT i=0; i<nEl; ++i)
5671
(*res)[i] = StrCmpFold( (*s0)[i], (*s1)[0], (*l2)[l2Scalar?0:i]);
5673
for( SizeT i=0; i<nEl; ++i)
5674
(*res)[i] = StrCmp( (*s0)[i], (*s1)[0], (*l2)[l2Scalar?0:i]);
5677
else // s1 and s2 are arrays
5680
if( s0->N_Elements() <= s1->N_Elements())
5682
res = new DByteGDL( s0->Dim(), BaseGDL::NOZERO);
5683
nEl = s0->N_Elements();
5687
res = new DByteGDL( s1->Dim(), BaseGDL::NOZERO);
5688
nEl = s1->N_Elements();
5692
if( s0->N_Elements() <= s1->N_Elements())
5693
if( s0->N_Elements() <= l2->N_Elements())
5695
res = new DByteGDL( s0->Dim(), BaseGDL::NOZERO);
5696
nEl = s0->N_Elements();
5700
res = new DByteGDL( l2->Dim(), BaseGDL::NOZERO);
5701
nEl = l2->N_Elements();
5704
if( s1->N_Elements() <= l2->N_Elements())
5706
res = new DByteGDL( s1->Dim(), BaseGDL::NOZERO);
5707
nEl = s1->N_Elements();
5711
res = new DByteGDL( l2->Dim(), BaseGDL::NOZERO);
5712
nEl = l2->N_Elements();
5716
for( SizeT i=0; i<nEl; ++i)
5717
(*res)[i] = StrCmpFold( (*s0)[i], (*s1)[i], (*l2)[l2Scalar?0:i]);
5719
for( SizeT i=0; i<nEl; ++i)
5720
(*res)[i] = StrCmp( (*s0)[i], (*s1)[i], (*l2)[l2Scalar?0:i]);
5727
string TagName( EnvT* e, const string& name)
5729
string n = StrUpCase( name);
5730
SizeT len = n.size();
5731
if( n[0] != '_' && n[0] != '!' && (n[0] < 'A' || n[0] > 'Z'))
5732
e->Throw( "Illegal tag name: "+name+".");
5733
for( SizeT i=1; i<len; ++i)
5738
if( n[i] != '_' && n[i] != '$' && //n[0] != '!' &&
5739
(n[i] < 'A' || n[i] > 'Z') &&
5740
(n[i] < '0' || n[i] > '9'))
5741
e->Throw( "Illegal tag name: "+name+".");
5746
BaseGDL* create_struct( EnvT* e)
5748
static int nameIx = e->KeywordIx( "NAME" );
5749
DString name = "$truct";
5750
if( e->KeywordPresent( nameIx)) {
5751
// Check if name exists, if not then treat as unnamed
5752
if (e->GetKW( nameIx) != NULL)
5753
e->AssureStringScalarKW( nameIx, name);
5756
if( name != "$truct") // named struct
5758
name = StrUpCase( name);
5760
SizeT nParam=e->NParam();
5765
e->Interpreter()->GetStruct( name, e->CallingNode());
5768
return new DStructGDL( desc, dim);
5771
DStructDesc* nStructDesc;
5772
auto_ptr<DStructDesc> nStructDescGuard;
5774
DStructDesc* oStructDesc=
5775
FindInStructList( structList, name);
5777
if( oStructDesc == NULL || oStructDesc->NTags() > 0)
5779
// not defined at all yet (-> define now)
5780
// or completely defined (-> define now and check equality)
5781
nStructDesc= new DStructDesc( name);
5784
nStructDescGuard.reset( nStructDesc);
5789
// not completely defined (only name in list)
5790
nStructDesc= oStructDesc;
5793
// the instance variable
5794
// dimension dim( 1);
5795
// DStructGDL* instance = new DStructGDL( nStructDesc, dim);
5796
DStructGDL* instance = new DStructGDL( nStructDesc);
5797
auto_ptr<DStructGDL> instance_guard(instance);
5799
for( SizeT p=0; p<nParam; ++p)
5801
BaseGDL* par = e->GetParDefined( p);
5802
DStructGDL* parStruct = dynamic_cast<DStructGDL*>( par);
5803
if( parStruct != NULL)
5806
if( !parStruct->Scalar())
5807
e->Throw("Expression must be a scalar in this context: "+
5808
e->GetParString( p));
5810
DStructDesc* desc = parStruct->Desc();
5811
for( SizeT t=0; t< desc->NTags(); ++t)
5813
instance->NewTag( desc->TagName( t),
5814
parStruct->GetTag( t)->Dup());
5819
// add tag value pair
5820
DStringGDL* tagNames = e->GetParAs<DStringGDL>( p);
5821
SizeT nTags = tagNames->N_Elements();
5823
SizeT tagStart = p+1;
5824
SizeT tagEnd = p+nTags;
5825
if( tagEnd >= nParam)
5826
e->Throw( "Incorrect number of arguments.");
5830
BaseGDL* value = e->GetParDefined( p);
5833
instance->NewTag( TagName( e, (*tagNames)[ p-tagStart]),
5840
if( oStructDesc != NULL)
5842
if( oStructDesc != nStructDesc)
5844
oStructDesc->AssureIdentical(nStructDesc);
5845
instance->DStructGDL::SetDesc(oStructDesc);
5846
//delete nStructDesc; // auto_ptr
5851
// release from guard (if not NULL)
5852
nStructDescGuard.release();
5853
// insert into struct list
5854
structList.push_back(nStructDesc);
5857
instance_guard.release();
5863
// Handle case of single structure parameter
5865
nParam = e->NParam(1);
5866
BaseGDL* par = e->GetParDefined( 0);
5867
DStructGDL* parStruct = dynamic_cast<DStructGDL*>( par);
5868
if (nParam != 1 || parStruct == NULL)
5869
nParam=e->NParam(2);
5871
DStructDesc* nStructDesc = new DStructDesc( "$truct");
5872
// instance takes care of nStructDesc since it is unnamed
5873
// dimension dim( 1);
5874
// DStructGDL* instance = new DStructGDL( nStructDesc, dim);
5875
DStructGDL* instance = new DStructGDL( nStructDesc);
5876
auto_ptr<DStructGDL> instance_guard(instance);
5878
for( SizeT p=0; p<nParam;)
5880
BaseGDL* par = e->GetParDefined( p);
5881
DStructGDL* parStruct = dynamic_cast<DStructGDL*>( par);
5882
if( parStruct != NULL)
5885
if( !parStruct->Scalar())
5886
e->Throw("Expression must be a scalar in this context: "+
5887
e->GetParString( p));
5889
DStructDesc* desc = parStruct->Desc();
5890
for( SizeT t=0; t< desc->NTags(); ++t)
5892
instance->NewTag( desc->TagName( t),
5893
parStruct->GetTag( t)->Dup());
5899
// add tag value pair
5900
DStringGDL* tagNames = e->GetParAs<DStringGDL>( p);
5901
SizeT nTags = tagNames->N_Elements();
5903
SizeT tagStart = p+1;
5904
SizeT tagEnd = p+nTags;
5905
if( tagEnd >= nParam)
5906
e->Throw( "Incorrect number of arguments.");
5908
for(++p; p<=tagEnd; ++p)
5910
BaseGDL* value = e->GetParDefined( p);
5913
instance->NewTag( TagName( e, (*tagNames)[ p-tagStart]),
5919
instance_guard.release();
5924
BaseGDL* rotate( EnvT* e)
5927
BaseGDL* p0 = e->GetParDefined( 0);
5929
if( p0->Rank() == 0)
5930
e->Throw( "Expression must be an array in this context: " + e->GetParString( 0));
5932
if( p0->Rank() != 1 && p0->Rank() != 2)
5933
e->Throw( "Only 1 or 2 dimensions allowed: " + e->GetParString( 0));
5935
if( p0->Type() == STRUCT)
5936
e->Throw( "STRUCT expression not allowed in this context: "+
5937
e->GetParString( 0));
5940
e->AssureLongScalarPar( 1, dir);
5942
return p0->Rotate( dir);
5945
// SA: based on the code of rotate() (above)
5946
BaseGDL* reverse( EnvT* e)
5949
BaseGDL* p0 = e->GetParDefined(0);
5950
if (p0->Rank() == 0) return p0->Dup();
5953
if (e->GetPar(1) != NULL)
5954
e->AssureLongScalarPar(1, dim);
5955
if (p0->Rank() != 0 && (dim > p0->Rank() || dim < 1))
5956
e->Throw("Subscript_index must be positive and less than or equal to number of dimensions.");
5959
// IDL doc states that OVERWRITE is ignored for one- or two-dim. arrays
5960
// but it seems to behave differently
5961
// if (p0->Rank() > 2 && e->KeywordSet("OVERWRITE") && e->GlobalPar(0))
5962
if (e->KeywordSet("OVERWRITE"))
5965
bool stolen = e->StealLocalPar( 0);
5966
if( !stolen) e->GetPar(0) = NULL;
5969
else ret = p0->DupReverse(dim - 1);
5973
// SA: parse_url based on the PHP parse_url() function code
5974
// by Jim Winstead / The PHP Group (PHP license v. 3.01)
5975
// (http://svn.php.net/viewvc/php/php-src/trunk/ext/standard/url.c)
5976
// PHP is free software available at http://www.php.net/software/
5979
// - IDL does not support IPv6 URLs, GDL does
5980
// - IDL includes characters after '#' in the QUERY part, GDL
5981
// just skips them and issues a warning (perhaps not needed)
5982
// - IDL preserves controll characters in URLs, GDL preserves
5983
// them as well but a warning is issued
5984
// - IDL sets 80 as a default value for PORT, even if the url has
5985
// an ftp:// schema indicated - GDL does not have any default value
5986
// - IDL excludes the leading "/" from the path, GDL preserves it
5987
// ... these differences seem just rational for me but please do change
5988
// it if IDL-compatibility would be beneficial for any reason here
5990
BaseGDL* parse_url(EnvT* env)
5992
// sanity check for number of parameters
5993
SizeT nParam = env->NParam();
5995
// 1-nd argument : the url string
5997
env->AssureScalarPar<DStringGDL>(0, url);
5999
// sanity check for controll characters
6000
string::iterator it;
6001
for (it = url.begin(); it < url.end(); it++) if (iscntrl(*it))
6003
Warning("PARSE_URL: URL contains a control character");
6007
// creating the output anonymous structure
6008
DStructDesc* urlstru_desc = new DStructDesc("$truct");
6010
urlstru_desc->AddTag("SCHEME", &aString);
6011
static size_t ixSCHEME = 0;
6012
urlstru_desc->AddTag("USERNAME", &aString);
6013
urlstru_desc->AddTag("PASSWORD", &aString);
6014
urlstru_desc->AddTag("HOST", &aString);
6015
urlstru_desc->AddTag("PORT", &aString);
6016
static size_t ixPORT = 4;
6017
urlstru_desc->AddTag("PATH", &aString);
6018
urlstru_desc->AddTag("QUERY", &aString);
6019
DStructGDL* urlstru = new DStructGDL(urlstru_desc, dimension());
6020
auto_ptr<DStructGDL> urlstru_guard(urlstru);
6023
char const *str = url.c_str();
6024
size_t length = url.length();
6026
char const *s, *e, *p, *pp, *ue;
6032
if ((e = (const char*)memchr(s, ':', length)) && (e - s))
6034
// validating scheme
6038
// scheme = 1*[ lowalpha | digit | "+" | "-" | "." ]
6039
if (!isalpha(*p) && !isdigit(*p) && *p != '+' && *p != '.' && *p != '-')
6041
if (e + 1 < ue) goto parse_port;
6042
else goto just_path;
6046
if (*(e + 1) == '\0')
6048
// only scheme is available
6049
urlstru->InitTag("SCHEME", DStringGDL(string(s, (e - s))));
6052
// schemas without '/' (like mailto: and zlib:)
6055
// check if the data we get is a port this allows us to correctly parse things like a.com:80
6057
while (isdigit(*p)) p++;
6058
if ((*p == '\0' || *p == '/') && (p - e) < 7) goto parse_port;
6059
urlstru->InitTag("SCHEME", DStringGDL(string(s, (e - s))));
6066
urlstru->InitTag("SCHEME", DStringGDL(string(s, (e - s))));
6070
if (!strncasecmp("file",
6071
(*static_cast<DStringGDL*>(urlstru->GetTag(ixSCHEME)))[0].c_str(),
6075
if (*(e + 3) == '/')
6077
// support windows drive letters as in: file:///c:/somedir/file.txt
6078
if (*(e + 5) == ':') s = e + 4;
6085
if (!strncasecmp("file",
6086
(*static_cast<DStringGDL*>(urlstru->GetTag(ixSCHEME)))[0].c_str(),
6104
// no scheme, look for port
6108
while (pp-p < 6 && isdigit(*pp)) pp++;
6109
if (pp-p < 6 && (*pp == '/' || *pp == '\0'))
6111
memcpy(port_buf, p, (pp-p));
6112
port_buf[pp-p] = '\0';
6113
urlstru->InitTag("PORT", DStringGDL(port_buf));
6115
else goto just_path;
6124
if (!(p = (const char*)memchr(s, '/', (ue - s))))
6126
if ((p = (const char*)memchr(s, '?', (ue - s)))) e = p;
6127
else if ((p = (const char*)memchr(s, '#', (ue - s)))) e = p;
6130
// check for login and password
6133
if ((pos = string(s, e - s).find_last_of("@")) != string::npos)
6136
if ((pp = (const char*)memchr(s, ':', (p-s))))
6138
if ((pp-s) > 0) urlstru->InitTag("USERNAME", DStringGDL(string(s, (pp - s))));
6140
if (p-pp > 0) urlstru->InitTag("PASSWORD", DStringGDL(string(pp, (p - pp))));
6142
else urlstru->InitTag("USERNAME", DStringGDL(string(s, (p - s))));
6147
if (*s == '[' && *(e-1) == ']') p = s; // IPv6 embedded address
6148
else for(p = e; *p != ':' && p >= s; p--); // memrchr is a GNU extension
6149
if (p >= s && *p == ':')
6151
if ((*static_cast<DStringGDL*>(urlstru->GetTag(ixPORT)))[0].length() == 0)
6154
if (e-p > 5) env->Throw("port cannot be longer then 5 characters");
6157
memcpy(port_buf, p, (e-p));
6158
port_buf[e-p] = '\0';
6159
urlstru->InitTag("PORT", DStringGDL(port_buf));
6165
// check if we have a valid host, if we don't reject the string as url
6166
if ((p-s) < 1) env->Throw("invalid host");
6167
urlstru->InitTag("HOST", DStringGDL(string(s, (p - s))));
6168
if (e == ue) goto end;
6171
if ((p = (const char*)memchr(s, '?', (ue - s))))
6173
pp = strchr(s, '#');
6177
pp = strchr(pp+2, '#');
6179
if (p - s) urlstru->InitTag("PATH", DStringGDL(string(s, (p - s))));
6182
if (pp - ++p) urlstru->InitTag("QUERY", DStringGDL(string(p, (pp - p))));
6186
else if (++p - ue) urlstru->InitTag("QUERY", DStringGDL(string(p, (ue - p))));
6188
else if ((p = (const char*)memchr(s, '#', (ue - s))))
6190
if (p - s) urlstru->InitTag("PATH", DStringGDL(string(s, (p - s))));
6193
if (ue - p) Warning("PARSE_URL: URL fragment left out: #" + string(p, (ue-p)));
6195
else urlstru->InitTag("PATH", DStringGDL(string(s, (ue - s))));
6198
// returning the result
6199
urlstru_guard.release();
6203
BaseGDL* locale_get(EnvT* e)
6205
#ifdef HAVE_LOCALE_H
6207
// make GDL inherit the calling process locale
6208
setlocale(LC_ALL, "");
6209
// note doen the inherited locale
6210
DStringGDL *locale = new DStringGDL(setlocale(LC_CTYPE, NULL));
6211
// return to the C locale
6212
setlocale(LC_ALL, "C");
6216
e->Throw("OS does not provide locale information");
6220
// SA: relies on the contents of the lib::command_line_args vector
6221
// defined and filled with data (pointers) in gdl.cpp
6222
BaseGDL* command_line_args_fun(EnvT* e)
6224
#ifdef PYTHON_MODULE
6225
e->Throw("no command line arguments available (GDL built as a Python module)");
6227
static int countIx = e->KeywordIx("COUNT");
6228
extern std::vector<char*> command_line_args;
6230
// setting the COUNT keyword value
6231
if (e->KeywordPresent(countIx))
6233
e->AssureGlobalKW(countIx);
6234
e->SetKW(countIx, new DLongGDL(command_line_args.size()));
6237
// returning empty string or an array of arguments
6238
if (command_line_args.empty()) return new DStringGDL("");
6241
BaseGDL* ret = new DStringGDL(dimension(command_line_args.size()));
6242
for (size_t i = 0; i < command_line_args.size(); i++)
6243
(*static_cast<DStringGDL*>(ret))[i] = command_line_args[i];
6249
// SA: relies in the uname() from libc (must be there if POSIX)
6250
BaseGDL* get_login_info( EnvT* e)
6253
char* login = getlogin();
6254
if (login == NULL) e->Throw("Failed to get user name from the OS");
6255
struct utsname info;
6256
if (0 != uname(&info)) e->Throw("Failed to get machine name from the OS");
6258
// creating the output anonymous structure
6259
DStructDesc* stru_desc = new DStructDesc("$truct");
6261
stru_desc->AddTag("MACHINE_NAME", &aString);
6262
stru_desc->AddTag("USER_NAME", &aString);
6263
DStructGDL* stru = new DStructGDL(stru_desc, dimension());
6265
// returning the info
6266
stru->InitTag("USER_NAME", DStringGDL(login));
6267
stru->InitTag("MACHINE_NAME", DStringGDL(info.nodename));
6271
// SA: base64 logic in base64.hpp, based on code by Bob Withers (consult base64.hpp)
6272
BaseGDL* idl_base64(EnvT* e)
6274
BaseGDL* p0 = e->GetPar(0);
6277
if (p0->Rank() == 0 && p0->Type() == STRING)
6280
string* str = &((*static_cast<DStringGDL*>(p0))[0]);
6281
if (str->length() == 0) return new DByteGDL(0);
6282
if (str->length() % 4 != 0)
6283
e->Throw("Input string length must be a multiple of 4");
6284
unsigned int retlen = base64::decodeSize(*str);
6285
if (retlen == 0 || retlen > str->length()) e->Throw("No data in the input string");
6286
DByteGDL* ret = new DByteGDL(dimension(retlen));
6287
if (!base64::decode(*str, (char*)&((*ret)[0]), ret->N_Elements()))
6288
e->Throw("Base64 decoder failed");
6291
if (p0->Rank() >= 1 && p0->Type() == BYTE)
6294
return new DStringGDL(
6295
base64::encode((char*)&(*static_cast<DByteGDL*>(p0))[0], p0->N_Elements())
6299
e->Throw("Expecting string or byte array as a first parameter");
6302
BaseGDL* get_drive_list(EnvT* e)
6304
if (e->KeywordPresent(0)) e->SetKW(0, new DLongGDL(0));
6305
return new DStringGDL("");
1
/***************************************************************************
2
basic_fun.cpp - basic GDL library function
5
copyright : (C) 2002 by Marc Schellens (exceptions see below)
6
email : m_schellens@users.sf.net
8
strtok_fun, getenv_fun, tag_names_fun, stregex_fun:
9
(C) 2004 by Peter Messmer
11
***************************************************************************/
13
/***************************************************************************
15
* This program is free software; you can redistribute it and/or modify *
16
* it under the terms of the GNU General Public License as published by *
17
* the Free Software Foundation; either version 2 of the License, or *
18
* (at your option) any later version. *
20
***************************************************************************/
22
#include "includefirst.hpp"
25
// http://sourceforge.net/forum/forum.php?thread_id=3292183&forum_id=338691
34
#include <regex.h> // stregex
37
# include <crt_externs.h>
38
# define environ (*_NSGetEnviron())
41
#if defined(__FreeBSD__) || defined(__sun__) || defined(__OpenBSD__)
42
extern "C" char **environ;
45
#include "nullgdl.hpp"
46
#include "datatypes.hpp"
49
#include "dinterpreter.hpp"
50
#include "basic_pro.hpp"
51
#include "terminfo.hpp"
52
#include "typedefs.hpp"
59
/* max regexp error message length */
60
#define MAX_REGEXPERR_LENGTH 80
63
#define isfinite _finite
65
#define round(f) floor(f+0.5)
66
int strncasecmp(const char *s1, const char *s2, size_t n)
70
while (n-- != 0 && tolower(*s1) == tolower(*s2))
72
if (n == 0 || *s1 == '\0' || *s2 == '\0')
78
return tolower(*(unsigned char *) s1) - tolower(*(unsigned char *) s2);
81
#include <sys/utsname.h>
87
using namespace antlr;
89
// assumes all parameters from pOffs till end are dim
90
void arr( EnvT* e, dimension& dim, SizeT pOffs=0)
93
int nParam=e->NParam()-pOffs;
96
e->Throw( "Incorrect number of arguments.");
98
const string BadDims="Array dimensions must be greater than 0.";
103
BaseGDL* par = e->GetParDefined( pOffs);
106
int ret = par->Scalar2index( newDim);
108
if (ret < 0) throw GDLException(BadDims);
110
if( ret > 0) { // single argument
111
if (newDim < 1) throw GDLException(BadDims);
115
if( ret == 0) { // array argument
117
static_cast<DLongGDL*>(par->Convert2(GDL_LONG, BaseGDL::COPY));
118
auto_ptr<DLongGDL> ind_guard( ind);
121
for(SizeT i =0; i < par->N_Elements(); ++i){
122
if ((*ind)[i] < 1) throw GDLException(BadDims);
127
e->Throw( "arr: should never arrive here.");
131
// max number checked in interpreter
132
SizeT endIx=nParam+pOffs;
133
for( SizeT i=pOffs; i<endIx; i++)
135
BaseGDL* par=e->GetParDefined( i);
138
int ret=par->Scalar2index( newDim);
139
if( ret < 1 || newDim == 0) throw GDLException(BadDims);
144
BaseGDL* bytarr( EnvT* e)
150
throw GDLException( "Array dimensions must be greater than 0");
152
if( e->KeywordSet(0)) return new DByteGDL(dim, BaseGDL::NOZERO);
153
return new DByteGDL(dim);
155
// catch( GDLException& ex)
157
// e->Throw( ex.getMessage());
160
BaseGDL* intarr( EnvT* e)
166
throw GDLException( "Array dimensions must be greater than 0");
168
if( e->KeywordSet(0)) return new DIntGDL(dim, BaseGDL::NOZERO);
169
return new DIntGDL(dim);
171
// catch( GDLException& ex)
173
// e->Throw( "INTARR: "+ex.getMessage());
176
BaseGDL* uintarr( EnvT* e)
182
throw GDLException( "Array dimensions must be greater than 0");
184
if( e->KeywordSet(0)) return new DUIntGDL(dim, BaseGDL::NOZERO);
185
return new DUIntGDL(dim);
187
// catch( GDLException& ex)
189
// e->Throw( "UINTARR: "+ex.getMessage());
192
BaseGDL* lonarr( EnvT* e)
198
throw GDLException( "Array dimensions must be greater than 0");
200
if( e->KeywordSet(0)) return new DLongGDL(dim, BaseGDL::NOZERO);
201
return new DLongGDL(dim);
203
catch( GDLException& ex)
205
e->Throw( "LONARR: "+ex.getMessage());
208
BaseGDL* ulonarr( EnvT* e)
214
throw GDLException( "Array dimensions must be greater than 0");
216
if( e->KeywordSet(0)) return new DULongGDL(dim, BaseGDL::NOZERO);
217
return new DULongGDL(dim);
219
catch( GDLException& ex)
221
e->Throw( "ULONARR: "+ex.getMessage());
225
BaseGDL* lon64arr( EnvT* e)
231
throw GDLException( "Array dimensions must be greater than 0");
233
if( e->KeywordSet(0)) return new DLong64GDL(dim, BaseGDL::NOZERO);
234
return new DLong64GDL(dim);
236
catch( GDLException& ex)
238
e->Throw( "LON64ARR: "+ex.getMessage());
241
BaseGDL* ulon64arr( EnvT* e)
247
throw GDLException( "Array dimensions must be greater than 0");
249
if( e->KeywordSet(0)) return new DULong64GDL(dim, BaseGDL::NOZERO);
250
return new DULong64GDL(dim);
252
catch( GDLException& ex)
254
e->Throw( "ULON64ARR: "+ex.getMessage());
257
BaseGDL* fltarr( EnvT* e)
263
throw GDLException( "Array dimensions must be greater than 0");
265
if( e->KeywordSet(0)) return new DFloatGDL(dim, BaseGDL::NOZERO);
266
return new DFloatGDL(dim);
268
catch( GDLException& ex)
270
e->Throw( "FLTARR: "+ex.getMessage());
273
BaseGDL* dblarr( EnvT* e)
279
throw GDLException( "Array dimensions must be greater than 0");
281
if( e->KeywordSet(0)) return new DDoubleGDL(dim, BaseGDL::NOZERO);
282
return new DDoubleGDL(dim);
284
catch( GDLException& ex)
286
e->Throw( "DBLARR: "+ex.getMessage());
289
BaseGDL* strarr( EnvT* e)
295
throw GDLException( "Array dimensions must be greater than 0");
297
if( e->KeywordSet(0))
298
e->Throw( "Keyword parameters not allowed in call.");
299
return new DStringGDL(dim);
301
catch( GDLException& ex)
303
e->Throw( "STRARR: "+ex.getMessage());
306
BaseGDL* complexarr( EnvT* e)
312
throw GDLException( "Array dimensions must be greater than 0");
314
if( e->KeywordSet(0)) return new DComplexGDL(dim, BaseGDL::NOZERO);
315
return new DComplexGDL(dim);
317
catch( GDLException& ex)
319
e->Throw( "COMPLEXARR: "+ex.getMessage());
322
BaseGDL* dcomplexarr( EnvT* e)
329
if( e->KeywordSet(0)) return new DComplexDblGDL(dim, BaseGDL::NOZERO);
330
return new DComplexDblGDL(dim);
332
catch( GDLException& ex)
334
e->Throw( "DCOMPLEXARR: "+ex.getMessage());
337
BaseGDL* ptrarr( EnvT* e)
343
throw GDLException( "Array dimensions must be greater than 0");
347
// if( e->KeywordSet(0))
348
// ret= new DPtrGDL(dim);//, BaseGDL::NOZERO);
350
// if( e->KeywordSet(1))
351
// ret= new DPtrGDL(dim, BaseGDL::NOZERO);
353
// return new DPtrGDL(dim);
354
if( !e->KeywordSet(1))
355
return new DPtrGDL(dim);
357
ret= new DPtrGDL(dim, BaseGDL::NOZERO);
359
SizeT nEl=ret->N_Elements();
360
SizeT sIx=e->NewHeap(nEl);
361
// #pragma omp parallel if (nEl >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl))
364
for( SizeT i=0; i<nEl; i++)
369
catch( GDLException& ex)
371
e->Throw( "PTRARR: "+ex.getMessage());
374
BaseGDL* objarr( EnvT* e)
380
throw GDLException( "Array dimensions must be greater than 0");
382
// reference counting if( e->KeywordSet(0)) return new DObjGDL(dim, BaseGDL::NOZERO);
383
return new DObjGDL(dim);
385
catch( GDLException& ex)
387
e->Throw( "OBJARR: "+ex.getMessage());
391
BaseGDL* ptr_new( EnvT* e)
393
int nParam=e->NParam();
397
// new ptr from undefined variable is allowed as well
398
BaseGDL* p= e->GetPar( 0);
401
DPtr heapID= e->NewHeap();
402
return new DPtrGDL( heapID);
405
if( e->KeywordSet(0)) // NO_COPY
407
BaseGDL** p= &e->GetPar( 0);
409
// e->Throw( "Parameter undefined: "+
410
// e->GetParString(0));
412
DPtr heapID= e->NewHeap( 1, *p);
414
return new DPtrGDL( heapID);
418
BaseGDL* p= e->GetParDefined( 0);
420
DPtr heapID= e->NewHeap( 1, p->Dup());
421
return new DPtrGDL( heapID);
426
if( e->KeywordSet(1)) // ALLOCATE_HEAP
428
DPtr heapID= e->NewHeap();
429
return new DPtrGDL( heapID);
433
return new DPtrGDL( 0); // null ptr
438
BaseGDL* ptr_valid( EnvT* e)
440
int nParam=e->NParam();
442
if( e->KeywordPresent( 1)) // COUNT
444
e->SetKW( 1, new DLongGDL( e->Interpreter()->HeapSize()));
449
return e->Interpreter()->GetAllHeap();
452
BaseGDL* p = e->GetPar( 0);
455
return new DByteGDL( 0);
458
if( e->KeywordSet( 0)) // CAST
460
DLongGDL* pL = dynamic_cast<DLongGDL*>( p);
461
auto_ptr<DLongGDL> pL_guard;
464
pL = static_cast<DLongGDL*>(p->Convert2(GDL_LONG,BaseGDL::COPY));
468
SizeT nEl = pL->N_Elements();
469
DPtrGDL* ret = new DPtrGDL( pL->Dim()); // zero
470
GDLInterpreter* interpreter = e->Interpreter();
471
for( SizeT i=0; i<nEl; ++i)
473
if( interpreter->PtrValid( (*pL)[ i]))
474
(*ret)[ i] = (*pL)[ i];
479
DPtrGDL* pPtr = dynamic_cast<DPtrGDL*>( p);
482
return new DByteGDL( p->Dim()); // zero
485
SizeT nEl = pPtr->N_Elements();
486
DByteGDL* ret = new DByteGDL( pPtr->Dim()); // zero
487
GDLInterpreter* interpreter = e->Interpreter();
488
for( SizeT i=0; i<nEl; ++i)
490
if( interpreter->PtrValid( (*pPtr)[ i]))
496
BaseGDL* obj_valid( EnvT* e)
498
int nParam=e->NParam();
500
if( e->KeywordPresent( 1)) // COUNT
502
e->SetKW( 1, new DLongGDL( e->Interpreter()->ObjHeapSize()));
507
return e->Interpreter()->GetAllObjHeap();
510
BaseGDL* p = e->GetPar( 0);
513
return new DByteGDL( 0);
516
if( e->KeywordSet( 0)) // CAST
518
DLongGDL* pL = dynamic_cast<DLongGDL*>( p);
519
auto_ptr<DLongGDL> pL_guard;
522
pL = static_cast<DLongGDL*>(p->Convert2(GDL_LONG,BaseGDL::COPY));
527
SizeT nEl = pL->N_Elements();
528
DObjGDL* ret = new DObjGDL( pL->Dim()); // zero
529
GDLInterpreter* interpreter = e->Interpreter();
530
for( SizeT i=0; i<nEl; ++i)
532
if( interpreter->ObjValid( (*pL)[ i]))
533
(*ret)[ i] = (*pL)[ i];
538
DObjGDL* pObj = dynamic_cast<DObjGDL*>( p);
541
return new DByteGDL( p->Dim()); // zero
544
SizeT nEl = pObj->N_Elements();
545
DByteGDL* ret = new DByteGDL( pObj->Dim()); // zero
546
GDLInterpreter* interpreter = e->Interpreter();
547
for( SizeT i=0; i<nEl; ++i)
549
if( interpreter->ObjValid( (*pObj)[ i]))
555
BaseGDL* obj_new( EnvT* e)
557
StackGuard<EnvStackT> guard( e->Interpreter()->CallStack());
559
int nParam=e->NParam();
563
return new DObjGDL( 0);
567
e->AssureScalarPar<DStringGDL>( 0, objName);
569
// this is a struct name -> convert to UPPERCASE
570
objName=StrUpCase(objName);
571
if( objName == "IDL_OBJECT")
572
objName = GDL_OBJECT_NAME; // replacement also done in GDLParser
574
DStructDesc* objDesc=e->Interpreter()->GetStruct( objName, e->CallingNode());
576
DStructGDL* objStruct= new DStructGDL( objDesc, dimension());
578
DObj objID= e->NewObjHeap( 1, objStruct); // owns objStruct
580
BaseGDL* newObj = new DObjGDL( objID); // the object
583
// call INIT function
584
DFun* objINIT= objDesc->GetFun( "INIT");
587
// morph to obj environment and push it onto the stack again
588
e->PushNewEnvUD( objINIT, 1, &newObj);
590
BaseGDL* res=e->Interpreter()->call_fun( objINIT->GetTree());
592
if( res == NULL || (!res->Scalar()) || res->False())
595
return new DObjGDL( 0);
600
e->FreeObjHeap( objID); // newObj might be changed
608
BaseGDL* bindgen( EnvT* e)
614
throw GDLException( "Array dimensions must be greater than 0");
616
return new DByteGDL(dim, BaseGDL::INDGEN);
618
catch( GDLException& ex)
620
e->Throw( "BINDGEN: "+ex.getMessage());
623
// keywords not supported yet
624
BaseGDL* indgen( EnvT* e)
628
// Defaulting to GDL_INT
629
DType type = GDL_INT;
631
static int kwIx1 = e->KeywordIx("BYTE");
632
if (e->KeywordSet(kwIx1)){ type = GDL_BYTE; }
634
static int kwIx2 = e->KeywordIx("COMPLEX");
635
if (e->KeywordSet(kwIx2)){ type = GDL_COMPLEX; }
637
static int kwIx3 = e->KeywordIx("DCOMPLEX");
638
if (e->KeywordSet(kwIx3)){ type = GDL_COMPLEXDBL; }
640
static int kwIx4 = e->KeywordIx("DOUBLE");
641
if (e->KeywordSet(kwIx4)){ type = GDL_DOUBLE; }
643
static int kwIx5 = e->KeywordIx("FLOAT");
644
if (e->KeywordSet(kwIx5)){ type = GDL_FLOAT; }
646
static int kwIx6 = e->KeywordIx("L64");
647
if (e->KeywordSet(kwIx6)){ type = GDL_LONG64; }
649
static int kwIx7 = e->KeywordIx("LONG");
650
if (e->KeywordSet(kwIx7)){ type = GDL_LONG; }
652
static int kwIx8 = e->KeywordIx("STRING");
653
if (e->KeywordSet(kwIx8)){ type = GDL_STRING; }
655
static int kwIx9 = e->KeywordIx("UINT");
656
if (e->KeywordSet(kwIx9)){ type = GDL_UINT; }
658
static int kwIx10 = e->KeywordIx("UL64");
659
if (e->KeywordSet(kwIx10)){ type = GDL_ULONG64; }
661
static int kwIx11 = e->KeywordIx("ULONG");
662
if (e->KeywordSet(kwIx11)){ type = GDL_ULONG; }
666
// Seeing if the user passed in a TYPE code
667
static int kwIx12 = e->KeywordIx("TYPE");
668
if ( e->KeywordPresent(kwIx12)){
670
e->AssureLongScalarKW(kwIx12, temp_long);
671
type = static_cast<DType>(temp_long);
676
throw GDLException( "Array dimensions must be greater than 0");
680
case GDL_INT: return new DIntGDL(dim, BaseGDL::INDGEN);
681
case GDL_BYTE: return new DByteGDL(dim, BaseGDL::INDGEN);
682
case GDL_COMPLEX: return new DComplexGDL(dim, BaseGDL::INDGEN);
683
case GDL_COMPLEXDBL: return new DComplexDblGDL(dim, BaseGDL::INDGEN);
684
case GDL_DOUBLE: return new DDoubleGDL(dim, BaseGDL::INDGEN);
685
case GDL_FLOAT: return new DFloatGDL(dim, BaseGDL::INDGEN);
686
case GDL_LONG64: return new DLong64GDL(dim, BaseGDL::INDGEN);
687
case GDL_LONG: return new DLongGDL(dim, BaseGDL::INDGEN);
689
DULongGDL* iGen = new DULongGDL(dim, BaseGDL::INDGEN);
690
return iGen->Convert2(GDL_STRING);
692
case GDL_UINT: return new DUIntGDL(dim, BaseGDL::INDGEN);
693
case GDL_ULONG64: return new DULong64GDL(dim, BaseGDL::INDGEN);
694
case GDL_ULONG: return new DULongGDL(dim, BaseGDL::INDGEN);
696
e->Throw( "Invalid type code specified.");
700
catch( GDLException& ex)
702
e->Throw( ex.getMessage());
706
BaseGDL* uindgen( EnvT* e)
712
throw GDLException( "Array dimensions must be greater than 0");
714
return new DUIntGDL(dim, BaseGDL::INDGEN);
716
catch( GDLException& ex)
718
e->Throw( "UINDGEN: "+ex.getMessage());
721
BaseGDL* sindgen( EnvT* e)
727
throw GDLException( "Array dimensions must be greater than 0");
729
DULongGDL* iGen = new DULongGDL(dim, BaseGDL::INDGEN);
730
return iGen->Convert2( GDL_STRING);
732
catch( GDLException& ex)
734
e->Throw( "SINDGEN: "+ex.getMessage());
737
BaseGDL* lindgen( EnvT* e)
742
return new DLongGDL(dim, BaseGDL::INDGEN);
744
catch( GDLException& ex)
746
e->Throw( "LINDGEN: "+ex.getMessage());
749
BaseGDL* ulindgen( EnvT* e)
755
throw GDLException( "Array dimensions must be greater than 0");
757
return new DULongGDL(dim, BaseGDL::INDGEN);
759
catch( GDLException& ex)
761
e->Throw( "ULINDGEN: "+ex.getMessage());
764
BaseGDL* l64indgen( EnvT* e)
770
throw GDLException( "Array dimensions must be greater than 0");
772
return new DLong64GDL(dim, BaseGDL::INDGEN);
774
catch( GDLException& ex)
776
e->Throw( "L64INDGEN: "+ex.getMessage());
779
BaseGDL* ul64indgen( EnvT* e)
785
throw GDLException( "Array dimensions must be greater than 0");
787
return new DULong64GDL(dim, BaseGDL::INDGEN);
789
catch( GDLException& ex)
791
e->Throw( "UL64INDGEN: "+ex.getMessage());
794
BaseGDL* findgen( EnvT* e)
800
throw GDLException( "Array dimensions must be greater than 0");
802
return new DFloatGDL(dim, BaseGDL::INDGEN);
804
catch( GDLException& ex)
806
e->Throw( "FINDGEN: "+ex.getMessage());
809
BaseGDL* dindgen( EnvT* e)
815
throw GDLException( "Array dimensions must be greater than 0");
817
return new DDoubleGDL(dim, BaseGDL::INDGEN);
819
catch( GDLException& ex)
821
e->Throw( "DINDGEN: "+ex.getMessage());
824
BaseGDL* cindgen( EnvT* e)
830
throw GDLException( "Array dimensions must be greater than 0");
832
return new DComplexGDL(dim, BaseGDL::INDGEN);
834
catch( GDLException& ex)
836
e->Throw( "CINDGEN: "+ex.getMessage());
839
BaseGDL* dcindgen( EnvT* e)
845
throw GDLException( "Array dimensions must be greater than 0");
847
return new DComplexDblGDL(dim, BaseGDL::INDGEN);
849
catch( GDLException& ex)
851
e->Throw( "DCINDGEN: "+ex.getMessage());
855
// only called from CALL_FUNCTION
856
// otherwise done directly in FCALL_LIB_N_ELEMENTSNode::Eval();
857
// (but must be defined anyway for LibInit() for correct parametrization)
858
// N_ELEMENTS is special because on error it just returns 0L
859
// (the error is just caught and dropped)
860
BaseGDL* n_elements( EnvT* e)
862
SizeT nParam=e->NParam(1);
864
BaseGDL* p0=e->GetPar( 0);
866
if( p0 == NULL) return new DLongGDL( 0);
867
return new DLongGDL( p0->N_Elements());
870
// e->Throw("Internal error: lib::n_elements called.");
871
// return NULL; // get rid of compiler warning
874
template< typename ComplexGDL, typename Complex, typename Float>
875
BaseGDL* complex_fun_template( EnvT* e)
877
SizeT nParam=e->NParam( 1);
882
BaseGDL* p0=e->GetParDefined( 0);
883
BaseGDL* p1=e->GetParDefined( 1);
884
auto_ptr<Float> p0Float( static_cast<Float*>
885
(p0->Convert2( Float::t,BaseGDL::COPY)));
886
auto_ptr<Float> p1Float( static_cast<Float*>
887
(p1->Convert2( Float::t,BaseGDL::COPY)));
888
if( p0Float->Rank() == 0)
890
ComplexGDL* res = new ComplexGDL( p1Float->Dim(),
893
SizeT nE=p1Float->N_Elements();
894
// #pragma omp parallel if (nE >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nE))
897
for( SizeT i=0; i<nE; i++)
899
(*res)[i]=Complex( (*p0Float)[0], (*p1Float)[i]);
904
else if( p1Float->Rank() == 0)
906
ComplexGDL* res = new ComplexGDL( p0Float->Dim(),
909
SizeT nE=p0Float->N_Elements();
910
// #pragma omp parallel if (nE >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nE))
913
for( SizeT i=0; i<nE; i++)
915
(*res)[i]=Complex( (*p0Float)[i], (*p1Float)[0]);
920
else if( p0Float->N_Elements() >= p1Float->N_Elements())
922
ComplexGDL* res = new ComplexGDL( p1Float->Dim(),
925
SizeT nE=p1Float->N_Elements();
926
// #pragma omp parallel if (nE >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nE))
929
for( SizeT i=0; i<nE; i++)
931
(*res)[i]=Complex( (*p0Float)[i], (*p1Float)[i]);
938
ComplexGDL* res = new ComplexGDL( p0Float->Dim(),
941
SizeT nE=p0Float->N_Elements();
942
// #pragma omp parallel if (nE >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nE))
945
for( SizeT i=0; i<nE; i++)
947
(*res)[i]=Complex( (*p0Float)[i], (*p1Float)[i]);
955
// SA: see tracker item 3151760
956
BaseGDL* p0 = e->GetParDefined( 0);
957
if (ComplexGDL::t == p0->Type() && e->GlobalPar(0)) return p0;
958
return p0->Convert2( ComplexGDL::t, BaseGDL::COPY);
961
else // GDL_COMPLEX( expr, offs, dim1,..,dim8)
963
BaseGDL* p0 = e->GetParDefined( 0);
964
// *** WRONG: with offs data is converted bytewise
965
auto_ptr<Float> p0Float(static_cast<Float*>
966
(p0->Convert2( Float::t,
969
e->AssureLongScalarPar( 1, offs);
974
SizeT nElCreate=dim.NDimElements();
976
SizeT nElSource=p0->N_Elements();
978
if( (offs+2*nElCreate) > nElSource)
979
e->Throw( "Specified offset to"
980
" array is out of range: "+e->GetParString(0));
982
ComplexGDL* res=new ComplexGDL( dim, BaseGDL::NOZERO);
984
// #pragma omp parallel if (nElCreate >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nElCreate))
987
for( SizeT i=0; i<nElCreate; i++)
989
SizeT srcIx=2*i+offs;
990
(*res)[i]=Complex( (*p0Float)[srcIx], (*p0Float)[srcIx+1]);
997
BaseGDL* complex_fun( EnvT* e)
999
if (e->KeywordSet("DOUBLE")) {
1000
return complex_fun_template< DComplexDblGDL, DComplexDbl, DDoubleGDL>( e);
1002
return complex_fun_template< DComplexGDL, DComplex, DFloatGDL>( e);
1005
BaseGDL* dcomplex_fun( EnvT* e)
1007
return complex_fun_template< DComplexDblGDL, DComplexDbl, DDoubleGDL>( e);
1010
template< class TargetClass>
1011
BaseGDL* type_fun( EnvT* e)
1013
SizeT nParam=e->NParam(1);
1017
BaseGDL* p0=e->GetParDefined( 0);
1019
assert( dynamic_cast< EnvUDT*>( e->Caller()) != NULL);
1021
// type_fun( expr) just convert
1022
if( static_cast< EnvUDT*>( e->Caller())->GetIOError() != NULL)
1023
return p0->Convert2( TargetClass::t,
1024
BaseGDL::COPY_THROWIOERROR);
1025
// SA: see tracker item no. 3151760
1026
else if (TargetClass::t == p0->Type() && e->GlobalPar(0))
1029
return p0->Convert2( TargetClass::t, BaseGDL::COPY);
1032
BaseGDL* p0=e->GetNumericParDefined( 0);
1034
// GDL_BYTE( expr, offs, dim1,..,dim8)
1036
e->AssureLongScalarPar( 1, offs);
1043
TargetClass* res=new TargetClass( dim, BaseGDL::NOZERO);
1045
SizeT nByteCreate=res->NBytes(); // net size of new data
1047
SizeT nByteSource=p0->NBytes(); // net size of src
1049
if( offs < 0 || (offs+nByteCreate) > nByteSource)
1052
e->Throw( "Specified offset to"
1053
" expression is out of range: "+e->GetParString(0));
1056
//*** POSSIBLE ERROR because of alignment here
1057
void* srcAddr = static_cast<void*>( static_cast<char*>(p0->DataAddr()) +
1059
void* dstAddr = static_cast<void*>(&(*res)[0]);
1060
memcpy( dstAddr, srcAddr, nByteCreate);
1062
// char* srcAddr = reinterpret_cast<char*>(p0->DataAddr());
1063
// char* dstAddr = reinterpret_cast<char*>(&(*res)[0]);
1064
// copy( srcAddr, srcAddr+nByteCreate, dstAddr);
1069
BaseGDL* byte_fun( EnvT* e)
1071
return type_fun<DByteGDL>( e);
1073
BaseGDL* uint_fun( EnvT* e)
1075
return type_fun<DUIntGDL>( e);
1077
BaseGDL* long_fun( EnvT* e)
1079
return type_fun<DLongGDL>( e);
1081
BaseGDL* ulong_fun( EnvT* e)
1083
return type_fun<DULongGDL>( e);
1085
BaseGDL* long64_fun( EnvT* e)
1087
return type_fun<DLong64GDL>( e);
1089
BaseGDL* ulong64_fun( EnvT* e)
1091
return type_fun<DULong64GDL>( e);
1093
BaseGDL* float_fun( EnvT* e)
1095
return type_fun<DFloatGDL>( e);
1097
BaseGDL* double_fun( EnvT* e)
1099
return type_fun<DDoubleGDL>( e);
1101
// GDL_STRING function behaves different
1102
BaseGDL* string_fun( EnvT* e)
1104
SizeT nParam=e->NParam();
1107
e->Throw( "Incorrect number of arguments.");
1109
bool printKey = e->KeywordSet( 4);
1112
// SA: handling special VMS-compatibility syntax, e.g.: string(1,'$(F)')
1113
// (if nor FORMAT neither PRINT defined, >1 parameter, last param is scalar string
1114
// which begins with "$(" or "(" but is not "()" then last param [minus "$"] is treated as FORMAT)
1115
bool vmshack = false;
1116
if (!printKey && (e->GetKW(0) == NULL) && nParam > 1)
1119
BaseGDL* par = e->GetParDefined(nParam - 1);
1120
if (par->Type() == GDL_STRING && par->Scalar())
1122
int dollar = (*static_cast<DStringGDL*>(par))[0].compare(0,2,"$(");
1123
if (dollar == 0 || ((*static_cast<DStringGDL*>(par))[0].compare(0,1,"(") == 0 && (*static_cast<DStringGDL*>(par))[0] != "()"))
1125
e->SetKeyword("FORMAT", new DStringGDL(
1126
(*static_cast<DStringGDL*>(par))[0].c_str() + (dollar == 0 ? 1 : 0)
1132
BaseGDL* format_kw = e->GetKW( 0);
1133
bool formatKey = format_kw != NULL;
1135
if (formatKey && format_kw->Type() == GDL_STRING && (*static_cast<DStringGDL*>(format_kw))[0] == "") formatKey = false;
1137
if( printKey || formatKey) // PRINT or FORMAT
1142
if( printKey) // otherwise: FORMAT -> width is ignored
1144
// for /PRINT always a terminal width of 80 is assumed
1145
width = 80;//TermWidth();
1151
e->ShiftParNumbering(1);
1153
print_os( &os, e, parOffset, width);
1156
e->ShiftParNumbering(-1);
1164
if( os.good()) buf.push_back( line);
1167
SizeT bufSize = buf.size();
1169
e->Throw( "Internal error: print buffer empty.");
1173
DStringGDL* retVal =
1174
new DStringGDL( dimension( bufSize), BaseGDL::NOZERO);
1176
for( SizeT i=0; i<bufSize; ++i)
1177
(*retVal)[ i] = buf[ i];
1182
return new DStringGDL( buf[0]);
1186
if( nParam == 1) // nParam == 1 -> conversion
1188
BaseGDL* p0 = e->GetParDefined( 0);
1189
// SA: see tracker item no. 3151760
1190
if (p0->Type() == GDL_STRING && e->GlobalPar(0)) return p0;
1191
return p0->Convert2( GDL_STRING, BaseGDL::COPY);
1193
else // concatenation
1196
for( SizeT i=0; i<nParam; ++i)
1198
BaseGDL* p = e->GetParDefined( i);
1199
DStringGDL* sP = static_cast<DStringGDL*>
1200
( p->Convert2(GDL_STRING,
1201
BaseGDL::COPY_BYTE_AS_INT));
1203
SizeT nEl = sP->N_Elements();
1204
for( SizeT e=0; e<nEl; ++e)
1208
// IDL here breaks the string into tty-width substrings
1209
return new DStringGDL( s);
1214
BaseGDL* fix_fun( EnvT* e)
1216
DIntGDL* type = e->IfDefGetKWAs<DIntGDL>( 0);
1218
int typ = (*type)[0];
1219
if (typ == GDL_BYTE)
1221
// SA: slow yet simple solution using GDL_BYTE->GDL_INT->GDL_BYTE conversion
1222
return (e->KeywordSet(1) && e->GetPar(0)->Type() == GDL_STRING)
1223
? type_fun<DIntGDL>( e)->Convert2(GDL_BYTE, BaseGDL::CONVERT)
1224
: type_fun<DByteGDL>( e);
1226
if (typ == 0 || typ == GDL_INT) return type_fun<DIntGDL>( e);
1227
if (typ == GDL_UINT) return type_fun<DUIntGDL>( e);
1228
if (typ == GDL_LONG) return type_fun<DLongGDL>( e);
1229
if (typ == GDL_ULONG) return type_fun<DULongGDL>( e);
1230
if (typ == GDL_LONG64) return type_fun<DLong64GDL>( e);
1231
if (typ == GDL_ULONG64) return type_fun<DULong64GDL>( e);
1232
if (typ == GDL_FLOAT) return type_fun<DFloatGDL>( e);
1233
if (typ == GDL_DOUBLE) return type_fun<DDoubleGDL>( e);
1234
if (typ == GDL_COMPLEX) return type_fun<DComplexGDL>( e);
1235
if (typ == GDL_COMPLEXDBL) return type_fun<DComplexDblGDL>( e);
1236
if (typ == GDL_STRING)
1238
// SA: calling GDL_STRING() with correct parameters
1239
static int stringIx = LibFunIx("STRING");
1241
assert( stringIx >= 0);
1243
EnvT* newEnv= new EnvT(e, libFunList[stringIx], NULL);
1245
auto_ptr<EnvT> guard( newEnv);
1247
newEnv->SetNextPar(&e->GetPar(0)); // pass as global
1248
if (e->KeywordSet(1) && e->GetPar(0)->Type() == GDL_BYTE)
1249
newEnv->SetKeyword("PRINT", new DIntGDL(1));
1250
// e->Interpreter()->CallStack().push_back( newEnv);
1251
return static_cast<DLibFun*>(newEnv->GetPro())->Fun()(newEnv);
1253
e->Throw( "Improper TYPE value.");
1255
return type_fun<DIntGDL>( e);
1258
BaseGDL* call_function( EnvT* e)
1260
int nParam=e->NParam();
1262
e->Throw( "No function specified.");
1265
e->AssureScalarPar<DStringGDL>( 0, callF);
1267
// this is a function name -> convert to UPPERCASE
1268
callF = StrUpCase( callF);
1270
// first search library funcedures
1271
int funIx=LibFunIx( callF);
1274
// e->PushNewEnv( libFunList[ funIx], 1);
1276
// EnvT* newEnv = static_cast<EnvT*>(e->Interpreter()->CallStack().back());
1278
// handle direct call functions
1279
if( libFunList[ funIx]->DirectCall())
1281
BaseGDL* directCallParameter = e->GetParDefined(1);
1283
static_cast<DLibFunDirect*>(libFunList[ funIx])->FunDirect()(directCallParameter, true /*isReference*/);
1288
EnvT* newEnv = e->NewEnv( libFunList[ funIx], 1);
1289
auto_ptr<EnvT> guard( newEnv);
1290
return static_cast<DLibFun*>(newEnv->GetPro())->Fun()(newEnv);
1295
// no direct call here
1297
StackGuard<EnvStackT> guard( e->Interpreter()->CallStack());
1299
funIx = GDLInterpreter::GetFunIx( callF);
1301
e->PushNewEnvUD( funList[ funIx], 1);
1304
EnvUDT* newEnv = static_cast<EnvUDT*>(e->Interpreter()->CallStack().back());
1305
return e->Interpreter()->call_fun(static_cast<DSubUD*>(newEnv->GetPro())->GetTree());
1309
BaseGDL* call_method_function( EnvT* e)
1311
StackGuard<EnvStackT> guard( e->Interpreter()->CallStack());
1313
int nParam=e->NParam();
1315
e->Throw( "Name and object reference"
1316
" must be specified.");
1319
e->AssureScalarPar<DStringGDL>( 0, callP);
1321
// this is a procedure name -> convert to UPPERCASE
1322
callP = StrUpCase( callP);
1324
DStructGDL* oStruct = e->GetObjectPar( 1);
1326
DFun* method= oStruct->Desc()->GetFun( callP);
1329
e->Throw( "Method not found: "+callP);
1331
e->PushNewEnvUD( method, 2, &e->GetPar( 1));
1334
return e->Interpreter()->call_fun( method->GetTree());
1339
BaseGDL* execute( EnvT* e)
1341
int nParam=e->NParam( 1);
1343
bool quietCompile = false;
1346
BaseGDL* p1 = e->GetParDefined( 1);
1349
e->Throw( "Expression must be scalar in this context: "+
1350
e->GetParString(1));
1352
quietCompile = p1->True();
1355
if (e->GetParDefined(0)->Rank() != 0)
1356
e->Throw("Expression must be scalar in this context: "+e->GetParString(0));
1359
e->AssureScalarPar<DStringGDL>( 0, line);
1361
// remove current environment (own one)
1362
assert( dynamic_cast<EnvUDT*>(e->Caller()) != NULL);
1363
EnvUDT* caller = static_cast<EnvUDT*>(e->Caller());
1364
// e->Interpreter()->CallStack().pop_back();
1366
// wrong: e is guarded, do not delete it here
1369
istringstream istr(line+"\n");
1373
GDLLexer lexer(istr, "", caller->CompileOpt());
1374
GDLParser& parser=lexer.Parser();
1376
parser.interactive();
1378
theAST=parser.getAST();
1380
catch( GDLException& ex)
1382
if( !quietCompile) GDLInterpreter::ReportCompileError( ex);
1383
return new DIntGDL( 0);
1385
catch( ANTLRException ex)
1387
if( !quietCompile) cerr << "EXECUTE: Lexer/Parser exception: " <<
1388
ex.getMessage() << endl;
1389
return new DIntGDL( 0);
1392
if( theAST == NULL) return new DIntGDL( 1);
1397
GDLTreeParser treeParser( caller);
1399
treeParser.interactive(theAST);
1401
trAST=treeParser.getAST();
1403
catch( GDLException& ex)
1405
if( !quietCompile) GDLInterpreter::ReportCompileError( ex);
1406
return new DIntGDL( 0);
1409
catch( ANTLRException ex)
1411
if( !quietCompile) cerr << "EXECUTE: Compiler exception: " <<
1412
ex.getMessage() << endl;
1413
return new DIntGDL( 0);
1416
if( trAST == NULL) return new DIntGDL( 1);
1418
int nForLoopsIn = caller->NForLoops();
1421
ProgNodeP progAST = ProgNode::NewProgNode( trAST);
1422
auto_ptr< ProgNode> progAST_guard( progAST);
1424
int nForLoops = ProgNode::NumberForLoops( progAST, nForLoopsIn);
1425
caller->ResizeForLoops( nForLoops);
1427
progAST->setLine( e->GetLineNumber());
1429
RetCode retCode = caller->Interpreter()->execute( progAST);
1431
caller->ResizeForLoops( nForLoopsIn);
1433
if( retCode == RC_OK)
1434
return new DIntGDL( 1);
1436
return new DIntGDL( 0);
1438
catch( GDLException& ex)
1440
caller->ResizeForLoops( nForLoopsIn);
1441
// are we throwing to target environment?
1442
// if( ex.GetTargetEnv() == NULL)
1443
if( !quietCompile) cerr << "EXECUTE: " <<
1444
ex.getMessage() << endl;
1445
return new DIntGDL( 0);
1447
catch( ANTLRException ex)
1449
caller->ResizeForLoops( nForLoopsIn);
1451
if( !quietCompile) cerr << "EXECUTE: Interpreter exception: " <<
1452
ex.getMessage() << endl;
1453
return new DIntGDL( 0);
1456
return new DIntGDL( 0); // control flow cannot reach here - compiler shut up
1459
BaseGDL* assoc( EnvT* e)
1461
SizeT nParam=e->NParam( 2);
1464
e->AssureLongScalarPar( 0, lun);
1466
bool stdLun = check_lun( e, lun);
1468
e->Throw( "File unit does not allow"
1469
" this operation. Unit: "+i2s( lun));
1472
if( nParam >= 3) e->AssureLongScalarPar( 2, offset);
1474
BaseGDL* arr = e->GetParDefined( 1);
1476
if( arr->StrictScalar())
1477
e->Throw( "Scalar variable not allowed in this"
1478
" context: "+e->GetParString(1));
1480
return arr->AssocVar( lun, offset);
1483
// gdl_ naming because of weired namespace problem in MSVC
1484
BaseGDL* gdl_logical_and( EnvT* e)
1486
SizeT nParam=e->NParam();
1489
"Incorrect number of arguments.");
1491
BaseGDL* e1=e->GetParDefined( 0);//, "LOGICAL_AND");
1492
BaseGDL* e2=e->GetParDefined( 1);//, "LOGICAL_AND");
1494
ULong nEl1 = e1->N_Elements();
1495
ULong nEl2 = e2->N_Elements();
1497
Data_<SpDByte>* res;
1503
res= new Data_<SpDByte>( e2->Dim(), BaseGDL::NOZERO);
1504
// #pragma omp parallel if (nEl2 >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl2))
1507
for( SizeT i=0; i < nEl2; i++)
1508
(*res)[i] = e2->LogTrue( i) ? 1 : 0;
1513
return new Data_<SpDByte>( e2->Dim());
1516
else if( e2->Scalar())
1520
res= new Data_<SpDByte>( e1->Dim(), BaseGDL::NOZERO);
1521
// #pragma omp parallel if (nEl1 >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl1))
1524
for( SizeT i=0; i < nEl1; i++)
1525
(*res)[i] = e1->LogTrue( i) ? 1 : 0;
1530
return new Data_<SpDByte>( e1->Dim());
1533
else if( nEl2 < nEl1)
1535
res= new Data_<SpDByte>( e2->Dim(), BaseGDL::NOZERO);
1536
// #pragma omp parallel if (nEl2 >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl2))
1539
for( SizeT i=0; i < nEl2; i++)
1540
(*res)[i] = (e1->LogTrue( i) && e2->LogTrue( i)) ? 1 : 0;
1543
else // ( nEl2 >= nEl1)
1545
res= new Data_<SpDByte>( e1->Dim(), BaseGDL::NOZERO);
1546
// #pragma omp parallel if (nEl1 >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl1))
1549
for( SizeT i=0; i < nEl1; i++)
1550
(*res)[i] = (e1->LogTrue( i) && e2->LogTrue( i)) ? 1 : 0;
1556
// gdl_ naming because of weired namespace problem in MSVC
1557
BaseGDL* gdl_logical_or( EnvT* e)
1559
SizeT nParam=e->NParam();
1562
"Incorrect number of arguments.");
1564
BaseGDL* e1=e->GetParDefined( 0);//, "LOGICAL_OR");
1565
BaseGDL* e2=e->GetParDefined( 1);//, "LOGICAL_OR");
1567
ULong nEl1 = e1->N_Elements();
1568
ULong nEl2 = e2->N_Elements();
1570
Data_<SpDByte>* res;
1576
res= new Data_<SpDByte>( e2->Dim(), BaseGDL::NOZERO);
1577
// #pragma omp parallel if (nEl2 >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl2))
1580
for( SizeT i=0; i < nEl2; i++)
1586
res= new Data_<SpDByte>( e2->Dim(), BaseGDL::NOZERO);
1587
// #pragma omp parallel if (nEl2 >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl2))
1590
for( SizeT i=0; i < nEl2; i++)
1591
(*res)[i] = e2->LogTrue( i) ? 1 : 0;
1595
else if( e2->Scalar())
1599
res= new Data_<SpDByte>( e1->Dim(), BaseGDL::NOZERO);
1600
// #pragma omp parallel if (nEl1 >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl1))
1603
for( SizeT i=0; i < nEl1; i++)
1609
res= new Data_<SpDByte>( e1->Dim(), BaseGDL::NOZERO);
1610
// #pragma omp parallel if (nEl1 >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl1))
1613
for( SizeT i=0; i < nEl1; i++)
1614
(*res)[i] = e1->LogTrue( i) ? 1 : 0;
1618
else if( nEl2 < nEl1)
1620
res= new Data_<SpDByte>( e2->Dim(), BaseGDL::NOZERO);
1621
// #pragma omp parallel if (nEl2 >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl2))
1624
for( SizeT i=0; i < nEl2; i++)
1625
(*res)[i] = (e1->LogTrue( i) || e2->LogTrue( i)) ? 1 : 0;
1628
else // ( nEl2 >= nEl1)
1630
res= new Data_<SpDByte>( e1->Dim(), BaseGDL::NOZERO);
1631
// #pragma omp parallel if (nEl1 >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl1))
1634
for( SizeT i=0; i < nEl1; i++)
1635
(*res)[i] = (e1->LogTrue( i) || e2->LogTrue( i)) ? 1 : 0;
1641
BaseGDL* logical_true( BaseGDL* e1, bool isReference)//( EnvT* e);
1643
assert( e1 != NULL);
1644
assert( e1->N_Elements() > 0);
1647
// SizeT nParam=e->NParam();
1650
// "Incorrect number of arguments.");
1652
// BaseGDL* e1=e->GetParDefined( 0);//, "LOGICAL_TRUE");
1654
ULong nEl1 = e1->N_Elements();
1656
Data_<SpDByte>* res = new Data_<SpDByte>( e1->Dim(), BaseGDL::NOZERO);
1657
// #pragma omp parallel if (nEl1 >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl1))
1660
for( SizeT i=0; i < nEl1; i++)
1661
(*res)[i] = e1->LogTrue( i) ? 1 : 0;
1666
BaseGDL* replicate( EnvT* e)
1668
SizeT nParam=e->NParam();
1670
e->Throw( "Incorrect number of arguments.");
1674
BaseGDL* p0=e->GetParDefined( 0);//, "REPLICATE");
1676
e->Throw( "Expression must be a scalar in this context: "+
1677
e->GetParString(0));
1679
return p0->New( dim, BaseGDL::INIT);
1682
BaseGDL* strtrim( EnvT* e)
1684
SizeT nParam = e->NParam( 1);//, "STRTRIM");
1686
BaseGDL* p0 = e->GetPar( 0);
1689
"Variable is undefined: "+
1690
e->GetParString(0));
1691
DStringGDL* p0S = static_cast<DStringGDL*>
1692
(p0->Convert2(GDL_STRING,BaseGDL::COPY));
1697
BaseGDL* p1 = e->GetPar( 1);
1700
"Variable is undefined: "+e->GetParString(1));
1703
"Expression must be a "
1704
"scalar in this context: "+
1705
e->GetParString(1));
1706
DLongGDL* p1L = static_cast<DLongGDL*>
1707
(p1->Convert2(GDL_LONG,BaseGDL::COPY));
1713
if( mode < 0 || mode > 2)
1718
"Value of <"+ p1->TypeStr() +
1720
")> is out of allowed range.");
1724
SizeT nEl = p0S->N_Elements();
1726
if( mode == 2) // both
1728
TRACEOMP( __FILE__, __LINE__)
1729
#pragma omp parallel if ((nEl*10) >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= (nEl*10)))
1732
for( int i=0; i<nEl; ++i)
1734
unsigned long first= (*p0S)[ i].find_first_not_of(" \t");
1735
if( first == (*p0S)[ i].npos)
1741
unsigned long last = (*p0S)[ i].find_last_not_of(" \t");
1742
(*p0S)[ i] = (*p0S)[ i].substr(first,last-first+1);
1747
else if( mode == 1) // leading
1749
TRACEOMP( __FILE__, __LINE__)
1750
#pragma omp parallel if ((nEl*10) >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= (nEl*10)))
1753
for( int i=0; i<nEl; ++i)
1755
unsigned long first= (*p0S)[ i].find_first_not_of(" \t");
1756
if( first == (*p0S)[ i].npos)
1762
(*p0S)[ i] = (*p0S)[ i].substr(first);
1769
TRACEOMP( __FILE__, __LINE__)
1770
#pragma omp parallel if ((nEl*10) >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= (nEl*10)))
1773
for( int i=0; i<nEl; ++i)
1775
unsigned long last = (*p0S)[ i].find_last_not_of(" \t");
1776
if( last == (*p0S)[ i].npos)
1782
(*p0S)[ i] = (*p0S)[ i].substr(0,last+1);
1790
BaseGDL* strcompress( EnvT* e)
1794
DStringGDL* p0S = e->GetParAs<DStringGDL>( 0);
1796
bool removeAll = e->KeywordSet(0);
1798
DStringGDL* res = new DStringGDL( p0S->Dim(), BaseGDL::NOZERO);
1800
SizeT nEl = p0S->N_Elements();
1801
TRACEOMP( __FILE__, __LINE__)
1802
#pragma omp parallel if ((nEl*10) >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= (nEl*10)))
1805
for( int i=0; i<nEl; ++i)
1807
(*res)[ i] = StrCompress((*p0S)[ i], removeAll);
1813
BaseGDL* strpos( EnvT* e)
1815
SizeT nParam = e->NParam( 2);//, "STRPOS");
1817
bool reverseOffset = e->KeywordSet(0); // REVERSE_OFFSET
1818
bool reverseSearch = e->KeywordSet(1); // REVERSE_SEARCH
1820
DStringGDL* p0S = e->GetParAs<DStringGDL>( 0);
1822
DString searchString;
1823
// e->AssureScalarPar<DStringGDL>( 1, searchString);
1824
DStringGDL* sStr = e->GetParAs<DStringGDL>( 1);
1825
if( !sStr->Scalar( searchString))
1826
e->Throw( "Search string must be a scalar or one element array: "+
1827
e->GetParString( 1));
1829
unsigned long pos = string::npos;
1832
BaseGDL* p2 = e->GetParDefined(2);
1833
// if( p2 != NULL) //e->AssureLongScalarPar( 2,posDLong);
1835
const SizeT pIx = 2;
1836
BaseGDL* p = e->GetParDefined( pIx);
1837
DLongGDL* lp = static_cast<DLongGDL*>(p->Convert2( GDL_LONG, BaseGDL::COPY));
1838
auto_ptr<DLongGDL> guard_lp( lp);
1840
if( !lp->Scalar( scalar))
1841
throw GDLException("Parameter must be a scalar in this context: "+
1842
e->GetParString(pIx));
1846
DLongGDL* res = new DLongGDL( p0S->Dim(), BaseGDL::NOZERO);
1848
SizeT nSrcStr = p0S->N_Elements();
1849
TRACEOMP( __FILE__, __LINE__)
1850
#pragma omp parallel if ((nSrcStr*10) >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= (nSrcStr*10)))
1853
for( long i=0; i<nSrcStr; ++i)
1855
(*res)[ i] = StrPos((*p0S)[ i], searchString, pos,
1856
reverseOffset, reverseSearch);
1862
BaseGDL* strmid( EnvT* e)
1864
e->NParam( 2);//, "STRMID");
1866
bool reverse = e->KeywordSet(0);
1868
DStringGDL* p0S = e->GetParAs<DStringGDL>( 0);
1869
DLongGDL* p1L = e->GetParAs<DLongGDL>( 1);
1871
BaseGDL* p2 = e->GetPar( 2);
1872
DLongGDL* p2L = NULL;
1873
if( p2 != NULL) p2L = e->GetParAs<DLongGDL>( 2);
1876
bool sc1 = p1L->Scalar( scVal1);
1878
DLong scVal2 = numeric_limits<DLong>::max();
1883
sc2 = p2L->Scalar( scalar);
1890
stride = p1L->Dim( 0);
1891
if( stride != p2L->Dim( 0))
1893
"Starting offset and length arguments "
1894
"have incompatible first dimension.");
1898
// at least one scalar, p2L possibly NULL
1900
stride = p1L->Dim( 0);
1902
stride = max( p1L->Dim( 0), p2L->Dim( 0));
1904
stride = (stride > 0)? stride : 1;
1907
dimension resDim( p0S->Dim());
1911
DStringGDL* res = new DStringGDL( resDim, BaseGDL::NOZERO);
1913
SizeT nEl1 = p1L->N_Elements();
1914
SizeT nEl2 = (sc2)? 1 : p2L->N_Elements();
1916
SizeT nSrcStr = p0S->N_Elements();
1917
TRACEOMP( __FILE__, __LINE__)
1918
#pragma omp parallel if ((nSrcStr*10) >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= (nSrcStr*10))) default( shared)
1921
for( long i=0; i<nSrcStr; ++i)
1923
for( long ii=0; ii<stride; ++ii)
1925
SizeT destIx = i * stride + ii;
1926
DLong actFirst = (sc1)? scVal1 : (*p1L)[ destIx % nEl1];
1927
DLong actLen = (sc2)? scVal2 : (*p2L)[ destIx % nEl2];
1929
(*res)[ destIx] = "";//StrMid((*p0S)[ i], actFirst, actLen, reverse);
1931
(*res)[ destIx] = StrMid((*p0S)[ i], actFirst, actLen, reverse);
1938
BaseGDL* strlowcase( BaseGDL* p0, bool isReference)//( EnvT* e)
1940
assert( p0 != NULL);
1941
assert( p0->N_Elements() > 0);
1943
// e->NParam( 1);//, "STRLOWCASE");
1945
// DStringGDL* p0S = e->GetParAs<DStringGDL>( 0);
1948
// auto_ptr<DStringGDL> guard;
1950
if( p0->Type() == GDL_STRING)
1952
p0S = static_cast<DStringGDL*>( p0);
1956
res = new DStringGDL( p0S->Dim(), BaseGDL::NOZERO);
1960
p0S = static_cast<DStringGDL*>( p0->Convert2( GDL_STRING, BaseGDL::COPY));
1962
// guard.reset( p0S);
1965
// DStringGDL* res = new DStringGDL( p0S->Dim(), BaseGDL::NOZERO);
1967
SizeT nEl = p0S->N_Elements();
1971
TRACEOMP( __FILE__, __LINE__)
1972
#pragma omp parallel if ((nEl*10) >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= (nEl*10)))
1975
for( int i=0; i<nEl; ++i)
1977
StrLowCaseInplace((*p0S)[ i]);
1983
TRACEOMP( __FILE__, __LINE__)
1984
#pragma omp parallel if ((nEl*10) >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= (nEl*10)))
1987
for( int i=0; i<nEl; ++i)
1989
(*res)[ i] = StrLowCase((*p0S)[ i]);
1996
BaseGDL* strupcase( BaseGDL* p0, bool isReference)//( EnvT* e)
1998
assert( p0 != NULL);
1999
assert( p0->N_Elements() > 0);
2001
// e->NParam( 1);//, "STRLOWCASE");
2003
// DStringGDL* p0S = e->GetParAs<DStringGDL>( 0);
2006
// auto_ptr<DStringGDL> guard;
2008
if( p0->Type() == GDL_STRING)
2010
p0S = static_cast<DStringGDL*>( p0);
2014
res = new DStringGDL( p0S->Dim(), BaseGDL::NOZERO);
2018
p0S = static_cast<DStringGDL*>( p0->Convert2( GDL_STRING, BaseGDL::COPY));
2020
// guard.reset( p0S);
2023
// DStringGDL* res = new DStringGDL( p0S->Dim(), BaseGDL::NOZERO);
2025
SizeT nEl = p0S->N_Elements();
2029
TRACEOMP( __FILE__, __LINE__)
2030
#pragma omp parallel if ((nEl*10) >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= (nEl*10)))
2033
for( int i=0; i<nEl; ++i)
2035
StrUpCaseInplace((*p0S)[ i]);
2041
TRACEOMP( __FILE__, __LINE__)
2042
#pragma omp parallel if ((nEl*10) >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= (nEl*10)))
2045
for( int i=0; i<nEl; ++i)
2047
(*res)[ i] = StrUpCase((*p0S)[ i]);
2054
BaseGDL* strlen( BaseGDL* p0, bool isReference)//( EnvT* e)
2056
assert( p0 != NULL);
2057
assert( p0->N_Elements() > 0);
2059
// e->NParam( 1);//, "STRLEN");
2062
auto_ptr<DStringGDL> guard;
2064
if( p0->Type() == GDL_STRING)
2065
p0S = static_cast<DStringGDL*>( p0);
2068
p0S = static_cast<DStringGDL*>( p0->Convert2( GDL_STRING, BaseGDL::COPY));
2072
DLongGDL* res = new DLongGDL( p0S->Dim(), BaseGDL::NOZERO);
2074
SizeT nEl = p0S->N_Elements();
2075
// #pragma omp parallel if (nEl >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl))
2078
for( SizeT i=0; i<nEl; ++i)
2080
(*res)[ i] = (*p0S)[ i].length();
2086
BaseGDL* strjoin( EnvT* e)
2088
SizeT nParam = e->NParam( 1);
2090
DStringGDL* p0S = e->GetParAs<DStringGDL>( 0);
2091
SizeT nEl = p0S->N_Elements();
2095
e->AssureStringScalarPar( 1, delim);
2097
bool single = e->KeywordSet( 0); // SINGLE
2101
DStringGDL* res = new DStringGDL( (*p0S)[0]);
2102
DString& scl = (*res)[0];
2104
for( SizeT i=1; i<nEl; ++i)
2105
scl += delim + (*p0S)[i];
2110
dimension resDim( p0S->Dim());
2113
SizeT stride = resDim.Stride( 1);
2117
DStringGDL* res = new DStringGDL( resDim, BaseGDL::NOZERO);
2118
for( SizeT src=0, dst=0; src<nEl; ++dst)
2120
(*res)[ dst] = (*p0S)[ src++];
2121
for(SizeT l=1; l<stride; ++l)
2122
(*res)[ dst] += delim + (*p0S)[ src++];
2128
BaseGDL* where( EnvT* e)
2130
SizeT nParam = e->NParam( 1);//, "WHERE");
2132
BaseGDL* p0 = e->GetParDefined( 0);//, "WHERE");
2134
SizeT nEl = p0->N_Elements();
2138
static int nullIx = e->KeywordIx("NULL");
2139
bool nullKW = e->KeywordSet(nullIx);
2141
DLong* ixList = p0->Where( e->KeywordPresent( 0), count);
2142
ArrayGuard<DLong> guard( ixList);
2143
SizeT nCount = nEl - count;
2145
if( e->KeywordPresent( 0)) // COMPLEMENT
2150
e->SetKW( 0, NullGDL::GetSingleInstance());
2152
e->SetKW( 0, new DLongGDL( -1));
2156
DLongGDL* cIxList = new DLongGDL( dimension( &nCount, 1),
2159
SizeT cIx = nEl - 1;
2160
// #pragma omp parallel if (nCount >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nCount))
2163
for( SizeT i=0; i<nCount; ++i)
2164
(*cIxList)[ i] = ixList[ cIx - i];
2165
// (*cIxList)[ i] = ixList[ --cIx];
2167
e->SetKW( 0, cIxList);
2171
if( e->KeywordPresent( 1)) // NCOMPLEMENT
2173
e->SetKW( 1, new DLongGDL( nCount));
2178
e->SetPar( 1, new DLongGDL( count));
2184
return NullGDL::GetSingleInstance();
2185
return new DLongGDL( -1);
2188
return new DLongGDL( ixList, count);
2190
// DLongGDL* res = new DLongGDL( dimension( &count, 1),
2191
// BaseGDL::NOZERO);
2192
// for( SizeT i=0; i<count; ++i)
2193
// (*res)[ i] = ixList[ i];
2198
BaseGDL* n_params( EnvT* e)
2200
EnvUDT* caller = static_cast<EnvUDT*>(e->Caller());
2201
if( caller == NULL) return new DLongGDL( 0);
2202
DLong nP = caller->NParam();
2203
if( caller->IsObject())
2204
return new DLongGDL( nP-1); // "self" is not counted
2205
return new DLongGDL( nP);
2208
BaseGDL* keyword_set( EnvT* e)
2210
e->NParam( 1);//, "KEYWORD_SET");
2212
BaseGDL* p0 = e->GetPar( 0);
2213
if( p0 == NULL) return new DIntGDL( 0);
2214
if( !p0->Scalar()) return new DIntGDL( 1);
2215
if( p0->Type() == GDL_STRUCT) return new DIntGDL( 1);
2216
if( p0->LogTrue()) return new DIntGDL( 1);
2217
return new DIntGDL( 0);
2220
// passing 2nd argument by value is slightly better for float and double,
2221
// but incur some overhead for the complex class.
2222
template<class T> inline void AddOmitNaN(T& dest, T value)
2224
if (isfinite(value))
2226
// #pragma omp atomic
2230
template<class T> inline void AddOmitNaNCpx(T& dest, T value)
2232
// #pragma omp atomic
2233
dest += T(isfinite(value.real())? value.real() : 0,
2234
isfinite(value.imag())? value.imag() : 0);
2236
template<> inline void AddOmitNaN(DComplex& dest, DComplex value)
2237
{ AddOmitNaNCpx<DComplex>(dest, value); }
2238
template<> inline void AddOmitNaN(DComplexDbl& dest, DComplexDbl value)
2239
{ AddOmitNaNCpx<DComplexDbl>(dest, value); }
2241
template<class T> inline void NaN2Zero(T& value)
2242
{ if (!isfinite(value)) value = 0; }
2243
template<class T> inline void NaN2ZeroCpx(T& value)
2245
value = T(isfinite(value.real())? value.real() : 0,
2246
isfinite(value.imag())? value.imag() : 0);
2248
template<> inline void NaN2Zero(DComplex& value)
2249
{ NaN2ZeroCpx< DComplex>(value); }
2250
template<> inline void NaN2Zero(DComplexDbl& value)
2251
{ NaN2ZeroCpx< DComplexDbl>(value); }
2253
// total over all elements
2255
BaseGDL* total_template( T* src, bool omitNaN)
2257
if (!omitNaN) return new T(src->Sum());
2258
typename T::Ty sum = 0;
2259
SizeT nEl = src->N_Elements();
2260
TRACEOMP( __FILE__, __LINE__)
2261
#pragma omp parallel if (nEl >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl)) shared(sum)
2264
for ( int i=0; i<nEl; ++i)
2266
AddOmitNaN(sum, (*src)[ i]);
2272
// cumulative over all dims
2273
template<typename T>
2274
BaseGDL* total_cu_template( T* res, bool omitNaN)
2276
SizeT nEl = res->N_Elements();
2279
// #pragma omp parallel if (nEl >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl))
2282
for( SizeT i=0; i<nEl; ++i)
2283
NaN2Zero((*res)[i]);
2286
for( SizeT i=1,ii=0; i<nEl; ++i,++ii)
2287
(*res)[i] += (*res)[ii];
2291
// total over one dim
2292
template< typename T>
2293
BaseGDL* total_over_dim_template( T* src,
2294
const dimension& srcDim,
2298
SizeT nEl = src->N_Elements();
2300
// get dest dim and number of summations
2301
dimension destDim = srcDim;
2302
SizeT nSum = destDim.Remove( sumDimIx);
2304
T* res = new T( destDim); // zero fields
2306
// sumStride is also the number of linear src indexing
2307
SizeT sumStride = srcDim.Stride( sumDimIx);
2308
SizeT outerStride = srcDim.Stride( sumDimIx + 1);
2309
SizeT sumLimit = nSum * sumStride;
2311
for( SizeT o=0; o < nEl; o += outerStride)
2312
for( SizeT i=0; i < sumStride; ++i)
2315
SizeT oiLimit = sumLimit + oi;
2318
for( SizeT s=oi; s<oiLimit; s += sumStride)
2319
AddOmitNaN((*res)[ rIx], (*src)[ s]);
2323
for( SizeT s=oi; s<oiLimit; s += sumStride)
2324
(*res)[ rIx] += (*src)[ s];
2331
// cumulative over one dim
2332
template< typename T>
2333
BaseGDL* total_over_dim_cu_template( T* res,
2337
SizeT nEl = res->N_Elements();
2338
const dimension& resDim = res->Dim();
2341
for( SizeT i=0; i<nEl; ++i)
2342
NaN2Zero((*res)[i]);
2344
SizeT cumStride = resDim.Stride( sumDimIx);
2345
SizeT outerStride = resDim.Stride( sumDimIx + 1);
2346
for( SizeT o=0; o < nEl; o += outerStride)
2348
SizeT cumLimit = o+outerStride;
2349
for( SizeT i=o+cumStride, ii=o; i<cumLimit; ++i, ++ii)
2350
(*res)[ i] += (*res)[ ii];
2356
BaseGDL* total( EnvT* e)
2358
SizeT nParam = e->NParam( 1);//, "TOTAL");
2360
BaseGDL* p0 = e->GetParDefined( 0);//, "TOTAL");
2362
SizeT nEl = p0->N_Elements();
2364
e->Throw( "Variable is undefined: "+e->GetParString(0));
2366
if( p0->Type() == GDL_STRING)
2367
e->Throw( "String expression not allowed "
2368
"in this context: "+e->GetParString(0));
2370
static int cumIx = e->KeywordIx( "CUMULATIVE");
2371
static int intIx = e->KeywordIx("INTEGER");
2372
static int doubleIx = e->KeywordIx( "DOUBLE");
2373
static int nanIx = e->KeywordIx( "NAN");
2374
static int preserveIx = e->KeywordIx( "PRESERVE_TYPE");
2376
bool cumulative = e->KeywordSet( cumIx);
2377
bool intRes = e->KeywordSet( intIx);
2378
bool doubleRes = e->KeywordSet( doubleIx);
2379
bool nan = e->KeywordSet( nanIx);
2380
bool preserve = e->KeywordSet( preserveIx);
2384
e->AssureLongScalarPar( 1, sumDim);
2394
case GDL_BYTE: return total_template<DByteGDL>(static_cast<DByteGDL*>(p0), false);
2395
case GDL_INT: return total_template<DIntGDL>(static_cast<DIntGDL*>(p0), false);
2396
case GDL_UINT: return total_template<DUIntGDL>(static_cast<DUIntGDL*>(p0), false);
2397
case GDL_LONG: return total_template<DLongGDL>(static_cast<DLongGDL*>(p0), false);
2398
case GDL_ULONG: return total_template<DULongGDL>(static_cast<DULongGDL*>(p0), false);
2399
case GDL_LONG64: return total_template<DLong64GDL>(static_cast<DLong64GDL*>(p0), false);
2400
case GDL_ULONG64: return total_template<DULong64GDL>(static_cast<DULong64GDL*>(p0), false);
2401
case GDL_FLOAT: return total_template<DFloatGDL>(static_cast<DFloatGDL*>(p0), nan);
2402
case GDL_DOUBLE: return total_template<DDoubleGDL>(static_cast<DDoubleGDL*>(p0), nan);
2403
case GDL_COMPLEX: return total_template<DComplexGDL>(static_cast<DComplexGDL*>(p0), nan);
2404
case GDL_COMPLEXDBL: return total_template<DComplexDblGDL>(static_cast<DComplexDblGDL*>(p0), nan);
2405
default: assert(false);
2409
// Integer parts by Erin Sheldon
2410
// In IDL total(), the INTEGER keyword takes precedence
2413
// We use GDL_LONG64 unless the input is GDL_ULONG64
2414
if ( p0->Type() == GDL_LONG64 )
2416
return total_template<DLong64GDL>
2417
( static_cast<DLong64GDL*>(p0), nan );
2419
if ( p0->Type() == GDL_ULONG64 )
2421
return total_template<DULong64GDL>
2422
( static_cast<DULong64GDL*>(p0), nan );
2426
DLong64GDL* p0L64 = static_cast<DLong64GDL*>
2427
(p0->Convert2( GDL_LONG64, BaseGDL::COPY));
2428
auto_ptr<DLong64GDL> guard( p0L64);
2429
return total_template<DLong64GDL>( p0L64, nan);
2431
} // integer results
2434
if( p0->Type() == GDL_DOUBLE)
2436
return total_template<DDoubleGDL>
2437
( static_cast<DDoubleGDL*>(p0), nan);
2439
if( p0->Type() == GDL_COMPLEXDBL)
2441
return total_template<DComplexDblGDL>
2442
( static_cast<DComplexDblGDL*>(p0), nan);
2447
if( p0->Type() == GDL_FLOAT)
2449
return total_template<DFloatGDL>
2450
( static_cast<DFloatGDL*>(p0), nan);
2452
if( p0->Type() == GDL_COMPLEX)
2454
return total_template<DComplexGDL>
2455
( static_cast<DComplexGDL*>(p0), nan);
2457
DFloatGDL* p0F = static_cast<DFloatGDL*>
2458
(p0->Convert2( GDL_FLOAT,BaseGDL::COPY));
2459
auto_ptr<DFloatGDL> guard( p0F);
2460
return total_template<DFloatGDL>( p0F, false);
2462
if( p0->Type() == GDL_COMPLEX)
2464
DComplexDblGDL* p0D = static_cast<DComplexDblGDL*>
2465
(p0->Convert2( GDL_COMPLEXDBL,BaseGDL::COPY));
2466
auto_ptr<DComplexDblGDL> p0D_guard( p0D);
2467
return total_template<DComplexDblGDL>( p0D, nan);
2470
DDoubleGDL* p0D = static_cast<DDoubleGDL*>
2471
(p0->Convert2( GDL_DOUBLE, BaseGDL::COPY));
2472
auto_ptr<DDoubleGDL> p0D_guard( p0D);
2473
return total_template<DDoubleGDL>( p0D, nan);
2481
case GDL_BYTE: return total_cu_template<DByteGDL>(static_cast<DByteGDL*>(p0)->Dup(), false);
2482
case GDL_INT: return total_cu_template<DIntGDL>(static_cast<DIntGDL*>(p0)->Dup(), false);
2483
case GDL_UINT: return total_cu_template<DUIntGDL>(static_cast<DUIntGDL*>(p0)->Dup(), false);
2484
case GDL_LONG: return total_cu_template<DLongGDL>(static_cast<DLongGDL*>(p0)->Dup(), false);
2485
case GDL_ULONG: return total_cu_template<DULongGDL>(static_cast<DULongGDL*>(p0)->Dup(), false);
2486
case GDL_LONG64: return total_cu_template<DLong64GDL>(static_cast<DLong64GDL*>(p0)->Dup(), false);
2487
case GDL_ULONG64: return total_cu_template<DULong64GDL>(static_cast<DULong64GDL*>(p0)->Dup(), false);
2488
case GDL_FLOAT: return total_cu_template<DFloatGDL>(static_cast<DFloatGDL*>(p0)->Dup(), nan);
2489
case GDL_DOUBLE: return total_cu_template<DDoubleGDL>(static_cast<DDoubleGDL*>(p0)->Dup(), nan);
2490
case GDL_COMPLEX: return total_cu_template<DComplexGDL>(static_cast<DComplexGDL*>(p0)->Dup(), nan);
2491
case GDL_COMPLEXDBL: return total_cu_template<DComplexDblGDL>(static_cast<DComplexDblGDL*>(p0)->Dup(), nan);
2492
default: assert(false);
2496
// INTEGER keyword takes precedence
2499
// We use GDL_LONG64 unless the input is GDL_ULONG64
2500
if ( p0->Type() == GDL_LONG64 )
2502
return total_cu_template<DLong64GDL>
2503
( static_cast<DLong64GDL*>(p0)->Dup(), nan );
2505
if ( p0->Type() == GDL_ULONG64 )
2507
return total_cu_template<DULong64GDL>
2508
( static_cast<DULong64GDL*>(p0)->Dup(), nan );
2511
// Convert to Long64
2512
return total_cu_template<DLong64GDL>
2513
( static_cast<DLong64GDL*>
2514
(p0->Convert2( GDL_LONG64, BaseGDL::COPY)), nan);
2516
} // integer results
2519
// special case as GDL_DOUBLE type overrides /GDL_DOUBLE
2520
if( p0->Type() == GDL_DOUBLE)
2522
return total_cu_template< DDoubleGDL>
2523
( static_cast<DDoubleGDL*>(p0)->Dup(), nan);
2525
if( p0->Type() == GDL_COMPLEXDBL)
2527
return total_cu_template< DComplexDblGDL>
2528
( static_cast<DComplexDblGDL*>(p0)->Dup(), nan);
2535
// special case for GDL_FLOAT has no advantage here
2536
if( p0->Type() == GDL_COMPLEX)
2538
return total_cu_template< DComplexGDL>
2539
( static_cast<DComplexGDL*>(p0)->Dup(), nan);
2541
return total_cu_template< DFloatGDL>
2542
( static_cast<DFloatGDL*>( p0->Convert2(GDL_FLOAT,
2543
BaseGDL::COPY)), nan);
2545
if( p0->Type() == GDL_COMPLEX)
2547
return total_cu_template< DComplexDblGDL>
2548
( static_cast<DComplexDblGDL*>(p0->Convert2( GDL_COMPLEXDBL,
2549
BaseGDL::COPY)), nan);
2551
return total_cu_template< DDoubleGDL>
2552
( static_cast<DDoubleGDL*>(p0->Convert2( GDL_DOUBLE,
2553
BaseGDL::COPY)), nan);
2557
// total over sumDim
2558
dimension srcDim = p0->Dim();
2559
SizeT srcRank = srcDim.Rank();
2561
if( sumDim < 1 || sumDim > srcRank)
2563
"Array must have "+i2s(sumDim)+
2564
" dimensions: "+e->GetParString(0));
2572
case GDL_BYTE: return total_over_dim_template<DByteGDL>(static_cast<DByteGDL*>(p0), srcDim, sumDim-1, false);
2573
case GDL_INT: return total_over_dim_template<DIntGDL>(static_cast<DIntGDL*>(p0), srcDim, sumDim-1, false);
2574
case GDL_UINT: return total_over_dim_template<DUIntGDL>(static_cast<DUIntGDL*>(p0), srcDim, sumDim-1, false);
2575
case GDL_LONG: return total_over_dim_template<DLongGDL>(static_cast<DLongGDL*>(p0), srcDim, sumDim-1, false);
2576
case GDL_ULONG: return total_over_dim_template<DULongGDL>(static_cast<DULongGDL*>(p0), srcDim, sumDim-1, false);
2577
case GDL_LONG64: return total_over_dim_template<DLong64GDL>(static_cast<DLong64GDL*>(p0), srcDim, sumDim-1, false);
2578
case GDL_ULONG64: return total_over_dim_template<DULong64GDL>(static_cast<DULong64GDL*>(p0), srcDim, sumDim-1, false);
2579
case GDL_FLOAT: return total_over_dim_template<DFloatGDL>(static_cast<DFloatGDL*>(p0), srcDim, sumDim-1, nan);
2580
case GDL_DOUBLE: return total_over_dim_template<DDoubleGDL>(static_cast<DDoubleGDL*>(p0), srcDim, sumDim-1, nan);
2581
case GDL_COMPLEX: return total_over_dim_template<DComplexGDL>(static_cast<DComplexGDL*>(p0), srcDim, sumDim-1, nan);
2582
case GDL_COMPLEXDBL: return total_over_dim_template<DComplexDblGDL>(static_cast<DComplexDblGDL*>(p0), srcDim, sumDim-1, nan);
2583
default: assert(false);
2587
// INTEGER keyword takes precedence
2590
// We use GDL_LONG64 unless the input is GDL_ULONG64
2591
if ( p0->Type() == GDL_LONG64 )
2593
return total_over_dim_template<DLong64GDL>
2594
( static_cast<DLong64GDL*>(p0), srcDim, sumDim-1, nan );
2596
if ( p0->Type() == GDL_ULONG64 )
2598
return total_over_dim_template<DULong64GDL>
2599
( static_cast<DULong64GDL*>(p0), srcDim, sumDim-1, nan );
2603
DLong64GDL* p0L64 = static_cast<DLong64GDL*>
2604
(p0->Convert2( GDL_LONG64, BaseGDL::COPY));
2606
auto_ptr<DLong64GDL> p0L64_guard( p0L64);
2607
return total_over_dim_template<DLong64GDL>
2608
( p0L64, srcDim, sumDim-1, nan);
2610
} // integer results
2613
if( p0->Type() == GDL_DOUBLE)
2615
return total_over_dim_template< DDoubleGDL>
2616
( static_cast<DDoubleGDL*>(p0), srcDim, sumDim-1, nan);
2618
if( p0->Type() == GDL_COMPLEXDBL)
2620
return total_over_dim_template< DComplexDblGDL>
2621
( static_cast<DComplexDblGDL*>(p0), srcDim, sumDim-1, nan);
2625
if( p0->Type() == GDL_FLOAT)
2627
return total_over_dim_template< DFloatGDL>
2628
( static_cast<DFloatGDL*>(p0), srcDim, sumDim-1, nan);
2630
if( p0->Type() == GDL_COMPLEX)
2632
return total_over_dim_template< DComplexGDL>
2633
( static_cast<DComplexGDL*>(p0), srcDim, sumDim-1, nan);
2635
// default for NOT /GDL_DOUBLE
2636
DFloatGDL* p0F = static_cast<DFloatGDL*>
2637
(p0->Convert2( GDL_FLOAT,BaseGDL::COPY));
2638
auto_ptr<DFloatGDL> p0F_guard( p0F);
2639
// p0F_guard.reset( p0F);
2640
return total_over_dim_template< DFloatGDL>
2641
( p0F, srcDim, sumDim-1, false);
2643
if( p0->Type() == GDL_COMPLEX)
2645
DComplexDblGDL* p0D = static_cast<DComplexDblGDL*>
2646
(p0->Convert2( GDL_COMPLEXDBL,BaseGDL::COPY));
2647
auto_ptr<DComplexDblGDL> p0D_guard( p0D);
2648
// p0D_guard.reset( p0D);
2649
return total_over_dim_template< DComplexDblGDL>
2650
( p0D, srcDim, sumDim-1, nan);
2652
// default for /GDL_DOUBLE
2653
DDoubleGDL* p0D = static_cast<DDoubleGDL*>
2654
(p0->Convert2( GDL_DOUBLE,BaseGDL::COPY));
2655
auto_ptr<DDoubleGDL> p0D_guard( p0D);
2656
//p0D_guard.reset( p0D);
2657
return total_over_dim_template< DDoubleGDL>( p0D, srcDim, sumDim-1,nan);
2665
case GDL_BYTE: return total_over_dim_cu_template<DByteGDL>(static_cast<DByteGDL*>(p0)->Dup(), sumDim-1, false);
2666
case GDL_INT: return total_over_dim_cu_template<DIntGDL>(static_cast<DIntGDL*>(p0)->Dup(), sumDim-1, false);
2667
case GDL_UINT: return total_over_dim_cu_template<DUIntGDL>(static_cast<DUIntGDL*>(p0)->Dup(), sumDim-1, false);
2668
case GDL_LONG: return total_over_dim_cu_template<DLongGDL>(static_cast<DLongGDL*>(p0)->Dup(), sumDim-1, false);
2669
case GDL_ULONG: return total_over_dim_cu_template<DULongGDL>(static_cast<DULongGDL*>(p0)->Dup(), sumDim-1, false);
2670
case GDL_LONG64: return total_over_dim_cu_template<DLong64GDL>(static_cast<DLong64GDL*>(p0)->Dup(), sumDim-1, false);
2671
case GDL_ULONG64: return total_over_dim_cu_template<DULong64GDL>(static_cast<DULong64GDL*>(p0)->Dup(), sumDim-1, false);
2672
case GDL_FLOAT: return total_over_dim_cu_template<DFloatGDL>(static_cast<DFloatGDL*>(p0)->Dup(), sumDim-1, nan);
2673
case GDL_DOUBLE: return total_over_dim_cu_template<DDoubleGDL>(static_cast<DDoubleGDL*>(p0)->Dup(), sumDim-1, nan);
2674
case GDL_COMPLEX: return total_over_dim_cu_template<DComplexGDL>(static_cast<DComplexGDL*>(p0)->Dup(), sumDim-1, nan);
2675
case GDL_COMPLEXDBL: return total_over_dim_cu_template<DComplexDblGDL>(static_cast<DComplexDblGDL*>(p0)->Dup(), sumDim-1, nan);
2676
default: assert(false);
2680
// INTEGER keyword takes precedence
2683
// We use GDL_LONG64 unless the input is GDL_ULONG64
2684
if ( p0->Type() == GDL_LONG64 )
2686
return total_over_dim_cu_template<DLong64GDL>
2687
( static_cast<DLong64GDL*>(p0)->Dup(), sumDim-1, nan );
2689
if ( p0->Type() == GDL_ULONG64 )
2691
return total_over_dim_cu_template<DULong64GDL>
2692
( static_cast<DULong64GDL*>(p0)->Dup(), sumDim-1, nan );
2695
// Convert to Long64
2696
return total_over_dim_cu_template<DLong64GDL>
2697
( static_cast<DLong64GDL*>
2698
(p0->Convert2( GDL_LONG64, BaseGDL::COPY)), sumDim-1, nan);
2700
} // integer results
2703
if( p0->Type() == GDL_DOUBLE)
2705
return total_over_dim_cu_template< DDoubleGDL>
2706
( static_cast<DDoubleGDL*>(p0)->Dup(), sumDim-1, nan);
2708
if( p0->Type() == GDL_COMPLEXDBL)
2710
return total_over_dim_cu_template< DComplexDblGDL>
2711
( static_cast<DComplexDblGDL*>(p0)->Dup(), sumDim-1, nan);
2715
// special case for GDL_FLOAT has no advantage here
2716
if( p0->Type() == GDL_COMPLEX)
2718
return total_over_dim_cu_template< DComplexGDL>
2719
( static_cast<DComplexGDL*>(p0)->Dup(), sumDim-1, nan);
2721
// default for NOT /GDL_DOUBLE
2722
return total_over_dim_cu_template< DFloatGDL>
2723
( static_cast<DFloatGDL*>( p0->Convert2( GDL_FLOAT,
2724
BaseGDL::COPY)), sumDim-1, nan);
2726
if( p0->Type() == GDL_COMPLEX)
2728
return total_over_dim_cu_template< DComplexDblGDL>
2729
( static_cast<DComplexDblGDL*>(p0->Convert2( GDL_COMPLEXDBL,
2730
BaseGDL::COPY)), sumDim-1, nan);
2732
// default for /GDL_DOUBLE
2733
return total_over_dim_cu_template< DDoubleGDL>
2734
( static_cast<DDoubleGDL*>(p0->Convert2( GDL_DOUBLE,
2735
BaseGDL::COPY)), sumDim-1, nan);
2740
// passing 2nd argument by value is slightly better for float and double,
2741
// but incur some overhead for the complex class.
2742
template<class T> inline void MultOmitNaN(T& dest, T value)
2744
if (isfinite(value))
2746
// #pragma omp atomic
2750
template<class T> inline void MultOmitNaNCpx(T& dest, T value)
2752
dest *= T(isfinite(value.real())? value.real() : 1,
2753
isfinite(value.imag())? value.imag() : 1);
2755
template<> inline void MultOmitNaN(DComplex& dest, DComplex value)
2756
{ MultOmitNaNCpx<DComplex>(dest, value); }
2757
template<> inline void MultOmitNaN(DComplexDbl& dest, DComplexDbl value)
2758
{ MultOmitNaNCpx<DComplexDbl>(dest, value); }
2760
template<class T> inline void Nan2One(T& value)
2761
{ if (!isfinite(value)) value = 1; }
2762
template<class T> inline void Nan2OneCpx(T& value)
2764
value = T(isfinite(value.real())? value.real() : 1,
2765
isfinite(value.imag())? value.imag() : 1);
2767
template<> inline void Nan2One(DComplex& value)
2768
{ Nan2OneCpx< DComplex>(value); }
2769
template<> inline void Nan2One(DComplexDbl& value)
2770
{ Nan2OneCpx< DComplexDbl>(value); }
2772
// product over all elements
2774
BaseGDL* product_template( T* src, bool omitNaN)
2776
typename T::Ty sum = 1;
2777
SizeT nEl = src->N_Elements();
2780
TRACEOMP( __FILE__, __LINE__)
2781
#pragma omp parallel if (nEl >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl)) shared(sum)
2783
#pragma omp for reduction(*:sum)
2784
for ( int i=0; i<nEl; ++i)
2792
TRACEOMP( __FILE__, __LINE__)
2793
#pragma omp parallel if (nEl >= CpuTPOOL_MIN_ELTS && (CpuTPOOL_MAX_ELTS == 0 || CpuTPOOL_MAX_ELTS <= nEl)) shared(sum)
2795
#pragma omp for reduction(*:sum)
2796
for ( int i=0; i<nEl; ++i)
2798
MultOmitNaN( sum, (*src)[ i]);
2806
BaseGDL* product_template( DComplexGDL* src, bool omitNaN)
2808
DComplexGDL::Ty sum = 1;
2809
SizeT nEl = src->N_Elements();
2812
for ( SizeT i=0; i<nEl; ++i)
2819
for ( SizeT i=0; i<nEl; ++i)
2821
MultOmitNaN( sum, (*src)[ i]);
2824
return new DComplexGDL( sum);
2828
BaseGDL* product_template( DComplexDblGDL* src, bool omitNaN)
2830
DComplexDblGDL::Ty sum = 1;
2831
SizeT nEl = src->N_Elements();
2834
for ( SizeT i=0; i<nEl; ++i)
2841
for ( SizeT i=0; i<nEl; ++i)
2843
MultOmitNaN( sum, (*src)[ i]);
2846
return new DComplexDblGDL( sum);
2849
// cumulative over all dims
2850
template<typename T>
2851
BaseGDL* product_cu_template( T* res, bool omitNaN)
2853
SizeT nEl = res->N_Elements();
2856
for( SizeT i=0; i<nEl; ++i)
2857
Nan2One( (*res)[i]);
2859
for( SizeT i=1,ii=0; i<nEl; ++i,++ii)
2860
(*res)[i] *= (*res)[ii];
2864
// product over one dim
2865
template< typename T>
2866
BaseGDL* product_over_dim_template( T* src,
2867
const dimension& srcDim,
2871
SizeT nEl = src->N_Elements();
2873
// get dest dim and number of summations
2874
dimension destDim = srcDim;
2875
SizeT nSum = destDim.Remove( sumDimIx);
2877
T* res = new T( destDim, BaseGDL::NOZERO);
2879
// sumStride is also the number of linear src indexing
2880
SizeT sumStride = srcDim.Stride( sumDimIx);
2881
SizeT outerStride = srcDim.Stride( sumDimIx + 1);
2882
SizeT sumLimit = nSum * sumStride;
2884
for( SizeT o=0; o < nEl; o += outerStride)
2885
for( SizeT i=0; i < sumStride; ++i)
2889
SizeT oiLimit = sumLimit + oi;
2892
for( SizeT s=oi; s<oiLimit; s += sumStride)
2893
MultOmitNaN((*res)[ rIx], (*src)[ s]);
2897
for( SizeT s=oi; s<oiLimit; s += sumStride)
2898
(*res)[ rIx] *= (*src)[ s];
2905
// cumulative over one dim
2906
template< typename T>
2907
BaseGDL* product_over_dim_cu_template( T* res,
2911
SizeT nEl = res->N_Elements();
2912
const dimension& resDim = res->Dim();
2915
for( SizeT i=0; i<nEl; ++i)
2918
SizeT cumStride = resDim.Stride( sumDimIx);
2919
SizeT outerStride = resDim.Stride( sumDimIx + 1);
2920
for( SizeT o=0; o < nEl; o += outerStride)
2922
SizeT cumLimit = o+outerStride;
2923
for( SizeT i=o+cumStride, ii=o; i<cumLimit; ++i, ++ii)
2924
(*res)[ i] *= (*res)[ ii];
2929
BaseGDL* product( EnvT* e)
2931
SizeT nParam = e->NParam( 1);
2933
BaseGDL* p0 = e->GetParDefined( 0);
2935
SizeT nEl = p0->N_Elements();
2937
e->Throw( "Variable is undefined: "+e->GetParString(0));
2939
if( p0->Type() == GDL_STRING)
2940
e->Throw( "String expression not allowed "
2941
"in this context: "+e->GetParString(0));
2943
static int cumIx = e->KeywordIx( "CUMULATIVE");
2944
static int nanIx = e->KeywordIx( "NAN");
2945
static int intIx = e->KeywordIx("INTEGER");
2946
static int preIx = e->KeywordIx("PRESERVE_TYPE");
2947
bool KwCumul = e->KeywordSet( cumIx);
2948
bool KwNaN = e->KeywordSet( nanIx);
2949
bool KwInt = e->KeywordSet( intIx);
2950
bool KwPre = e->KeywordSet( preIx);
2955
e->AssureLongScalarPar( 1, sumDim);
2963
case GDL_BYTE: return product_template<DByteGDL>(static_cast<DByteGDL*>(p0), nanInt);
2964
case GDL_INT: return product_template<DIntGDL>(static_cast<DIntGDL*>(p0), nanInt);
2965
case GDL_UINT: return product_template<DUIntGDL>(static_cast<DUIntGDL*>(p0), nanInt);
2966
case GDL_LONG: return product_template<DLongGDL>(static_cast<DLongGDL*>(p0), nanInt);
2967
case GDL_ULONG: return product_template<DULongGDL>(static_cast<DULongGDL*>(p0), nanInt);
2968
case GDL_LONG64: return product_template<DLong64GDL>(static_cast<DLong64GDL*>(p0), nanInt);
2969
case GDL_ULONG64: return product_template<DULong64GDL>(static_cast<DULong64GDL*>(p0), nanInt);
2970
case GDL_FLOAT: return product_template<DFloatGDL>(static_cast<DFloatGDL*>(p0), KwNaN);
2971
case GDL_DOUBLE: return product_template<DDoubleGDL>(static_cast<DDoubleGDL*>(p0), KwNaN);
2972
case GDL_COMPLEX: return product_template<DComplexGDL>(static_cast<DComplexGDL*>(p0), KwNaN);
2973
case GDL_COMPLEXDBL: return product_template<DComplexDblGDL>(static_cast<DComplexDblGDL*>(p0), KwNaN);
2974
default: assert(false);
2978
// Integer parts derivated from Total code by Erin Sheldon
2979
// In IDL PRODUCT(), the INTEGER keyword takes precedence
2981
// We use GDL_LONG64 unless the input is GDL_ULONG64
2982
if ((p0->Type() == GDL_LONG64) && (!KwNaN)) {
2983
return product_template<DLong64GDL>
2984
( static_cast<DLong64GDL*>(p0), nanInt );
2986
if ((p0->Type() == GDL_ULONG64) && (!KwNaN)) {
2987
return product_template<DULong64GDL>
2988
(static_cast<DULong64GDL*>(p0), nanInt );
2991
// Convert to Long64
2992
DLong64GDL* p0L64 = static_cast<DLong64GDL*>
2993
(p0->Convert2( GDL_LONG64, BaseGDL::COPY));
2994
auto_ptr<DLong64GDL> guard( p0L64);
2996
DFloatGDL* p0f = static_cast<DFloatGDL*>
2997
(p0->Convert2( GDL_FLOAT, BaseGDL::COPY));
2998
auto_ptr<DFloatGDL> guard( p0f);
2999
for( SizeT i=0; i<nEl; ++i) {
3000
if (!isfinite((*p0f)[i])) (*p0L64)[i]=1;
3003
return product_template<DLong64GDL>( p0L64, nanInt);
3004
} // integer results
3006
if( p0->Type() == GDL_DOUBLE) {
3007
return product_template<DDoubleGDL>
3008
( static_cast<DDoubleGDL*>(p0), KwNaN);
3010
if( p0->Type() == GDL_COMPLEXDBL) {
3011
return product_template<DComplexDblGDL>
3012
( static_cast<DComplexDblGDL*>(p0), KwNaN);
3014
if( p0->Type() == GDL_COMPLEX) {
3015
DComplexDblGDL* p0D = static_cast<DComplexDblGDL*>
3016
(p0->Convert2( GDL_COMPLEXDBL,BaseGDL::COPY));
3017
auto_ptr<DComplexDblGDL> p0D_guard( p0D);
3018
//p0D_guard.reset( p0D);
3019
return product_template<DComplexDblGDL>( p0D, KwNaN);
3022
DDoubleGDL* p0D = static_cast<DDoubleGDL*>
3023
(p0->Convert2( GDL_DOUBLE, BaseGDL::COPY));
3024
auto_ptr<DDoubleGDL> p0D_guard( p0D);
3025
// p0D_guard.reset( p0D);
3026
return product_template<DDoubleGDL>( p0D, KwNaN);
3035
case GDL_BYTE: return product_cu_template<DByteGDL>(static_cast<DByteGDL*>(p0)->Dup(), nanInt);
3036
case GDL_INT: return product_cu_template<DIntGDL>(static_cast<DIntGDL*>(p0)->Dup(), nanInt);
3037
case GDL_UINT: return product_cu_template<DUIntGDL>(static_cast<DUIntGDL*>(p0)->Dup(), nanInt);
3038
case GDL_LONG: return product_cu_template<DLongGDL>(static_cast<DLongGDL*>(p0)->Dup(), nanInt);
3039
case GDL_ULONG: return product_cu_template<DULongGDL>(static_cast<DULongGDL*>(p0)->Dup(), nanInt);
3040
case GDL_LONG64: return product_cu_template<DLong64GDL>(static_cast<DLong64GDL*>(p0)->Dup(), nanInt);
3041
case GDL_ULONG64: return product_cu_template<DULong64GDL>(static_cast<DULong64GDL*>(p0)->Dup(), nanInt);
3042
case GDL_FLOAT: return product_cu_template<DFloatGDL>(static_cast<DFloatGDL*>(p0)->Dup(), KwNaN);
3043
case GDL_DOUBLE: return product_cu_template<DDoubleGDL>(static_cast<DDoubleGDL*>(p0)->Dup(), KwNaN);
3044
case GDL_COMPLEX: return product_cu_template<DComplexGDL>(static_cast<DComplexGDL*>(p0)->Dup(), KwNaN);
3045
case GDL_COMPLEXDBL: return product_cu_template<DComplexDblGDL>(static_cast<DComplexDblGDL*>(p0)->Dup(), KwNaN);
3046
default: assert(false);
3050
// Integer parts derivated from Total code by Erin Sheldon
3051
// In IDL PRODUCT(), the INTEGER keyword takes precedence
3053
// We use GDL_LONG64 unless the input is GDL_ULONG64
3054
if ((p0->Type() == GDL_LONG64) && (!KwNaN)) {
3055
return product_cu_template<DLong64GDL>
3056
( static_cast<DLong64GDL*>(p0)->Dup(), nanInt);
3058
if ((p0->Type() == GDL_ULONG64) && (!KwNaN)) {
3059
return product_cu_template<DULong64GDL>
3060
( static_cast<DULong64GDL*>(p0)->Dup(), nanInt);
3062
// Convert to Long64
3063
DLong64GDL* p0L64 = static_cast<DLong64GDL*>
3064
(p0->Convert2( GDL_LONG64, BaseGDL::COPY));
3065
auto_ptr<DLong64GDL> guard( p0L64);
3067
DFloatGDL* p0f = static_cast<DFloatGDL*>
3068
(p0->Convert2( GDL_FLOAT, BaseGDL::COPY));
3069
auto_ptr<DFloatGDL> guard( p0f);
3070
for( SizeT i=0; i<nEl; ++i) {
3071
if (!isfinite((*p0f)[i])) (*p0L64)[i]=1;
3074
return product_cu_template<DLong64GDL>
3075
((p0L64)->Dup(), nanInt);
3076
} // integer results
3078
// special case as GDL_DOUBLE type overrides /GDL_DOUBLE
3079
if (p0->Type() == GDL_DOUBLE) {
3080
return product_cu_template< DDoubleGDL>
3081
( static_cast<DDoubleGDL*>(p0)->Dup(), KwNaN);
3083
if (p0->Type() == GDL_COMPLEXDBL) {
3084
return product_cu_template< DComplexDblGDL>
3085
( static_cast<DComplexDblGDL*>(p0)->Dup(), KwNaN);
3087
if (p0->Type() == GDL_COMPLEX) {
3088
return product_cu_template< DComplexDblGDL>
3089
( static_cast<DComplexDblGDL*>
3090
(p0->Convert2( GDL_COMPLEXDBL, BaseGDL::COPY)), KwNaN);
3092
return product_cu_template< DDoubleGDL>
3093
( static_cast<DDoubleGDL*>
3094
(p0->Convert2( GDL_DOUBLE, BaseGDL::COPY)), KwNaN);
3098
// product over sumDim
3099
dimension srcDim = p0->Dim();
3100
SizeT srcRank = srcDim.Rank();
3102
if( sumDim < 1 || sumDim > srcRank)
3103
e->Throw( "Array must have "+i2s(sumDim)+
3104
" dimensions: "+e->GetParString(0));
3112
case GDL_BYTE: return product_over_dim_template<DByteGDL>(static_cast<DByteGDL*>(p0), srcDim, sumDim-1, nanInt);
3113
case GDL_INT: return product_over_dim_template<DIntGDL>(static_cast<DIntGDL*>(p0), srcDim, sumDim-1, nanInt);
3114
case GDL_UINT: return product_over_dim_template<DUIntGDL>(static_cast<DUIntGDL*>(p0), srcDim, sumDim-1, nanInt);
3115
case GDL_LONG: return product_over_dim_template<DLongGDL>(static_cast<DLongGDL*>(p0), srcDim, sumDim-1, nanInt);
3116
case GDL_ULONG: return product_over_dim_template<DULongGDL>(static_cast<DULongGDL*>(p0), srcDim, sumDim-1, nanInt);
3117
case GDL_LONG64: return product_over_dim_template<DLong64GDL>(static_cast<DLong64GDL*>(p0), srcDim, sumDim-1, nanInt);
3118
case GDL_ULONG64: return product_over_dim_template<DULong64GDL>(static_cast<DULong64GDL*>(p0), srcDim, sumDim-1, nanInt);
3119
case GDL_FLOAT: return product_over_dim_template<DFloatGDL>(static_cast<DFloatGDL*>(p0), srcDim, sumDim-1, KwNaN);
3120
case GDL_DOUBLE: return product_over_dim_template<DDoubleGDL>(static_cast<DDoubleGDL*>(p0), srcDim, sumDim-1, KwNaN);
3121
case GDL_COMPLEX: return product_over_dim_template<DComplexGDL>(static_cast<DComplexGDL*>(p0), srcDim, sumDim-1, KwNaN);
3122
case GDL_COMPLEXDBL: return product_over_dim_template<DComplexDblGDL>(static_cast<DComplexDblGDL*>(p0), srcDim, sumDim-1, KwNaN);
3123
default: assert(false);
3127
// Integer parts derivated from Total code by Erin Sheldon
3128
// In IDL PRODUCT(), the INTEGER keyword takes precedence
3130
// We use GDL_LONG64 unless the input is GDL_ULONG64
3131
if ((p0->Type() == GDL_LONG64 ) && (!KwNaN)) {
3132
return product_over_dim_template<DLong64GDL>
3133
( static_cast<DLong64GDL*>(p0), srcDim, sumDim-1, nanInt);
3135
if ((p0->Type() == GDL_ULONG64) && (!KwNaN)) {
3136
return product_over_dim_template<DULong64GDL>
3137
( static_cast<DULong64GDL*>(p0), srcDim, sumDim-1, nanInt);
3141
DLong64GDL* p0L64 = static_cast<DLong64GDL*>
3142
(p0->Convert2( GDL_LONG64, BaseGDL::COPY));
3143
auto_ptr<DLong64GDL> guard( p0L64);
3145
DFloatGDL* p0f = static_cast<DFloatGDL*>
3146
(p0->Convert2( GDL_FLOAT, BaseGDL::COPY));
3147
auto_ptr<DFloatGDL> guard( p0f);
3148
for( SizeT i=0; i<nEl; ++i) {
3149
if (!isfinite((*p0f)[i])) (*p0L64)[i]=1;
3152
return product_over_dim_template<DLong64GDL>
3153
( p0L64, srcDim, sumDim-1, nanInt);
3154
} // integer results
3156
if( p0->Type() == GDL_DOUBLE) {
3157
return product_over_dim_template< DDoubleGDL>
3158
( static_cast<DDoubleGDL*>(p0), srcDim, sumDim-1, KwNaN);
3160
if( p0->Type() == GDL_COMPLEXDBL) {
3161
return product_over_dim_template< DComplexDblGDL>
3162
( static_cast<DComplexDblGDL*>(p0), srcDim, sumDim-1, KwNaN);
3164
if( p0->Type() == GDL_COMPLEX) {
3165
DComplexDblGDL* p0D = static_cast<DComplexDblGDL*>
3166
(p0->Convert2( GDL_COMPLEXDBL,BaseGDL::COPY));
3167
auto_ptr<DComplexDblGDL> p0D_guard( p0D);
3168
// p0D_guard.reset( p0D);
3169
return product_over_dim_template< DComplexDblGDL>
3170
( p0D, srcDim, sumDim-1, KwNaN);
3173
DDoubleGDL* p0D = static_cast<DDoubleGDL*>
3174
(p0->Convert2( GDL_DOUBLE,BaseGDL::COPY));
3175
auto_ptr<DDoubleGDL> p0D_guard( p0D);
3176
//p0D_guard.reset( p0D);
3177
return product_over_dim_template< DDoubleGDL>
3178
( p0D, srcDim, sumDim-1,KwNaN);
3187
case GDL_BYTE: return product_over_dim_cu_template<DByteGDL>(static_cast<DByteGDL*>(p0)->Dup(), sumDim-1, nanInt);
3188
case GDL_INT: return product_over_dim_cu_template<DIntGDL>(static_cast<DIntGDL*>(p0)->Dup(), sumDim-1, nanInt);
3189
case GDL_UINT: return product_over_dim_cu_template<DUIntGDL>(static_cast<DUIntGDL*>(p0)->Dup(), sumDim-1, nanInt);
3190
case GDL_LONG: return product_over_dim_cu_template<DLongGDL>(static_cast<DLongGDL*>(p0)->Dup(), sumDim-1, nanInt);
3191
case GDL_ULONG: return product_over_dim_cu_template<DULongGDL>(static_cast<DULongGDL*>(p0)->Dup(), sumDim-1, nanInt);
3192
case GDL_LONG64: return product_over_dim_cu_template<DLong64GDL>(static_cast<DLong64GDL*>(p0)->Dup(), sumDim-1, nanInt);
3193
case GDL_ULONG64: return product_over_dim_cu_template<DULong64GDL>(static_cast<DULong64GDL*>(p0)->Dup(), sumDim-1, nanInt);
3194
case GDL_FLOAT: return product_over_dim_cu_template<DFloatGDL>(static_cast<DFloatGDL*>(p0)->Dup(), sumDim-1, KwNaN);
3195
case GDL_DOUBLE: return product_over_dim_cu_template<DDoubleGDL>(static_cast<DDoubleGDL*>(p0)->Dup(), sumDim-1, KwNaN);
3196
case GDL_COMPLEX: return product_over_dim_cu_template<DComplexGDL>(static_cast<DComplexGDL*>(p0)->Dup(), sumDim-1, KwNaN);
3197
case GDL_COMPLEXDBL: return product_over_dim_cu_template<DComplexDblGDL>(static_cast<DComplexDblGDL*>(p0)->Dup(), sumDim-1, KwNaN);
3198
default: assert(false);
3202
// Integer parts derivated from Total code by Erin Sheldon
3203
// In IDL PRODUCT(), the INTEGER keyword takes precedence
3205
// We use GDL_LONG64 unless the input is GDL_ULONG64
3206
if ((p0->Type() == GDL_LONG64) && (!KwNaN)) {
3207
return product_over_dim_cu_template<DLong64GDL>
3208
( static_cast<DLong64GDL*>(p0)->Dup(), sumDim-1, nanInt);
3210
if ((p0->Type() == GDL_ULONG64 ) && (!KwNaN)) {
3211
return product_over_dim_cu_template<DULong64GDL>
3212
( static_cast<DULong64GDL*>(p0)->Dup(), sumDim-1, nanInt);
3215
// Convert to Long64
3217
DFloatGDL* p0f = static_cast<DFloatGDL*>
3218
(p0->Convert2( GDL_FLOAT, BaseGDL::COPY));
3219
auto_ptr<DFloatGDL> guard( p0f);
3220
for( SizeT i=0; i<nEl; ++i) {
3221
if (!isfinite((*p0f)[i])) (*p0f)[i]=1;
3223
return product_over_dim_cu_template<DLong64GDL>
3224
( static_cast<DLong64GDL*>
3225
(p0f->Convert2( GDL_LONG64, BaseGDL::COPY)), sumDim-1, nanInt);
3227
return product_over_dim_cu_template<DLong64GDL>
3228
( static_cast<DLong64GDL*>
3229
(p0->Convert2( GDL_LONG64, BaseGDL::COPY)), sumDim-1, nanInt);
3231
} // integer results
3233
if( p0->Type() == GDL_DOUBLE) {
3234
return product_over_dim_cu_template< DDoubleGDL>
3235
( static_cast<DDoubleGDL*>(p0)->Dup(), sumDim-1, KwNaN);
3237
if( p0->Type() == GDL_COMPLEXDBL) {
3238
return product_over_dim_cu_template< DComplexDblGDL>
3239
( static_cast<DComplexDblGDL*>(p0)->Dup(), sumDim-1, KwNaN);
3241
if( p0->Type() == GDL_COMPLEX) {
3242
return product_over_dim_cu_template< DComplexDblGDL>
3243
( static_cast<DComplexDblGDL*>
3244
(p0->Convert2( GDL_COMPLEXDBL, BaseGDL::COPY)), sumDim-1, KwNaN);
3247
return product_over_dim_cu_template< DDoubleGDL>
3248
( static_cast<DDoubleGDL*>
3249
(p0->Convert2( GDL_DOUBLE, BaseGDL::COPY)), sumDim-1, KwNaN);
3253
BaseGDL* array_equal( EnvT* e)
3255
e->NParam( 2);//, "ARRAY_EQUAL");
3257
BaseGDL* p0 = e->GetParDefined( 0);//, "ARRAY_EQUAL");
3258
BaseGDL* p1 = e->GetParDefined( 1);//, "ARRAY_EQUAL");
3260
if( p0 == p1) return new DByteGDL( 1);
3262
SizeT nEl0 = p0->N_Elements();
3263
SizeT nEl1 = p1->N_Elements();
3264
if( nEl0 != nEl1 && nEl0 != 1 && nEl1 != 1)
3265
return new DByteGDL( 0);
3267
auto_ptr<BaseGDL> p0_guard;
3268
auto_ptr<BaseGDL> p1_guard;
3269
if( p0->Type() != p1->Type())
3271
if( e->KeywordSet( 0)) // NO_TYPECONV
3272
return new DByteGDL( 0);
3275
DType aTy=p0->Type();
3276
DType bTy=p1->Type();
3277
if( DTypeOrder[aTy] >= DTypeOrder[bTy])
3279
p1 = p1->Convert2( aTy, BaseGDL::COPY);
3280
p1_guard.reset( p1);
3284
p0 = p0->Convert2( bTy, BaseGDL::COPY);
3285
p0_guard.reset( p0);
3290
if( p0->ArrayEqual( p1)) return new DByteGDL( 1);
3292
return new DByteGDL( 0);
3295
BaseGDL* min_fun( EnvT* e)
3297
SizeT nParam = e->NParam( 1);
3298
BaseGDL* searchArr = e->GetParDefined( 0);
3300
bool omitNaN = e->KeywordSet( "NAN");
3302
static int subIx = e->KeywordIx("SUBSCRIPT_MAX");
3303
bool subMax = e->KeywordPresent(subIx);
3305
static int dimIx = e->KeywordIx("DIMENSION");
3306
bool dimSet = e->KeywordSet(dimIx);
3308
static int maxIx = e->KeywordIx("MAX");
3309
bool maxSet = e->KeywordPresent(maxIx);
3313
e->AssureLongScalarKW(dimIx, searchDim);
3314
if (searchDim < 0 || searchDim > searchArr->Rank())
3315
e->Throw("Illegal keyword value for DIMENSION");
3318
if (dimSet && searchArr->Rank() > 1)
3320
searchDim -= 1; // user-supplied dimensions start with 1!
3322
// here destDim is in fact the srcDim...
3323
dimension destDim = searchArr->Dim();
3324
SizeT searchStride = destDim.Stride(searchDim);
3325
SizeT outerStride = destDim.Stride(searchDim + 1);
3326
// ... and now becomes the destDim
3327
SizeT nSearch = destDim.Remove(searchDim);
3328
SizeT searchLimit = nSearch * searchStride;
3329
SizeT nEl = searchArr->N_Elements();
3331
// memory allocation
3332
BaseGDL *maxVal, *resArr = searchArr->New(destDim, BaseGDL::NOZERO);
3333
DLongGDL *minElArr, *maxElArr;
3337
e->AssureGlobalKW(maxIx); // instead of using a guard pointer
3338
maxVal = searchArr->New(destDim, BaseGDL::NOZERO);
3343
e->AssureGlobalKW(subIx); // instead of using a guard pointer
3344
maxElArr = new DLongGDL(destDim);
3349
e->AssureGlobalPar(1); // instead of using a guard pointer
3350
minElArr = new DLongGDL(destDim);
3354
for (SizeT o = 0; o < nEl; o += outerStride) for (SizeT i = 0; i < searchStride; ++i)
3357
(nParam == 2 ? &((*minElArr)[rIx]) : NULL),
3358
(subMax ? &((*maxElArr)[rIx]) : NULL),
3360
(maxSet ? &maxVal : NULL),
3361
omitNaN, o + i, searchLimit + o + i, searchStride, rIx
3366
if (nParam == 2) e->SetPar(1, minElArr);
3367
if (subMax) e->SetKW(subIx, maxElArr);
3368
if (maxSet) e->SetKW(maxIx, maxVal);
3377
if (maxSet) // MAX keyword given
3379
e->AssureGlobalKW( 0);
3380
GDLDelete(e->GetKW( 0));
3382
searchArr->MinMax( &minEl, &maxEl, &res, &e->GetKW( 0), omitNaN);
3383
if (subMax) e->SetKW(subIx, new DLongGDL(maxEl));
3385
else // no MAX keyword
3390
searchArr->MinMax( &minEl, &maxEl, &res, NULL, omitNaN);
3391
e->SetKW(subIx, new DLongGDL(maxEl));
3393
else searchArr->MinMax(&minEl, NULL, &res, NULL, omitNaN);
3397
if (nParam == 2) e->SetPar(1, new DLongGDL( minEl));
3398
else SysVar::SetC( minEl);
3403
BaseGDL* max_fun( EnvT* e)
3405
SizeT nParam = e->NParam( 1);
3406
BaseGDL* searchArr = e->GetParDefined( 0);
3408
bool omitNaN = e->KeywordSet( "NAN");
3410
static int subIx = e->KeywordIx("SUBSCRIPT_MIN");
3411
bool subMin = e->KeywordPresent(subIx);
3413
static int dimIx = e->KeywordIx("DIMENSION");
3414
bool dimSet = e->KeywordSet(dimIx);
3416
static int minIx = e->KeywordIx("MIN");
3417
bool minSet = e->KeywordPresent(minIx);
3422
e->AssureLongScalarKW(dimIx, searchDim);
3423
if (searchDim < 0 || searchDim > searchArr->Rank())
3424
e->Throw("Illegal keyword value for DIMENSION");
3427
if (dimSet && searchArr->Rank() > 1)
3429
searchDim -= 1; // user-supplied dimensions start with 1!
3431
// here destDim is in fact the srcDim...
3432
dimension destDim = searchArr->Dim();
3433
SizeT searchStride = destDim.Stride(searchDim);
3434
SizeT outerStride = destDim.Stride(searchDim + 1);
3435
// ... and now becomes the destDim
3436
SizeT nSearch = destDim.Remove(searchDim);
3437
SizeT searchLimit = nSearch * searchStride;
3438
SizeT nEl = searchArr->N_Elements();
3440
// memory allocation
3441
BaseGDL *minVal, *resArr = searchArr->New(destDim, BaseGDL::NOZERO);
3442
DLongGDL *minElArr, *maxElArr;
3446
e->AssureGlobalKW(minIx); // instead of using a guard pointer
3447
minVal = searchArr->New(destDim, BaseGDL::NOZERO);
3452
e->AssureGlobalKW(subIx); // instead of using a guard pointer
3453
minElArr = new DLongGDL(destDim);
3458
e->AssureGlobalPar(1); // instead of using a guard pointer
3459
maxElArr = new DLongGDL(destDim);
3463
for (SizeT o = 0; o < nEl; o += outerStride) for (SizeT i = 0; i < searchStride; ++i)
3466
(subMin ? &((*minElArr)[rIx]) : NULL),
3467
(nParam == 2 ? &((*maxElArr)[rIx]) : NULL),
3468
(minSet ? &minVal : NULL),
3470
omitNaN, o + i, searchLimit + o + i, searchStride, rIx
3475
if (nParam == 2) e->SetPar(1, maxElArr);
3476
if (subMin) e->SetKW(subIx, minElArr);
3477
if (minSet) e->SetKW(minIx, minVal);
3486
if (minSet) // MIN keyword given
3488
e->AssureGlobalKW( 0);
3489
GDLDelete(e->GetKW( 0));
3491
searchArr->MinMax( &minEl, &maxEl, &e->GetKW( 0), &res, omitNaN);
3492
if (subMin) e->SetKW(subIx, new DLongGDL(minEl));
3494
else // no MIN keyword
3499
searchArr->MinMax( &minEl, &maxEl, NULL, &res, omitNaN);
3500
e->SetKW(subIx, new DLongGDL(minEl));
3502
else searchArr->MinMax(NULL, &maxEl, NULL, &res, omitNaN);
3506
if (nParam == 2) e->SetPar(1, new DLongGDL( maxEl));
3507
else SysVar::SetC(maxEl);
3512
BaseGDL* transpose( EnvT* e)
3514
SizeT nParam=e->NParam( 1);
3516
BaseGDL* p0 = e->GetParDefined( 0);
3517
if( p0->Type() == GDL_STRUCT)
3518
e->Throw("Struct expression not allowed in this context: "+
3519
e->GetParString(0));
3521
SizeT rank = p0->Rank();
3523
e->Throw( "Expression must be an array "
3524
"in this context: "+ e->GetParString(0));
3529
BaseGDL* p1 = e->GetParDefined( 1);
3530
if( p1->N_Elements() != rank)
3531
e->Throw("Incorrect number of elements in permutation.");
3533
DUInt* perm = new DUInt[rank];
3534
auto_ptr<DUInt> perm_guard( perm);
3536
DUIntGDL* p1L = static_cast<DUIntGDL*>
3537
(p1->Convert2( GDL_UINT, BaseGDL::COPY));
3538
for( SizeT i=0; i<rank; ++i) perm[i] = (*p1L)[ i];
3541
// check permutation vector
3542
for( SizeT i=0; i<rank; ++i)
3545
for( j=0; j<rank; ++j) if( perm[j] == i) break;
3547
e->Throw( "Incorrect permutation vector.");
3549
return p0->Transpose( perm);
3552
return p0->Transpose( NULL);
3556
// BaseGDL* matrix_multiply( EnvT* e)
3558
// SizeT nParam=e->NParam( 2);
3560
// BaseGDL* a = e->GetNumericArrayParDefined( 0);
3561
// BaseGDL* b = e->GetNumericArrayParDefined( 1);
3563
// static int aTIx = e->KeywordIx("ATRANSPOSE");
3564
// bool aT = e->KeywordPresent(aTIx);
3565
// static int bTIx = e->KeywordIx("BTRANSPOSE");
3566
// bool bT = e->KeywordPresent(bTIx);
3568
// static int strassenIx = e->KeywordIx("STRASSEN_ALGORITHM");
3569
// bool strassen = e->KeywordPresent(strassenIx);
3572
// if( p1->N_Elements() != rank)
3573
// e->Throw("Incorrect number of elements in permutation.");
3575
// DUInt* perm = new DUInt[rank];
3576
// auto_ptr<DUInt> perm_guard( perm);
3578
// DUIntGDL* p1L = static_cast<DUIntGDL*>
3579
// (p1->Convert2( GDL_UINT, BaseGDL::COPY));
3580
// for( SizeT i=0; i<rank; ++i) perm[i] = (*p1L)[ i];
3583
// // check permutaion vector
3584
// for( SizeT i=0; i<rank; ++i)
3587
// for( j=0; j<rank; ++j) if( perm[j] == i) break;
3589
// e->Throw( "Incorrect permutation vector.");
3591
// return p0->Transpose( perm);
3594
// return a->Transpose( NULL);
3597
// helper function for sort_fun, recursive
3598
// optimized version
3599
template< typename IndexT>
3600
void MergeSortOpt( BaseGDL* p0, IndexT* hhS, IndexT* h1, IndexT* h2,
3603
if( len <= 1) return;
3605
SizeT h1N = len / 2;
3606
SizeT h2N = len - h1N;
3609
MergeSortOpt(p0, hhS, h1, h2, h1N);
3612
IndexT* hhM = &hhS[h1N];
3613
MergeSortOpt(p0, hhM, h1, h2, h2N);
3616
for(i=0; i<h1N; ++i) h1[i] = hhS[ i];
3617
for(i=0; i<h2N; ++i) h2[i] = hhM[ i];
3621
for( i=0; (h1Ix < h1N) && (h2Ix < h2N); ++i)
3623
// the actual comparisson
3624
if( p0->Greater( h1[h1Ix], h2[h2Ix]))
3625
hhS[ i] = h2[ h2Ix++];
3627
hhS[ i] = h1[ h1Ix++];
3629
for(; h1Ix < h1N; ++i) hhS[ i] = h1[ h1Ix++];
3630
for(; h2Ix < h2N; ++i) hhS[ i] = h2[ h2Ix++];
3633
// helper function for sort_fun, recursive
3634
void MergeSort( BaseGDL* p0, SizeT* hh, SizeT* h1, SizeT* h2,
3635
SizeT start, SizeT end)
3637
if( start+1 >= end) return;
3639
SizeT middle = (start+end) / 2;
3641
MergeSort(p0, hh, h1, h2, start, middle);
3642
MergeSort(p0, hh, h1, h2, middle, end);
3644
SizeT h1N = middle - start;
3645
SizeT h2N = end - middle;
3647
SizeT* hhS = &hh[start];
3650
for(i=0; i<h1N; ++i) h1[i] = hhS[ i];
3651
for(i=0; i<h2N; ++i) h2[i] = hh[middle + i];
3655
for( i=0; (h1Ix < h1N) && (h2Ix < h2N); ++i)
3657
// the actual comparisson
3658
if( p0->Greater( h1[h1Ix], h2[h2Ix]))
3659
hhS[ i] = h2[ h2Ix++];
3661
hhS[ i] = h1[ h1Ix++];
3663
for(; h1Ix < h1N; ++i) hhS[ i] = h1[ h1Ix++];
3664
for(; h2Ix < h2N; ++i) hhS[ i] = h2[ h2Ix++];
3667
// sort function uses MergeSort
3668
BaseGDL* sort_fun( EnvT* e)
3672
BaseGDL* p0 = e->GetParDefined( 0);
3674
if( p0->Type() == GDL_STRUCT)
3675
e->Throw( "Struct expression not allowed in this context: "+
3676
e->GetParString(0));
3678
static int l64Ix = e->KeywordIx( "L64");
3679
bool l64 = e->KeywordSet( l64Ix);
3681
SizeT nEl = p0->N_Elements();
3684
DLongGDL* res = new DLongGDL( dimension( nEl), BaseGDL::INDGEN);
3687
if( p0->Type() == GDL_FLOAT)
3689
DFloatGDL* p0F = static_cast<DFloatGDL*>(p0);
3690
for( DLong i=nEl-1; i >= 0; --i)
3692
if( isnan((*p0F)[ i]) )//|| !isfinite((*p0F)[ i]))
3695
(*res)[i] = (*res)[nanIx];
3698
// cout << "swap " << i << " with " << nanIx << endl;
3700
// for( DLong ii=0; ii < nEl; ++ii)
3702
// cout << (*res)[ii] << " ";
3708
else if( p0->Type() == GDL_DOUBLE)
3710
DDoubleGDL* p0F = static_cast<DDoubleGDL*>(p0);
3711
for( DLong i=nEl-1; i >= 0; --i)
3713
if( isnan((*p0F)[ i]))// || !isfinite((*p0F)[ i]))
3716
(*res)[i] = (*res)[nanIx];
3721
else if( p0->Type() == GDL_COMPLEX)
3723
DComplexGDL* p0F = static_cast<DComplexGDL*>(p0);
3724
for( DLong i=nEl-1; i >= 0; --i)
3726
if( isnan((*p0F)[ i].real()) || //!isfinite((*p0F)[ i].real()) ||
3727
isnan((*p0F)[ i].imag()))// || !isfinite((*p0F)[ i].imag()) )
3730
(*res)[i] = (*res)[nanIx];
3735
else if( p0->Type() == GDL_COMPLEXDBL)
3737
DComplexDblGDL* p0F = static_cast<DComplexDblGDL*>(p0);
3738
for( DLong i=nEl-1; i >= 0; --i)
3740
if( isnan((*p0F)[ i].real()) || //!isfinite((*p0F)[ i].real()) ||
3741
isnan((*p0F)[ i].imag()))// || !isfinite((*p0F)[ i].imag()) )
3744
(*res)[i] = (*res)[nanIx];
3750
// cout << "nEl " << nEl << " nanIx " << nanIx << endl;
3752
// cout << "sorting: ";
3753
// for( DLong ii=0; ii < nEl; ++ii)
3755
// cout << (*res)[ii] << " ";
3759
DLong *hh = static_cast<DLong*>(res->DataAddr());
3761
DLong* h1 = new DLong[ nEl/2];
3762
DLong* h2 = new DLong[ (nEl+1)/2];
3763
// call the sort routine
3764
MergeSortOpt<DLong>( p0, hh, h1, h2, nEl);
3770
// leave it this way, as sorting of more than 2^31
3771
// items seems not feasible in the future we might
3772
// use MergeSortOpt<DLong64>(...) for this
3773
return res->Convert2( GDL_LONG64);
3780
// 2 parts in the code: without "width" or with "width" (limited to 1D and 2D)
3781
BaseGDL* median( EnvT* e) {
3783
BaseGDL* p0 = e->GetParDefined( 0);
3785
if( p0->Type() == GDL_PTR)
3786
e->Throw( "Pointer expression not allowed in this context: "+ e->GetParString(0));
3787
if( p0->Type() == GDL_OBJ)
3788
e->Throw( "Object expression not allowed in this context: "+ e->GetParString(0));
3789
if( p0->Type() == GDL_STRUCT)
3790
e->Throw( "Struct expression not allowed in this context: "+ e->GetParString(0));
3792
if( p0->Rank() == 0)
3793
e->Throw( "Expression must be an array in this context: "+ e->GetParString(0));
3795
SizeT nParam = e->NParam( 1);
3796
SizeT nEl = p0->N_Elements();
3798
// "f_nan" and "d_nan" used by both parts ...
3799
static DStructGDL *Values = SysVar::Values();
3800
DFloat f_nan=(*static_cast<DFloatGDL*>(Values->GetTag(Values->Desc()->TagIndex("F_NAN"), 0)))[0];
3801
DDouble d_nan=(*static_cast<DDoubleGDL*>(Values->GetTag(Values->Desc()->TagIndex("D_NAN"), 0)))[0];
3803
// --------------------------------------------------------
3804
// begin of the part 1: without "width" param
3807
static int evenIx = e->KeywordIx( "EVEN");
3811
p0->Type() == GDL_DOUBLE ||
3812
p0->Type() == GDL_COMPLEXDBL ||
3813
e->KeywordSet(e->KeywordIx("DOUBLE"));
3814
DType type = dbl ? GDL_DOUBLE : GDL_FLOAT;
3815
bool noconv = (dbl && p0->Type() == GDL_DOUBLE) ||
3816
(!dbl && p0->Type() == GDL_FLOAT);
3818
// DIMENSION keyword
3822
e->AssureLongScalarKWIfPresent( "DIMENSION", dim);
3824
// cout << "dim : "<< dim << endl;
3826
if (dim > p0->Rank())
3827
e->Throw( "Illegal keyword value for DIMENSION.");
3832
for (SizeT i=0; i<p0->Rank(); ++i)
3835
dims[k++] = p0->Dim(i);
3837
dimension dimRes((DLong *) dims, p0->Rank()-1);
3839
? static_cast<BaseGDL*>(new DDoubleGDL(dimRes, BaseGDL::NOZERO))
3840
: static_cast<BaseGDL*>(new DFloatGDL(dimRes, BaseGDL::NOZERO));
3843
? static_cast<BaseGDL*>(new DDoubleGDL(1))
3844
: static_cast<BaseGDL*>(new DFloatGDL(1));
3847
// conversion of Complex types
3848
if (p0->Type() == GDL_COMPLEX) p0 = p0->Convert2(GDL_FLOAT, BaseGDL::COPY);
3849
if (p0->Type() == GDL_COMPLEXDBL) p0 = p0->Convert2(GDL_DOUBLE, BaseGDL::COPY);
3852
if (nmed > 1) nEl = p0->N_Elements() / nmed;
3854
// cout << "hello2" << endl;
3856
DLong *hh = new DLong[ nEl];
3857
DLong* h1 = new DLong[ nEl/2];
3858
DLong* h2 = new DLong[ (nEl+1)/2];
3860
DLong accumStride = 1;
3862
for( DLong i=0; i<dim-1; ++i) accumStride *= p0->Dim(i);
3864
BaseGDL *op1, *op2, *op3;
3865
if (dbl) op3 = new DDoubleGDL(2);
3866
else op3 = new DFloatGDL(2);
3868
// nEl_extern is used to store "nEl" initial value
3869
DLong nanIx, nEl_extern;
3871
// if (nmed > 1) nEl_extern = p0->N_Elements() / nmed;
3872
//else nEl_extern = p0->N_Elements();
3874
// cout << "hello type" << p0->Type() << endl;
3876
// Loop over all subarray medians
3877
for (SizeT k=0; k<nmed; ++k) {
3882
//cout << "hello inside 1D" << endl;
3883
for( DLong i=0; i<nEl; ++i) hh[i] = i;
3886
if (p0->Type() == GDL_DOUBLE) {
3887
DDoubleGDL* p0F = static_cast<DDoubleGDL*>(p0);
3888
for( DLong i=nEl-1; i >= 0; --i) {
3889
if( isnan((*p0F)[i])) {
3897
if (p0->Type() == GDL_FLOAT) {
3898
DFloatGDL* p0F = static_cast<DFloatGDL*>(p0);
3899
for( DLong i=nEl-1; i >= 0; --i) {
3900
if( isnan((*p0F)[i])) {
3908
//cout << "nEl " << nEl << " nanIx " << nanIx << endl;
3916
// DLong nanIx = nEl;
3918
DLong start = accumStride * p0->Dim(dim-1) * (k / accumStride) +
3920
for( DLong i=0; i<nEl; ++i) hh[i] = start + i * accumStride;
3924
if (p0->Type() == GDL_FLOAT) {
3925
DFloatGDL* p0F = static_cast<DFloatGDL*>(p0);
3926
for( DLong i=nEl-1; i >= 0; --i) {
3927
jj=start + i * accumStride;
3928
if( isnan((*p0F)[ jj]) ) {
3937
if (p0->Type() == GDL_DOUBLE) {
3938
DDoubleGDL* p0F = static_cast<DDoubleGDL*>(p0);
3939
for( DLong i=nEl-1; i >= 0; --i) {
3940
jj=start + i * accumStride;
3941
if( isnan((*p0F)[ jj]) ) {
3947
//cout << "nanIx :" << nanIx << "nEl :" << nEl << endl;
3951
DLong medEl, medEl_1;
3953
// call the sort routine
3955
MergeSortOpt<DLong>( p0, hh, h1, h2, nEl);
3957
medEl_1 = hh[ nEl/2 - 1];
3963
{ // normal case, more than one element, nothing to do
3964
//cout << "gasp : no result ! " << endl;
3968
if (nEl <= 0) { // we have a NaN
3969
if (dbl) (*static_cast<DDoubleGDL*>(res))[k] = d_nan;
3970
else (*static_cast<DFloatGDL*>(res))[k] = f_nan;
3972
//cout << k << "" << (*static_cast<DFloatGDL*>(p0))[medEl] << " "
3973
// << (*static_cast<DFloatGDL*>(p0))[medEl_1] << endl;
3974
//cout << "k :" << k << endl;
3975
if( (nEl % 2) == 1 || !e->KeywordSet( evenIx)) {
3977
res = p0->NewIx(medEl)->Convert2(type, BaseGDL::CONVERT);
3981
if (dbl) (*static_cast<DDoubleGDL*>(res))[k] = (*static_cast<DDoubleGDL*>(p0))[medEl];
3982
else (*static_cast<DFloatGDL*>(res))[k] = (*static_cast<DFloatGDL*>(p0))[medEl];
3986
op1 = p0->NewIx(medEl)->Convert2(type, BaseGDL::CONVERT);
3987
if (dbl) (*static_cast<DDoubleGDL*>(res))[k] = (*static_cast<DDoubleGDL*>(op1))[0];
3988
else (*static_cast<DFloatGDL*>(res))[k] = (*static_cast<DFloatGDL*>(op1))[0];
3995
if (dbl) (*static_cast<DDoubleGDL*>(res))[k] = .5 * (
3996
(*static_cast<DDoubleGDL*>(p0))[medEl] +
3997
(*static_cast<DDoubleGDL*>(p0))[medEl_1]
3999
else (*static_cast<DFloatGDL*>(res))[k] = .5 * (
4000
(*static_cast<DFloatGDL*>(p0))[medEl] +
4001
(*static_cast<DFloatGDL*>(p0))[medEl_1]
4006
op1 = p0->NewIx(medEl)->Convert2(type, BaseGDL::CONVERT);
4007
op2 = p0->NewIx(medEl_1)->Convert2(type, BaseGDL::CONVERT);
4008
if (nmed == 1) res = op2->Add(op1)->Div(op3); // TODO: leak with res?
4011
if (dbl) (*static_cast<DDoubleGDL*>(res))[k] =
4012
(*static_cast<DDoubleGDL*>((op2->Add(op1)->Div(op3))))[0];
4013
else (*static_cast<DFloatGDL*>(res))[k] =
4014
(*static_cast<DFloatGDL*>((op2->Add(op1)->Div(op3))))[0];
4030
// begin of the part 2: with "width" param
4032
// with parameter Width : median filtering with no optimisation,
4033
// such as histogram algorithms.
4034
// Copyright: (C) 2008 by Nicolas Galmiche
4036
// basic checks on "vector/array" input
4037
DDoubleGDL* p0 = e->GetParAs<DDoubleGDL>( 0);
4040
e->Throw( "Only 1 or 2 dimensions allowed: "+ e->GetParString(0));
4042
// basic checks on "width" input
4043
DDoubleGDL* p1d = e->GetParAs<DDoubleGDL>(1);
4045
if (p1d->N_Elements() > 1 || (*p1d)[0] <=0 )
4046
e->Throw( "Width must be a positive scalar or 1 (positive) element array in this context: "+ e->GetParString(0));
4047
DLong MaxAllowedWidth=0;
4048
if (p0->Rank() == 1) MaxAllowedWidth=p0->N_Elements();
4049
if (p0->Rank() == 2) {
4050
MaxAllowedWidth=p0->Dim(0);
4051
if (p0->Dim(1) < MaxAllowedWidth) MaxAllowedWidth=p0->Dim(1);
4055
cout << "X dim " << p0->Dim(0) <<endl;
4056
cout << "y dim " << p0->Dim(1) <<endl;
4057
cout << "MaxAllowedWidth " << MaxAllowedWidth <<endl;
4059
if (!isfinite( (*p1d)[0]))
4060
e->Throw("Width must be > 1, and < dimension of array (NaN or Inf)");
4062
DLongGDL* p1 = e->GetParAs<DLongGDL>(1);
4064
DDoubleGDL *tamp = new DDoubleGDL(p0->Dim(),BaseGDL::NOZERO);
4065
DDouble min=((*p0)[0]);
4068
for (SizeT ii=0 ; ii<p0->N_Elements() ; ++ii)
4069
{(*tamp)[ii]=(*p0)[ii];
4070
if ( (*p0)[ii] < min ) min = ((*p0)[ii]);
4071
if ( (*p0)[ii] > max ) max = ((*p0)[ii]);
4074
//---------------------------- END d'acquisistion des paramètres -------------------------------------
4077
static int evenIx = e->KeywordIx( "EVEN");
4078
static int doubleIx = e->KeywordIx( "DOUBLE");
4079
static DStructGDL *Values = SysVar::Values();
4080
DDouble d_nan=(*static_cast<DDoubleGDL*>(Values->GetTag(Values->Desc()->TagIndex("D_NAN"), 0)))[0];
4081
DDouble d_infinity= (*static_cast<DDoubleGDL*>(Values->GetTag(Values->Desc()->TagIndex("D_INFINITY"), 0)))[0];
4083
//------------------------------ Init variables and allocation ---------------------------------------
4084
SizeT width=(*p1)[0];
4085
SizeT N_MaskElem= width*width;
4086
SizeT larg = p0->Stride(1);
4087
SizeT haut = p0->Stride(2)/larg;
4088
SizeT lim= static_cast<SizeT>(round(width/2));
4089
SizeT init=(lim*larg+lim);
4091
// we don't go further if dimension(s) versus not width OK
4093
if (debug == 1) {cout << "ici" <<endl;}
4095
if ( p0->Rank() == 1) {
4096
if (larg < width || width==1 ) e->Throw( "Width must be > 1, and < width of vector");
4098
if ( p0->Rank() == 2) {
4099
if (larg < width || haut < width || width==1) e->Throw("Width must be > 1, and < dimension of array");
4102
// for 2D arrays, we use the algorithm described in paper
4103
// from T. Huang, G. Yang, and G. Tang, “A Fast Two-Dimensional Median
4104
// Filtering Algorithm,” IEEE Trans. Acoust., Speech, Signal Processing,
4105
// vol. 27, no. 1, pp. 13–18, 1979.
4107
if ( (e->GetParDefined( 0)->Type() == GDL_BYTE ||
4108
e->GetParDefined( 0)->Type() == GDL_INT ||
4109
e->GetParDefined( 0)->Type() == GDL_UINT ||
4110
e->GetParDefined( 0)->Type() == GDL_LONG ||
4111
e->GetParDefined( 0)->Type() == GDL_ULONG ||
4112
e->GetParDefined( 0)->Type() == GDL_LONG64 ||
4113
e->GetParDefined( 0)->Type() == GDL_ULONG64) &&
4116
SizeT taille=static_cast<SizeT>(abs(max)-min+1);
4117
DDoubleGDL* Histo = new DDoubleGDL(taille,BaseGDL::NOZERO);
4120
for(SizeT i=0 ; i<haut-2*lim ; ++i)
4124
SizeT initial=init+i*larg-lim*larg-lim;
4125
for(SizeT pp=0 ; pp<taille;++pp)(*Histo)[pp]=0;
4126
for (SizeT ii=initial ; ii <initial+ width ; ++ii)
4128
for(SizeT yy=0;yy<width;yy++)
4129
(*Histo)[static_cast<SizeT>((*p0)[ii+yy*larg]-min)]++;
4132
while (ltmed+(*Histo)[med]<=(N_MaskElem /2))
4134
ltmed+= static_cast<SizeT>((*Histo)[med]);
4137
if (e->KeywordSet( evenIx))
4141
//if ((*Histo)[EvenMed]==1 || (ltmed!=0 && ltmed !=(N_MaskElem /2) -1))
4142
if ((*Histo)[EvenMed]==1 || (ltmed!=0 && N_MaskElem /2- ltmed!=1) )
4144
while ((*Histo)[EvenMed-1]==0)
4146
(*tamp)[init+i*larg]=((med+min)+(EvenMed-1+min))/2;
4149
(*tamp)[init+i*larg]=med+min;
4152
{(*tamp)[init+i*larg]=med+min; }
4154
for(SizeT j=init+i*larg +1; j<init+(i+1)*larg-2*lim ;++ j)
4156
SizeT initMask=j-lim*larg-lim;
4157
for(SizeT k=0;k<2*lim;++k)
4159
(*Histo)[static_cast<SizeT>((*p0)[initMask-1+k*larg]-min)]--;
4160
if ((*p0)[initMask-1+k*larg]-min<med)ltmed--;
4162
(*Histo)[static_cast<SizeT>((*p0)[initMask+k*larg+2*lim-1]-min)]++;
4163
if ((*p0)[initMask+k*larg+2*lim-1]-min<med)ltmed++;
4165
if (ltmed>N_MaskElem /2)
4167
while(ltmed>N_MaskElem /2)
4170
ltmed-=static_cast<SizeT>((*Histo)[med]);
4175
while (ltmed+(*Histo)[med]<=(N_MaskElem /2))
4177
ltmed+= static_cast<SizeT>((*Histo)[med]);
4182
if (e->KeywordSet( evenIx))
4185
if ((*Histo)[EvenMed]==1 || (ltmed!=0 &&N_MaskElem /2- ltmed!=1 ))
4187
while ((*Histo)[EvenMed-1]==0)
4189
(*tamp)[j]=((med+min)+(EvenMed-1+min))/2;
4192
{(*tamp)[j]=med+min; }
4195
{(*tamp)[j]=med+min; }
4201
for(SizeT i=0 ; i<haut-2*lim ; ++i)
4205
SizeT initial=init+i*larg-lim*larg-lim;
4206
for(SizeT pp=0 ; pp<taille;++pp)(*Histo)[pp]=0;
4207
for (SizeT ii=initial ; ii <initial+ width ; ++ii)
4209
for(SizeT yy=0;yy<width;yy++)
4210
(*Histo)[static_cast<SizeT>((*p0)[ii+yy*larg]-min)]++;
4213
while (ltmed+(*Histo)[med]<=(N_MaskElem /2))
4215
ltmed+= static_cast<SizeT>((*Histo)[med]);
4218
(*tamp)[init+i*larg]=med+min;
4220
for(SizeT j=init+i*larg +1; j<init+(i+1)*larg-2*lim ;++ j)
4223
SizeT initMask=j-lim*larg-lim;
4224
for(SizeT k=0;k<=2*lim;++k)
4226
(*Histo)[static_cast<SizeT>((*p0)[initMask-1+k*larg]-min)]--;
4227
if ((*p0)[initMask-1+k*larg]-min<med)ltmed--;
4229
(*Histo)[static_cast<SizeT>((*p0)[initMask+k*larg+2*lim]-min)]++;
4230
if ((*p0)[initMask+k*larg+2*lim]-min<med)ltmed++;
4232
if (ltmed>N_MaskElem /2)
4234
while(ltmed>N_MaskElem /2)
4237
ltmed-=static_cast<SizeT>((*Histo)[med]);
4242
while (ltmed+(*Histo)[med]<=(N_MaskElem /2))
4244
ltmed+= static_cast<SizeT>((*Histo)[med]);
4261
DDoubleGDL* Mask,*Mask1D;
4262
if ( p0->Rank() != 1 )
4264
hh = new DLong[ N_MaskElem];
4265
h1 = new DLong[ N_MaskElem/2];
4266
h2= new DLong[ (N_MaskElem+1)/2];
4267
Mask = new DDoubleGDL(N_MaskElem,BaseGDL::NOZERO);
4269
for( DLong i=0; i<N_MaskElem; ++i) hh[i] = i;
4273
hh = new DLong[ width];
4274
h1 = new DLong[ width/2];
4275
h2= new DLong[(width+1)/2];
4276
Mask1D = new DDoubleGDL(width,BaseGDL::NOZERO);
4278
for( DLong i=0; i<width; ++i) hh[i] = i;
4281
//-------------------------------- END OF VARIABLES INIT ---------------------------------------------
4283
//------------------------------ Median Filter Algorithms ---------------------------------------
4287
if ( p0->Rank() == 1 )//------------------------ For a vector with even width -------------------
4289
for (SizeT col= lim ; col<larg-lim ; ++col)
4293
for (SizeT ind=col-lim ; ind<col+lim ; ++ind)
4295
if( (*p0)[ind]!=d_infinity && (*p0)[ind]!=-d_infinity && isfinite((*p0)[ind])==0)
4299
(*Mask1D)[kk]=(*p0)[ind];
4305
if(ctl_NaN==width)(*tamp)[col]= d_nan;
4308
DLong* hhbis = new DLong[ width-ctl_NaN];
4309
DLong* h1bis = new DLong[ width-ctl_NaN/2];
4310
DLong* h2bis= new DLong[(width-ctl_NaN+1)/2];
4311
DDoubleGDL *Mask1Dbis = new DDoubleGDL(width-ctl_NaN,BaseGDL::NOZERO);
4312
for( DLong t=0; t<width-ctl_NaN; ++t) hhbis[t] = t;
4313
for( DLong ii=0; ii<width-ctl_NaN; ++ii)(*Mask1Dbis)[ii]=(*Mask1D)[ii];
4314
BaseGDL* besort=static_cast<BaseGDL*>(Mask1Dbis);
4315
MergeSortOpt<DLong>( besort, hhbis, h1bis, h2bis,(width - ctl_NaN));
4316
if (e->KeywordSet( evenIx)&& (width - ctl_NaN) % 2 == 0)
4317
(*tamp)[col]=((*Mask1Dbis)[hhbis[ (width-ctl_NaN)/2]]+(*Mask1Dbis
4318
)[hhbis [ (width - ctl_NaN-1)/2]])/2;
4320
(*tamp)[col]=(*Mask1Dbis)[hhbis[ (width- ctl_NaN)/2]];
4328
BaseGDL* besort=static_cast<BaseGDL*>(Mask1D);
4329
MergeSortOpt<DLong>( besort, hh, h1, h2,width ); // call the sort routine
4331
if (e->KeywordSet( evenIx))
4333
(*tamp)[col]=((*Mask1D)[hh[ width/2]]+(*Mask1D)[hh[ (width-1)/2]])/2;
4335
(*tamp)[col]=(*Mask1D)[hh[ width/2]];// replace value by Mask median
4340
else//------------------------ For an array with even width -------------------
4343
for(SizeT i=0 ; i<haut-2*lim ; ++i) // lines to replace
4345
for(SizeT j=init+i*larg ; j<init+(i+1)*larg-2*lim ; ++j)// elements to replace
4347
SizeT initMask=j-lim*larg-lim; // left corner of mask
4350
for(SizeT k=0;k<2*lim;++k) // lines of mask
4353
for(jj=initMask+k*larg ; jj<(initMask+k*larg)+2*lim ; ++jj) // elements of mask
4355
if( (*p0)[jj]!=d_infinity && (*p0)[jj]!=-d_infinity && isfinite((*p0)[jj])==0)
4359
(*Mask)[kk]=(*p0)[jj];
4366
if(ctl_NaN==N_MaskElem)(*tamp)[j]= d_nan;
4368
DLong* hhb = new DLong[ N_MaskElem-ctl_NaN];
4369
DLong* h1b = new DLong[ (N_MaskElem-ctl_NaN)/2];
4370
DLong* h2b = new DLong[(N_MaskElem-ctl_NaN+1)/2];
4371
DDoubleGDL *Maskb = new DDoubleGDL(N_MaskElem-ctl_NaN,BaseGDL::NOZERO);
4372
for( DLong t=0; t<N_MaskElem-ctl_NaN; ++t) hhb[t] = t;
4373
for( DLong ii=0; ii<N_MaskElem-ctl_NaN; ++ii)(*Maskb)[ii]=(*Mask)[ii];
4374
BaseGDL* besort=static_cast<BaseGDL*>(Maskb);
4375
MergeSortOpt<DLong>( besort, hhb, h1b, h2b,(N_MaskElem - ctl_NaN));
4376
if ((N_MaskElem - ctl_NaN) % 2 == 0 && e->KeywordSet( evenIx))
4377
(*tamp)[j]=((*Maskb)[hhb[ (N_MaskElem-ctl_NaN)/2]]+(*Maskb)[hhb
4381
(*tamp)[j]=(*Maskb)[hhb[ (N_MaskElem- ctl_NaN)/2]];
4389
BaseGDL* besort=static_cast<BaseGDL*>(Mask);
4390
MergeSortOpt<DLong>( besort, hh, h1, h2, N_MaskElem); // call the sort routine
4391
if (e->KeywordSet( evenIx))
4392
(*tamp)[j]=((*Mask)[hh[ N_MaskElem/2]]+(*Mask)[hh[ (N_MaskElem-1)/2]])/2;
4394
(*tamp)[j]=(*Mask)[hh[ N_MaskElem/2]];// replace value by median Mask one
4403
if ( p0->Rank() == 1 )//------------------------ For a vector with odd width -------------------
4406
for (SizeT col= lim ; col<larg-lim ; ++col)
4410
for (SizeT ind=col-lim ; ind<=col+lim ; ++ind)
4411
{if( (*p0)[ind]!=d_infinity && (*p0)[ind]!=-d_infinity && isfinite((*p0)[ind])==0)
4414
(*Mask1D)[kk]=(*p0)[ind];
4420
if(ctl_NaN==width)(*tamp)[col]= d_nan;
4422
DLong* hhbis = new DLong[ width-ctl_NaN];
4423
DLong* h1bis = new DLong[ width-ctl_NaN/2];
4424
DLong* h2bis= new DLong[(width-ctl_NaN+1)/2];
4425
DDoubleGDL *Mask1Dbis = new DDoubleGDL(width-ctl_NaN,BaseGDL::NOZERO);
4426
for( DLong t=0; t<width-ctl_NaN; ++t) hhbis[t] = t;
4427
for( DLong ii=0; ii<width-ctl_NaN; ++ii)(*Mask1Dbis)[ii]=(*Mask1D)[ii];
4428
BaseGDL* besort=static_cast<BaseGDL*>(Mask1Dbis);
4429
MergeSortOpt<DLong>( besort, hhbis, h1bis, h2bis,(width - ctl_NaN));
4430
if (e->KeywordSet( evenIx)&& (width - ctl_NaN) % 2 == 0)
4431
(*tamp)[col]=((*Mask1Dbis)[hhbis[ (width-ctl_NaN)/2]]+(*Mask1Dbis
4432
)[hhbis [ (width - ctl_NaN-1)/2]])/2;
4433
else(*tamp)[col]=(*Mask1Dbis)[hhbis[ (width- ctl_NaN)/2]];
4441
BaseGDL* besort=static_cast<BaseGDL*>(Mask1D);
4442
MergeSortOpt<DLong>( besort, hh, h1, h2,width ); // call the sort routine
4443
(*tamp)[col]=(*Mask1D)[hh[ (width)/2]]; // replace value by Mask median
4449
else //----------------------------- For an array with odd width ---------------------------------
4452
for(SizeT i=0 ; i<haut-2*lim ; ++i) // lines to replace
4455
SizeT initial=init+i*larg-lim*larg-lim;
4456
SizeT dd=0;SizeT ctl_NaN_init=0;
4457
for(SizeT yy=0;yy<width;yy++)
4459
for (SizeT ii=initial+yy*larg ; ii <initial+ yy*larg+ width; ++ii)
4462
if( (*p0)[ii]!=d_infinity && (*p0)[ii]!=-d_infinity && isfinite((*p0)[ii])==0)
4465
(*Mask)[dd]=(*p0)[ii];
4471
for(SizeT j=init+i*larg ; j<init+(i+1)*larg-2*lim ; ++j)// elements to replace
4473
SizeT initMask=j-lim*larg-lim; // left corner of mask
4476
for(SizeT k=0;k<=2*lim;++k) // lines of mask
4479
for(jj=initMask+k*larg ; jj<=(initMask+k*larg)+2*lim ; ++jj) // elements of mask
4481
if( (*p0)[jj]!=d_infinity && (*p0)[jj]!=-d_infinity && isfinite((*p0)[jj])==0)
4486
(*Mask)[kk]=(*p0)[jj];
4495
if(ctl_NaN==N_MaskElem)
4498
DLong* hhb = new DLong[ N_MaskElem-ctl_NaN];
4499
DLong* h1b = new DLong[ (N_MaskElem-ctl_NaN)/2];
4500
DLong* h2b= new DLong[(N_MaskElem-ctl_NaN+1)/2];
4501
DDoubleGDL*Maskb = new DDoubleGDL(N_MaskElem-ctl_NaN,BaseGDL::NOZERO);
4502
for( DLong t=0; t<N_MaskElem-ctl_NaN; ++t) hhb[t] = t;
4503
for( DLong ii=0; ii<N_MaskElem-ctl_NaN; ++ii)(*Maskb)[ii]=(*Mask)[ii];
4504
BaseGDL* besort=static_cast<BaseGDL*>(Maskb);
4505
MergeSortOpt<DLong>( besort, hhb, h1b, h2b,(N_MaskElem - ctl_NaN));
4506
if ((N_MaskElem - ctl_NaN) % 2 == 0 && e->KeywordSet( evenIx))
4507
(*tamp)[j]=((*Maskb)[hhb[ (N_MaskElem-ctl_NaN)/2]]+(*Maskb)[hhb
4510
else(*tamp)[j]=(*Maskb)[hhb[(N_MaskElem- ctl_NaN)/2]];
4518
BaseGDL* besort=static_cast<BaseGDL*>(Mask);
4519
MergeSortOpt<DLong>( besort, hh, h1, h2, N_MaskElem); // call the sort routine
4520
(*tamp)[j]=(*Mask)[hh[ (N_MaskElem)/2]]; // replace value by Mask median
4527
//--------------------------- END OF MEDIAN FILTER ALOGORITHMS -----------------------------------
4533
if ( e->GetParDefined( 0)->Type() == GDL_DOUBLE || p0->Type() == GDL_COMPLEXDBL ||e->KeywordSet( doubleIx) )
4535
else if (e->GetParDefined( 0)->Type() == GDL_BYTE)
4536
return tamp->Convert2(GDL_BYTE,BaseGDL::CONVERT);
4538
return tamp->Convert2(GDL_FLOAT,BaseGDL::CONVERT);
4544
BaseGDL* shift_fun( EnvT* e)
4546
SizeT nParam = e->NParam( 2);
4548
BaseGDL* p0 = e->GetParDefined( 0);
4550
SizeT nShift = nParam - 1;
4554
e->AssureLongScalarPar( 1, s1);
4556
// IncRef[Obj] done for GDL_PTR and GDL_OBJ
4557
return p0->CShift( s1);
4560
if( p0->Rank() != nShift)
4561
e->Throw( "Incorrect number of arguments.");
4563
DLong sIx[ MAXRANK];
4564
for( SizeT i=0; i< nShift; i++)
4565
e->AssureLongScalarPar( i+1, sIx[ i]);
4567
if( p0->Type() == GDL_OBJ)
4568
GDLInterpreter::IncRefObj( static_cast<DObjGDL*>(p0));
4569
else if( p0->Type() == GDL_PTR)
4570
GDLInterpreter::IncRef( static_cast<DPtrGDL*>(p0));
4572
return p0->CShift( sIx);
4575
BaseGDL* arg_present( EnvT* e)
4579
if( !e->GlobalPar( 0))
4580
return new DIntGDL( 0);
4582
EnvBaseT* caller = e->Caller();
4584
return new DIntGDL( 0);
4586
BaseGDL** pp0 = &e->GetPar( 0);
4588
int ix = caller->FindGlobalKW( pp0);
4590
return new DIntGDL( 0);
4592
return new DIntGDL( 1);
4595
BaseGDL* eof_fun( EnvT* e)
4600
e->AssureLongScalarPar( 0, lun);
4602
bool stdLun = check_lun( e, lun);
4604
return new DIntGDL( 0);
4606
// nicer error message (Disregard if socket)
4607
if ( fileUnits[ lun-1].SockNum() == -1) {
4608
if( !fileUnits[ lun-1].IsOpen())
4609
throw GDLIOException( e->CallingNode(), "File unit is not open: "+i2s( lun)+".");
4611
if( fileUnits[ lun-1].Eof())
4612
return new DIntGDL( 1);
4615
string *recvBuf = &fileUnits[ lun-1].RecvBuf();
4616
if (recvBuf->size() == 0)
4617
return new DIntGDL( 1);
4619
return new DIntGDL( 0);
4622
BaseGDL* convol( EnvT* e)
4624
SizeT nParam=e->NParam( 2);
4626
BaseGDL* p0 = e->GetNumericParDefined( 0);
4627
if( p0->Rank() == 0)
4628
e->Throw( "Expression must be an array in this context: "+
4629
e->GetParString(0));
4631
BaseGDL* p1 = e->GetNumericParDefined( 1);
4632
if( p1->Rank() == 0)
4633
e->Throw( "Expression must be an array in this context: "+
4634
e->GetParString(1));
4636
if( p0->N_Elements() <= p1->N_Elements())
4637
e->Throw( "Incompatible dimensions for Array and Kernel.");
4639
// rank 1 for kernel works always
4640
if( p1->Rank() != 1)
4642
SizeT rank = p0->Rank();
4643
if( rank != p1->Rank())
4644
e->Throw( "Incompatible dimensions for Array and Kernel.");
4646
for( SizeT r=0; r<rank; ++r)
4647
if( p0->Dim( r) <= p1->Dim( r))
4648
e->Throw( "Incompatible dimensions for Array and Kernel.");
4651
// convert kernel to array type
4652
auto_ptr<BaseGDL> p1Guard;
4653
if( p0->Type() == GDL_BYTE)
4655
if( p1->Type() != GDL_INT)
4657
p1 = p1->Convert2( GDL_INT, BaseGDL::COPY);
4661
else if( p0->Type() != p1->Type())
4663
p1 = p1->Convert2( p0->Type(), BaseGDL::COPY);
4668
auto_ptr<BaseGDL> scaleGuard;
4671
scale = e->GetParDefined( 2);
4672
if( scale->Rank() > 0)
4673
e->Throw( "Expression must be a scalar in this context: "+
4674
e->GetParString(2));
4676
// p1 here handles GDL_BYTE case also
4677
if( p1->Type() != scale->Type())
4679
scale = scale->Convert2( p1->Type(),BaseGDL::COPY);
4680
scaleGuard.reset( scale);
4685
scale = p1->New( dimension(), BaseGDL::ZERO);
4689
static int centerIx = e->KeywordIx( "CENTER");
4690
if( e->KeywordPresent( centerIx))
4693
e->AssureLongScalarKW( centerIx, c);
4697
// overrides EDGE_TRUNCATE
4698
static int edge_wrapIx = e->KeywordIx( "EDGE_WRAP");
4699
bool edge_wrap = e->KeywordSet( edge_wrapIx);
4700
static int edge_truncateIx = e->KeywordIx( "EDGE_TRUNCATE");
4701
bool edge_truncate = e->KeywordSet( edge_truncateIx);
4706
else if( edge_truncate)
4709
// p0, p1 and scale have same type
4710
// p1 has rank of 1 or same rank as p0 with each dimension smaller than p0
4711
// scale is a scalar
4712
return p0->Convol( p1, scale, center, edgeMode);
4715
BaseGDL* rebin_fun( EnvT* e)
4717
SizeT nParam = e->NParam( 2);
4719
BaseGDL* p0 = e->GetNumericParDefined( 0);
4721
SizeT rank = p0->Rank();
4724
e->Throw( "Expression must be an array in this context: "+
4725
e->GetParString(0));
4727
SizeT resDimInit[ MAXRANK];
4729
DLongGDL* p1 = e->GetParAs<DLongGDL>(1);
4730
if (p1->Rank() > 0 && nParam > 2)
4731
e->Throw("The new dimensions must either be specified as an array or as a set of scalars.");
4732
SizeT np = p1->Rank() == 0 ? nParam : p1->N_Elements() + 1;
4734
for( SizeT p=1; p<np; ++p)
4737
if (p1->Rank() == 0) e->AssureLongScalarPar( p, newDim);
4738
else newDim = (*p1)[p - 1];
4741
e->Throw( "Array dimensions must be greater than 0.");
4745
SizeT oldDim = p0->Dim( p-1);
4747
if( newDim > oldDim)
4749
if( (newDim % oldDim) != 0)
4750
e->Throw( "Result dimensions must be integer factor "
4751
"of original dimensions.");
4755
if( (oldDim % newDim) != 0)
4756
e->Throw( "Result dimensions must be integer factor "
4757
"of original dimensions.");
4761
resDimInit[ p-1] = newDim;
4764
dimension resDim( resDimInit, np-1);
4766
static int sampleIx = e->KeywordIx( "SAMPLE");
4767
bool sample = e->KeywordSet( sampleIx);
4769
return p0->Rebin( resDim, sample);
4772
BaseGDL* obj_class( EnvT* e)
4774
SizeT nParam = e->NParam();
4776
static int countIx = e->KeywordIx( "COUNT");
4777
static int superIx = e->KeywordIx( "SUPERCLASS");
4779
bool super = e->KeywordSet( superIx);
4781
bool count = e->KeywordPresent( countIx);
4783
e->AssureGlobalKW( countIx);
4787
BaseGDL* p0 = e->GetParDefined( 0);
4789
if( p0->Type() != GDL_STRING && p0->Type() != GDL_OBJ)
4790
e->Throw( "Argument must be a scalar object reference or string: "+
4791
e->GetParString(0));
4794
e->Throw( "Expression must be a scalar or 1 element "
4795
"array in this context: "+e->GetParString(0));
4797
DStructDesc* objDesc;
4799
if( p0->Type() == GDL_STRING)
4802
e->AssureScalarPar<DStringGDL>( 0, objName);
4803
objName = StrUpCase( objName);
4805
objDesc = FindInStructList( structList, objName);
4806
if( objDesc == NULL)
4809
e->SetKW( countIx, new DLongGDL( 0));
4810
return new DStringGDL( "");
4816
e->AssureScalarPar<DObjGDL>( 0, objRef);
4821
e->SetKW( countIx, new DLongGDL( 0));
4822
return new DStringGDL( "");
4825
DStructGDL* oStruct;
4827
oStruct = e->GetObjHeap( objRef);
4829
catch ( GDLInterpreter::HeapException)
4830
{ // non valid object
4832
e->SetKW( countIx, new DLongGDL( 0));
4833
return new DStringGDL( "");
4836
objDesc = oStruct->Desc(); // cannot be NULL
4842
e->SetKW( countIx, new DLongGDL( 1));
4843
return new DStringGDL( objDesc->Name());
4846
deque< string> pNames;
4847
objDesc->GetParentNames( pNames);
4849
SizeT nNames = pNames.size();
4852
e->SetKW( countIx, new DLongGDL( nNames));
4856
return new DStringGDL( "");
4859
DStringGDL* res = new DStringGDL( dimension( nNames),
4862
for( SizeT i=0; i<nNames; ++i)
4864
(*res)[i] = pNames[i];
4871
e->Throw( "Conflicting keywords.");
4873
SizeT nObj = structList.size();
4875
DStringGDL* res = new DStringGDL( dimension( nObj),
4878
for( SizeT i=0; i<nObj; ++i)
4880
(*res)[i] = structList[i]->Name();
4886
BaseGDL* obj_isa( EnvT* e)
4888
SizeT nParam = e->NParam( 2);
4890
BaseGDL* p0 = e->GetPar( 0);
4891
if( p0 == NULL || p0->Type() != GDL_OBJ)
4892
e->Throw( "Object reference type required in this context: "+
4893
e->GetParString(0));
4896
e->AssureScalarPar<DStringGDL>( 1, className);
4897
className = StrUpCase( className);
4899
DObjGDL* pObj = static_cast<DObjGDL*>( p0);
4901
DByteGDL* res = new DByteGDL( pObj->Dim()); // zero
4903
GDLInterpreter* interpreter = e->Interpreter();
4905
SizeT nElem = pObj->N_Elements();
4906
for( SizeT i=0; i<nElem; ++i)
4908
if( interpreter->ObjValid( (*pObj)[ i]))
4910
DStructGDL* oStruct = e->GetObjHeap( (*pObj)[i]);
4911
if( oStruct->Desc()->IsParent( className))
4919
BaseGDL* n_tags( EnvT* e)
4923
BaseGDL* p0 = e->GetPar( 0);
4925
return new DLongGDL( 0);
4927
if( p0->Type() != GDL_STRUCT)
4928
return new DLongGDL( 0);
4930
DStructGDL* s = static_cast<DStructGDL*>( p0);
4932
//static int lengthIx = e->KeywordIx( "DATA_LENGTH");
4933
//bool length = e->KeywordSet( lengthIx);
4935
// we don't know now how to distinghuis the 2 following cases
4936
if(e->KeywordSet("DATA_LENGTH"))
4937
return new DLongGDL( s->Sizeof());
4939
if(e->KeywordSet("LENGTH"))
4940
return new DLongGDL( s->Sizeof());
4942
return new DLongGDL( s->Desc()->NTags());
4945
BaseGDL* bytscl( EnvT* e)
4947
SizeT nParam = e->NParam( 1);
4949
BaseGDL* p0=e->GetNumericParDefined( 0);
4951
static int minIx = e->KeywordIx( "MIN");
4952
static int maxIx = e->KeywordIx( "MAX");
4953
static int topIx = e->KeywordIx( "TOP");
4954
bool omitNaN = e->KeywordPresent( 3);
4957
if( e->GetKW( topIx) != NULL)
4958
e->AssureLongScalarKW( topIx, topL);
4959
DByte top = static_cast<DByte>(topL);
4960
DDouble dTop = static_cast<DDouble>(top);
4963
bool minSet = false;
4964
// SA: handling 3 parameters to emulate undocumented IDL behaviour
4965
// of translating second and third arguments to MIN and MAX, respectively
4966
// (parameters have precedence over keywords)
4969
e->AssureDoubleScalarPar(1, min);
4972
else if (e->GetKW(minIx) != NULL)
4974
e->AssureDoubleScalarKW(minIx, min);
4979
bool maxSet = false;
4982
e->AssureDoubleScalarPar(2, max);
4985
else if (e->GetKW(maxIx) != NULL)
4987
e->AssureDoubleScalarKW(maxIx, max);
4992
static_cast<DDoubleGDL*>(p0->Convert2( GDL_DOUBLE, BaseGDL::COPY));
4995
if( !maxSet || !minSet)
4996
dRes->MinMax( &minEl, &maxEl, NULL, NULL, omitNaN);
4998
min = (*dRes)[ minEl];
5000
max = (*dRes)[ maxEl];
5002
SizeT nEl = dRes->N_Elements();
5003
for( SizeT i=0; i<nEl; ++i)
5005
DDouble& d = (*dRes)[ i];
5006
if( d <= min) (*dRes)[ i] = 0;
5007
else if( d >= max) (*dRes)[ i] = dTop;
5010
// SA: floor is used for integer types to simulate manipulation on input data types
5011
if (IntType(p0->Type())) (*dRes)[ i] = floor(((dTop + 1.)*(d - min) - 1.) / (max-min));
5012
// SA (?): here floor is used (instead of round) to simulate IDL behaviour
5013
else (*dRes)[ i] = floor((d - min) / (max-min) * (dTop + .9999));
5017
return dRes->Convert2( GDL_BYTE);
5020
BaseGDL* strtok_fun( EnvT* e)
5022
SizeT nParam=e->NParam( 1);
5025
e->AssureStringScalarPar( 0, stringIn);
5027
DString pattern = " \t";
5029
e->AssureStringScalarPar( 1, pattern);
5032
static int extractIx = e->KeywordIx( "EXTRACT");
5033
bool extract = e->KeywordSet( extractIx);
5035
static int lengthIx = e->KeywordIx( "LENGTH");
5036
bool lengthPresent = e->KeywordPresent( lengthIx);
5038
if( extract && lengthPresent)
5039
e->Throw( "Conflicting keywords.");
5041
static int pre0Ix = e->KeywordIx( "PRESERVE_NULL");
5042
bool pre0 = e->KeywordSet( pre0Ix);
5044
static int regexIx = e->KeywordIx( "REGEX");
5045
bool regex = e->KeywordPresent( regexIx);
5046
char err_msg[MAX_REGEXPERR_LENGTH];
5049
deque<long> tokenStart;
5050
deque<long> tokenLen;
5052
int strLen = stringIn.length();
5054
DString escape = "";
5055
e->AssureStringScalarKWIfPresent( "ESCAPE", escape);
5056
deque<long> escList;
5058
while(pos != string::npos)
5060
pos = stringIn.find_first_of( escape, pos);
5061
if( pos != string::npos)
5063
escList.push_back( pos+1); // remember escaped char
5064
pos += 2; // skip escaped char
5067
deque<long>::iterator escBeg = escList.begin();
5068
deque<long>::iterator escEnd = escList.end();
5075
// If regex then compile regex
5077
if (pattern == " \t") pattern = " "; // regcomp doesn't like "\t" JMG
5078
int compRes = regcomp( ®exp, pattern.c_str(), REG_EXTENDED);
5080
regerror(compRes, ®exp, err_msg, MAX_REGEXPERR_LENGTH);
5081
e->Throw( "Error processing regular expression: "+
5082
pattern+"\n "+string(err_msg)+".");
5088
regmatch_t pmatch[1];
5090
int matchres = regexec( ®exp, stringIn.c_str()+nextE, 1, pmatch, 0);
5091
tokE = matchres? -1:pmatch[0].rm_so;
5093
tokE = stringIn.find_first_of( pattern, nextE);
5096
if( tokE == string::npos)
5098
actLen = strLen - tokB;
5099
if( actLen > 0 || pre0)
5101
tokenStart.push_back( tokB);
5102
tokenLen.push_back( actLen);
5107
if( find( escBeg, escEnd, tokE) == escEnd)
5109
if (regex) actLen = tokE; else actLen = tokE - tokB;
5110
if( actLen > 0 || pre0)
5112
tokenStart.push_back( tokB);
5113
tokenLen.push_back( actLen);
5115
if (regex) tokB += pmatch[0].rm_eo; else tokB = tokE + 1;
5117
if (regex) nextE += pmatch[0].rm_eo; else nextE = tokE + 1;
5120
if (regex) regfree( ®exp);
5122
SizeT nTok = tokenStart.size();
5128
e->AssureGlobalKW( lengthIx);
5132
dimension dim(nTok);
5133
DLongGDL* len = new DLongGDL(dim);
5134
for(int i=0; i < nTok; i++)
5135
(*len)[i] = tokenLen[i];
5137
e->SetKW( lengthIx, len);
5141
e->SetKW( lengthIx, new DLongGDL( 0));
5145
if( nTok == 0) return new DLongGDL( 0);
5147
dimension dim(nTok);
5148
DLongGDL* d = new DLongGDL(dim);
5149
for(int i=0; i < nTok; i++)
5150
(*d)[i] = tokenStart[i];
5155
if( nTok == 0) return new DStringGDL( "");
5157
dimension dim(nTok);
5158
DStringGDL *d = new DStringGDL(dim);
5159
for(int i=0; i < nTok; i++)
5161
(*d)[i] = stringIn.substr(tokenStart[i], tokenLen[i]);
5164
DString& act = (*d)[i];
5165
long escPos = act.find_first_of( escape, 0);
5166
while( escPos != string::npos)
5168
act = act.substr( 0, escPos)+act.substr( escPos+1);
5169
escPos = act.find_first_of( escape, escPos+1);
5175
BaseGDL* getenv_fun( EnvT* e)
5177
SizeT nParam=e->NParam();
5179
static int environmentIx = e->KeywordIx( "ENVIRONMENT" );
5180
bool environment = e->KeywordSet( environmentIx );
5188
e->Throw( "Incorrect number of arguments.");
5190
// determine number of environment entries
5191
for(nEnv = 0; environ[nEnv] != NULL ; ++nEnv);
5193
dimension dim( nEnv );
5194
env = new DStringGDL(dim);
5196
// copy stuff into local string array
5197
for(SizeT i=0; i < nEnv ; ++i)
5198
(*env)[i] = environ[i];
5203
e->Throw( "Incorrect number of arguments.");
5205
DStringGDL* name = e->GetParAs<DStringGDL>(0);
5206
nEnv = name->N_Elements();
5208
env = new DStringGDL( name->Dim());
5210
// copy the stuff into local string only if param found
5212
for(SizeT i=0; i < nEnv ; ++i)
5214
// handle special environment variables
5215
// GDL_TMPDIR, IDL_TMPDIR
5216
if( (*name)[i] == "GDL_TMPDIR" || (*name)[i] == "IDL_TMPDIR")
5218
resPtr = getenv((*name)[i].c_str());
5223
(*env)[i] = SysVar::Dir();
5225
AppendIfNeeded( (*env)[i], "/");
5227
else // normal environment variables
5228
if( (resPtr = getenv((*name)[i].c_str())) )
5236
BaseGDL* tag_names_fun( EnvT* e)
5238
SizeT nParam=e->NParam();
5239
DStructGDL* struc= e->GetParAs<DStructGDL>(0);
5241
static int structureNameIx = e->KeywordIx( "STRUCTURE_NAME" );
5242
bool structureName = e->KeywordSet( structureNameIx );
5244
DStringGDL* tagNames;
5248
if ((*struc).Desc()->Name() != "$truct")
5249
tagNames = new DStringGDL((*struc).Desc()->Name());
5251
tagNames = new DStringGDL("");
5254
SizeT nTags = (*struc).Desc()->NTags();
5256
tagNames = new DStringGDL(dimension(nTags));
5257
for(int i=0; i < nTags; ++i)
5258
(*tagNames)[i] = (*struc).Desc()->TagName(i);
5264
// AC 12-Oc-2011: better version for: len=len, /Extract and /Sub
5265
// but it is still not perfect
5267
BaseGDL* stregex_fun( EnvT* e)
5269
SizeT nParam=e->NParam( 2);
5271
DStringGDL* stringExpr= e->GetParAs<DStringGDL>(0);
5272
dimension dim = stringExpr->Dim();
5275
e->AssureStringScalarPar(1, pattern);
5276
if (pattern.size() <= 0)
5278
e->Throw( "Error processing regular expression: "+pattern+
5279
"\n empty (sub)expression");
5282
static int booleanIx = e->KeywordIx( "BOOLEAN" );
5283
bool booleanKW = e->KeywordSet( booleanIx );
5285
static int extractIx = e->KeywordIx( "EXTRACT" );
5286
bool extractKW = e->KeywordSet( extractIx );
5288
static int foldCaseIx = e->KeywordIx( "FOLD_CASE" );
5289
bool foldCaseKW = e->KeywordSet( foldCaseIx );
5291
//XXXpch: this is wrong, should check arg_present
5292
static int lengthIx = e->KeywordIx( "LENGTH" );
5293
bool lengthKW = e->KeywordPresent( lengthIx );
5295
static int subexprIx = e->KeywordIx( "SUBEXPR" );
5296
bool subexprKW = e->KeywordSet( subexprIx );
5298
if( booleanKW && (subexprKW || extractKW || lengthKW))
5299
e->Throw( "Conflicting keywords.");
5301
char err_msg[MAX_REGEXPERR_LENGTH];
5303
// set the compile flags
5304
int cflags = REG_EXTENDED;
5306
cflags |= REG_ICASE;
5308
cflags |= REG_NOSUB;
5310
// compile the regular expression
5312
int compRes = regcomp( ®exp, pattern.c_str(), cflags);
5313
SizeT nSubExpr = regexp.re_nsub + 1;
5315
// cout << regexp.re_nsub << endl;
5318
regerror(compRes, ®exp, err_msg, MAX_REGEXPERR_LENGTH);
5319
e->Throw( "Error processing regular expression: "+
5320
pattern+"\n "+string(err_msg)+".");
5326
result = new DByteGDL(dim);
5327
else if( extractKW && !subexprKW)
5329
// cout << "my pb ! ? dim= " << dim << endl;
5330
result = new DStringGDL(dim);
5334
// cout << "my pb 2 ? dim= " << dim << endl;
5335
dimension subExprDim = dim;
5336
subExprDim >> nSubExpr; // m_schellens: commented in, needed
5338
result = new DStringGDL(subExprDim);
5340
result = new DLongGDL(subExprDim);
5343
result = new DLongGDL(dim);
5345
DLongGDL* len = NULL;
5347
e->AssureGlobalKW( lengthIx);
5350
dimension subExprDim = dim;
5351
subExprDim >> nSubExpr; // m_schellens: commented in, needed
5352
len = new DLongGDL(subExprDim);
5356
len = new DLongGDL(dim);
5358
for( SizeT i=0; i<len->N_Elements(); ++i)
5363
if( subexprKW) nmatch = nSubExpr;
5365
regmatch_t* pmatch = new regmatch_t[nSubExpr];
5366
ArrayGuard<regmatch_t> pmatchGuard( pmatch);
5368
// cout << "dim " << dim.NDimElements() << endl;
5369
for( SizeT s=0; s<dim.NDimElements(); ++s)
5373
for( SizeT sE=0; sE<nSubExpr; ++sE)
5374
pmatch[sE].rm_so = -1;
5376
// now match towards the string
5377
int matchres = regexec( ®exp, (*stringExpr)[s].c_str(), nmatch, pmatch, eflags);
5380
if ( extractKW && subexprKW) {
5382
// Loop through subexpressions & fill output array
5383
for( SizeT i = 0; i<nSubExpr; ++i) {
5384
if (pmatch[i].rm_so != -1)
5385
(*static_cast<DStringGDL*>(result))[i+s*nSubExpr] =
5386
(*stringExpr)[s].substr( pmatch[i].rm_so, pmatch[i].rm_eo - pmatch[i].rm_so);
5387
// (*stringExpr)[i+s*nSubExpr].substr( pmatch[i].rm_so, pmatch[i].rm_eo - pmatch[i].rm_so);
5389
(*len)[i+s*nSubExpr] = pmatch[i].rm_so != -1 ? pmatch[i].rm_eo - pmatch[i].rm_so : -1;
5390
// (*len)[i+s*nSubExpr] = pmatch[i].rm_eo - pmatch[i].rm_so;
5393
else if ( subexprKW)
5395
// cout << "je ne comprends pas v2: "<< nSubExpr << endl;
5397
// Loop through subexpressions & fill output array
5398
for( SizeT i = 0; i<nSubExpr; ++i) {
5399
(* static_cast<DLongGDL*>(result))[i+s*nSubExpr] = pmatch[i].rm_so;
5401
(*len)[i+s*nSubExpr] = pmatch[i].rm_so != -1 ? pmatch[i].rm_eo - pmatch[i].rm_so : -1;
5407
(* static_cast<DByteGDL*>(result))[s] = (matchres == 0);
5408
else if ( extractKW) // !subExprKW
5411
(* static_cast<DStringGDL*>(result))[s] =
5412
(*stringExpr)[s].substr( pmatch[0].rm_so,
5413
pmatch[0].rm_eo - pmatch[0].rm_so);
5416
(*static_cast<DLongGDL*>(result))[s] = matchres ? -1 : pmatch[0].rm_so;
5419
if( lengthKW && !subexprKW)
5420
(*len)[s] = pmatch[0].rm_eo - pmatch[0].rm_so;
5426
e->SetKW( lengthIx, len);
5431
BaseGDL* routine_info( EnvT* e)
5433
SizeT nParam=e->NParam();
5435
static int functionsIx = e->KeywordIx( "FUNCTIONS" );
5436
bool functionsKW = e->KeywordSet( functionsIx );
5437
static int systemIx = e->KeywordIx( "SYSTEM" );
5438
bool systemKW = e->KeywordSet( systemIx );
5439
static int disabledIx = e->KeywordIx( "DISABLED" );
5440
bool disabledKW = e->KeywordSet( disabledIx );
5441
static int parametersIx = e->KeywordIx( "PARAMETERS" );
5442
bool parametersKW = e->KeywordSet( parametersIx );
5447
if (systemKW || disabledKW) e->Throw("Conflicting keywords.");
5448
if (nParam != 1) e->Throw("Incorrect number of arguments.");
5450
// getting the routine name from the first parameter
5452
e->AssureScalarPar<DStringGDL>(0, name);
5453
name = StrUpCase(name);
5455
DSubUD* routine = functionsKW
5456
? static_cast<DSubUD*>(funList[GDLInterpreter::GetFunIx(name)])
5457
: static_cast<DSubUD*>(proList[GDLInterpreter::GetProIx(name)]);
5458
SizeT np = routine->NPar(), nk = routine->NKey();
5460
// creating the output anonymous structure
5461
DStructDesc* stru_desc = new DStructDesc("$truct");
5463
stru_desc->AddTag("NUM_ARGS", &aLong);
5464
stru_desc->AddTag("NUM_KW_ARGS", &aLong);
5467
SpDString aStringArr(dimension((int)np));
5468
stru_desc->AddTag("ARGS", &aStringArr);
5472
SpDString aStringArr(dimension((int)nk));
5473
stru_desc->AddTag("KW_ARGS", &aStringArr);
5475
DStructGDL* stru = new DStructGDL(stru_desc, dimension());
5477
// filling the structure with information about the routine
5478
stru->InitTag("NUM_ARGS", DLongGDL(np));
5479
stru->InitTag("NUM_KW_ARGS", DLongGDL(nk));
5482
DStringGDL *pnames = new DStringGDL(dimension(np));
5483
for (SizeT p = 0; p < np; ++p) (*pnames)[p] = routine->GetVarName(nk + p);
5484
stru->InitTag("ARGS", *pnames);
5489
DStringGDL *knames = new DStringGDL(dimension(nk));
5490
for (SizeT k = 0; k < nk; ++k) (*knames)[k] = routine->GetKWName(k);
5491
stru->InitTag("KW_ARGS", *knames);
5499
// GDL does not have disabled routines
5500
if( disabledKW) return new DStringGDL("");
5502
// if( functionsKW || systemKW || nParam == 0)
5504
deque<DString> subList;
5510
SizeT n = libFunList.size();
5511
if( n == 0) return new DStringGDL("");
5513
DStringGDL* res = new DStringGDL( dimension( n), BaseGDL::NOZERO);
5514
for( SizeT i = 0; i<n; ++i)
5515
(*res)[i] = libFunList[ i]->ObjectName();
5521
SizeT n = funList.size();
5522
if( n == 0) return new DStringGDL("");
5525
for( SizeT i = 0; i<n; ++i)
5526
subList.push_back( funList[ i]->ObjectName());
5533
SizeT n = libProList.size();
5534
if( n == 0) return new DStringGDL("");
5536
DStringGDL* res = new DStringGDL( dimension( n), BaseGDL::NOZERO);
5537
for( SizeT i = 0; i<n; ++i)
5538
(*res)[i] = libProList[ i]->ObjectName();
5544
SizeT n = proList.size();
5545
if( n == 0) return new DStringGDL("");
5548
for( SizeT i = 0; i<n; ++i)
5549
subList.push_back( proList[ i]->ObjectName());
5553
sort( subList.begin(), subList.end());
5554
SizeT nS = subList.size();
5556
DStringGDL* res = new DStringGDL( dimension( nS), BaseGDL::NOZERO);
5557
for( SizeT s=0; s<nS; ++s)
5558
(*res)[ s] = subList[ s];
5564
BaseGDL* get_kbrd( EnvT* e)
5566
#if defined(HAVE_LIBREADLINE)
5567
#include <readline/readline.h>
5568
rl_prep_terminal (0);
5571
SizeT nParam=e->NParam();
5578
e->AssureLongScalarPar( 0, waitArg);
5585
// https://sourceforge.net/forum/forum.php?thread_id=3292183&forum_id=338691
5586
// DONE: Implement proper SCALAR parameter handling (doWait variable)
5587
// which is/was not blocking in the original program.
5588
// note: multi-byte input is not supported here.
5590
char c='\0'; //initialize is never a bad idea...
5592
int fd=fileno(stdin);
5594
struct termios orig, get;
5596
// Get terminal setup to revert to it at end.
5598
(void)tcgetattr(fd, &orig);
5599
// New terminal setup, non-canonical.
5604
// will wait for a character
5608
(void)tcsetattr(fd, TCSANOW, &get);
5614
// will not wait, but return EOF or next character in terminal buffer if present
5618
(void)tcsetattr(fd, TCSANOW, &get);
5620
//the trick is *not to use C++ functions here. cin.get would wait.*
5621
c=std::fgetc(stdin);
5622
//and to convert EOF to null (otherwise GDL may exit if not compiled with
5627
// Restore original terminal settings.
5629
(void)tcsetattr(fd, TCSANOW, &orig);
5631
#if defined(HAVE_LIBREADLINE)
5632
rl_deprep_terminal ();
5635
DStringGDL* res = new DStringGDL( DString( i2s( c)));
5642
BaseGDL* temporary( EnvT* e)
5644
SizeT nParam=e->NParam(1);
5646
BaseGDL** p0 = &e->GetParDefined( 0);
5650
*p0 = NULL; // make parameter undefined
5654
BaseGDL* memory( EnvT* e)
5656
SizeT nParam=e->NParam( 0);
5659
bool kw_l64 = e->KeywordSet(e->KeywordIx("L64"));
5660
// TODO: IDL-doc mentions about automatically switching to L64 if needed
5662
if (e->KeywordSet(e->KeywordIx("STRUCTURE")))
5664
// returning structure
5667
ret = new DStructGDL("IDL_MEMORY64");
5668
DStructGDL* retStru = static_cast<DStructGDL*>(ret);
5669
(retStru->GetTag(retStru->Desc()->TagIndex("CURRENT")))->InitFrom( DLong64GDL(MemStats::GetCurrent()));
5670
(retStru->GetTag(retStru->Desc()->TagIndex("NUM_ALLOC")))->InitFrom( DLong64GDL(MemStats::GetNumAlloc()));
5671
(retStru->GetTag(retStru->Desc()->TagIndex("NUM_FREE")))->InitFrom( DLong64GDL(MemStats::GetNumFree()));
5672
(retStru->GetTag(retStru->Desc()->TagIndex("HIGHWATER")))->InitFrom( DLong64GDL(MemStats::GetHighWater()));
5676
ret = new DStructGDL("IDL_MEMORY");
5677
DStructGDL* retStru = static_cast<DStructGDL*>(ret);
5678
(retStru->GetTag(retStru->Desc()->TagIndex("CURRENT")))->InitFrom( DLongGDL(MemStats::GetCurrent()));
5679
(retStru->GetTag(retStru->Desc()->TagIndex("NUM_ALLOC")))->InitFrom( DLongGDL(MemStats::GetNumAlloc()));
5680
(retStru->GetTag(retStru->Desc()->TagIndex("NUM_FREE")))->InitFrom( DLongGDL(MemStats::GetNumFree()));
5681
(retStru->GetTag(retStru->Desc()->TagIndex("HIGHWATER")))->InitFrom( DLongGDL(MemStats::GetHighWater()));
5686
bool kw_current = e->KeywordSet(e->KeywordIx("CURRENT"));
5687
bool kw_num_alloc = e->KeywordSet(e->KeywordIx("NUM_ALLOC"));
5688
bool kw_num_free = e->KeywordSet(e->KeywordIx("NUM_FREE"));
5689
bool kw_highwater = e->KeywordSet(e->KeywordIx("HIGHWATER"));
5691
// Following the IDL documentation: mutually exclusive keywords
5692
// IDL behaves different, incl. segfaults with selected kw combinations
5693
if (kw_current + kw_num_alloc + kw_num_free + kw_highwater > 1)
5694
e->Throw("CURRENT, NUM_ALLOC, NUM_FREE & HIGHWATER keywords"
5695
" are mutually exclusive");
5699
if (kw_l64) ret = new DLong64GDL(MemStats::GetCurrent());
5700
else ret = new DLongGDL(MemStats::GetCurrent());
5702
else if (kw_num_alloc)
5704
if (kw_l64) ret = new DLong64GDL(MemStats::GetNumAlloc());
5705
else ret = new DLongGDL(MemStats::GetNumAlloc());
5707
else if (kw_num_free)
5709
if (kw_l64) ret = new DLong64GDL(MemStats::GetNumFree());
5710
else ret = new DLongGDL(MemStats::GetNumFree());
5712
else if (kw_highwater)
5714
if (kw_l64) ret = new DLong64GDL(MemStats::GetHighWater());
5715
else ret = new DLongGDL(MemStats::GetHighWater());
5719
// returning 4-element array
5722
ret = new DLong64GDL(dimension(4));
5723
(*static_cast<DLong64GDL*>(ret))[0] = MemStats::GetCurrent();
5724
(*static_cast<DLong64GDL*>(ret))[1] = MemStats::GetNumAlloc();
5725
(*static_cast<DLong64GDL*>(ret))[2] = MemStats::GetNumFree();
5726
(*static_cast<DLong64GDL*>(ret))[3] = MemStats::GetHighWater();
5730
ret = new DLongGDL(dimension(4));
5731
(*static_cast<DLongGDL*>(ret))[0] = MemStats::GetCurrent();
5732
(*static_cast<DLongGDL*>(ret))[1] = MemStats::GetNumAlloc();
5733
(*static_cast<DLongGDL*>(ret))[2] = MemStats::GetNumFree();
5734
(*static_cast<DLongGDL*>(ret))[3] = MemStats::GetHighWater();
5742
inline DByte StrCmp( const string& s1, const string& s2, DLong n)
5744
if( n <= 0) return 1;
5745
if( s1.substr(0,n) == s2.substr(0,n)) return 1;
5748
inline DByte StrCmp( const string& s1, const string& s2)
5750
if( s1 == s2) return 1;
5753
inline DByte StrCmpFold( const string& s1, const string& s2, DLong n)
5755
if( n <= 0) return 1;
5756
if( StrUpCase( s1.substr(0,n)) == StrUpCase(s2.substr(0,n))) return 1;
5759
inline DByte StrCmpFold( const string& s1, const string& s2)
5761
if( StrUpCase( s1) == StrUpCase(s2)) return 1;
5765
BaseGDL* strcmp_fun( EnvT* e)
5767
SizeT nParam=e->NParam(2);
5769
DStringGDL* s0 = static_cast<DStringGDL*>( e->GetParAs< DStringGDL>( 0));
5770
DStringGDL* s1 = static_cast<DStringGDL*>( e->GetParAs< DStringGDL>( 1));
5772
DLongGDL* l2 = NULL;
5775
l2 = static_cast<DLongGDL*>( e->GetParAs< DLongGDL>( 2));
5778
static int foldIx = e->KeywordIx( "FOLD_CASE");
5779
bool fold = e->KeywordSet( foldIx );
5781
if( s0->Scalar() && s1->Scalar())
5786
return new DByteGDL( StrCmpFold( (*s0)[0], (*s1)[0]));
5788
return new DByteGDL( StrCmp( (*s0)[0], (*s1)[0]));
5792
DByteGDL* res = new DByteGDL( l2->Dim(), BaseGDL::NOZERO);
5793
SizeT nEl = l2->N_Elements();
5795
for( SizeT i=0; i<nEl; ++i)
5796
(*res)[i] = StrCmpFold( (*s0)[0], (*s1)[0], (*l2)[i]);
5798
for( SizeT i=0; i<nEl; ++i)
5799
(*res)[i] = StrCmp( (*s0)[0], (*s1)[0], (*l2)[i]);
5803
else // at least one array
5809
DByteGDL* res = new DByteGDL( s1->Dim(), BaseGDL::NOZERO);
5810
SizeT nEl = s1->N_Elements();
5812
for( SizeT i=0; i<nEl; ++i)
5813
(*res)[i] = StrCmpFold( (*s0)[0], (*s1)[i]);
5815
for( SizeT i=0; i<nEl; ++i)
5816
(*res)[i] = StrCmp( (*s0)[0], (*s1)[i]);
5819
else if( s1->Scalar())
5821
DByteGDL* res = new DByteGDL( s0->Dim(), BaseGDL::NOZERO);
5822
SizeT nEl = s0->N_Elements();
5824
for( SizeT i=0; i<nEl; ++i)
5825
(*res)[i] = StrCmpFold( (*s0)[i], (*s1)[0]);
5827
for( SizeT i=0; i<nEl; ++i)
5828
(*res)[i] = StrCmp( (*s0)[i], (*s1)[0]);
5835
if( s0->N_Elements() <= s1->N_Elements())
5837
res = new DByteGDL( s0->Dim(), BaseGDL::NOZERO);
5838
nEl = s0->N_Elements();
5842
res = new DByteGDL( s1->Dim(), BaseGDL::NOZERO);
5843
nEl = s1->N_Elements();
5846
for( SizeT i=0; i<nEl; ++i)
5847
(*res)[i] = StrCmpFold( (*s0)[i], (*s1)[i]);
5849
for( SizeT i=0; i<nEl; ++i)
5850
(*res)[i] = StrCmp( (*s0)[i], (*s1)[i]);
5858
bool l2Scalar = l2->Scalar();
5861
if( l2Scalar || s1->N_Elements() <= l2->N_Elements())
5863
res = new DByteGDL( s1->Dim(), BaseGDL::NOZERO);
5864
nEl = s1->N_Elements();
5868
res = new DByteGDL( l2->Dim(), BaseGDL::NOZERO);
5869
nEl = l2->N_Elements();
5872
for( SizeT i=0; i<nEl; ++i)
5873
(*res)[i] = StrCmpFold( (*s0)[0], (*s1)[i], (*l2)[l2Scalar?0:i]);
5875
for( SizeT i=0; i<nEl; ++i)
5876
(*res)[i] = StrCmp( (*s0)[0], (*s1)[i], (*l2)[l2Scalar?0:i]);
5879
else if( s1->Scalar())
5881
if( l2Scalar || s0->N_Elements() <= l2->N_Elements())
5883
res = new DByteGDL( s0->Dim(), BaseGDL::NOZERO);
5884
nEl = s0->N_Elements();
5888
res = new DByteGDL( l2->Dim(), BaseGDL::NOZERO);
5889
nEl = l2->N_Elements();
5892
for( SizeT i=0; i<nEl; ++i)
5893
(*res)[i] = StrCmpFold( (*s0)[i], (*s1)[0], (*l2)[l2Scalar?0:i]);
5895
for( SizeT i=0; i<nEl; ++i)
5896
(*res)[i] = StrCmp( (*s0)[i], (*s1)[0], (*l2)[l2Scalar?0:i]);
5899
else // s1 and s2 are arrays
5902
if( s0->N_Elements() <= s1->N_Elements())
5904
res = new DByteGDL( s0->Dim(), BaseGDL::NOZERO);
5905
nEl = s0->N_Elements();
5909
res = new DByteGDL( s1->Dim(), BaseGDL::NOZERO);
5910
nEl = s1->N_Elements();
5914
if( s0->N_Elements() <= s1->N_Elements())
5915
if( s0->N_Elements() <= l2->N_Elements())
5917
res = new DByteGDL( s0->Dim(), BaseGDL::NOZERO);
5918
nEl = s0->N_Elements();
5922
res = new DByteGDL( l2->Dim(), BaseGDL::NOZERO);
5923
nEl = l2->N_Elements();
5926
if( s1->N_Elements() <= l2->N_Elements())
5928
res = new DByteGDL( s1->Dim(), BaseGDL::NOZERO);
5929
nEl = s1->N_Elements();
5933
res = new DByteGDL( l2->Dim(), BaseGDL::NOZERO);
5934
nEl = l2->N_Elements();
5938
for( SizeT i=0; i<nEl; ++i)
5939
(*res)[i] = StrCmpFold( (*s0)[i], (*s1)[i], (*l2)[l2Scalar?0:i]);
5941
for( SizeT i=0; i<nEl; ++i)
5942
(*res)[i] = StrCmp( (*s0)[i], (*s1)[i], (*l2)[l2Scalar?0:i]);
5949
string TagName( EnvT* e, const string& name)
5951
string n = StrUpCase( name);
5952
SizeT len = n.size();
5953
if( n[0] != '_' && n[0] != '!' && (n[0] < 'A' || n[0] > 'Z'))
5954
e->Throw( "Illegal tag name: "+name+".");
5955
for( SizeT i=1; i<len; ++i)
5960
if( n[i] != '_' && n[i] != '$' && //n[0] != '!' &&
5961
(n[i] < 'A' || n[i] > 'Z') &&
5962
(n[i] < '0' || n[i] > '9'))
5963
e->Throw( "Illegal tag name: "+name+".");
5968
BaseGDL* create_struct( EnvT* e)
5970
static int nameIx = e->KeywordIx( "NAME" );
5971
DString name = "$truct";
5972
if( e->KeywordPresent( nameIx)) {
5973
// Check if name exists, if not then treat as unnamed
5974
if (e->GetKW( nameIx) != NULL)
5975
e->AssureStringScalarKW( nameIx, name);
5978
if( name != "$truct") // named struct
5980
name = StrUpCase( name);
5982
SizeT nParam=e->NParam();
5987
e->Interpreter()->GetStruct( name, e->CallingNode());
5990
return new DStructGDL( desc, dim);
5993
DStructDesc* nStructDesc;
5994
auto_ptr<DStructDesc> nStructDescGuard;
5996
DStructDesc* oStructDesc=
5997
FindInStructList( structList, name);
5999
if( oStructDesc == NULL || oStructDesc->NTags() > 0)
6001
// not defined at all yet (-> define now)
6002
// or completely defined (-> define now and check equality)
6003
nStructDesc= new DStructDesc( name);
6006
nStructDescGuard.reset( nStructDesc);
6011
// not completely defined (only name in list)
6012
nStructDesc= oStructDesc;
6015
// the instance variable
6016
// dimension dim( 1);
6017
// DStructGDL* instance = new DStructGDL( nStructDesc, dim);
6018
DStructGDL* instance = new DStructGDL( nStructDesc);
6019
auto_ptr<DStructGDL> instance_guard(instance);
6021
for( SizeT p=0; p<nParam; ++p)
6023
BaseGDL* par = e->GetParDefined( p);
6024
DStructGDL* parStruct = dynamic_cast<DStructGDL*>( par);
6025
if( parStruct != NULL)
6028
if( !parStruct->Scalar())
6029
e->Throw("Expression must be a scalar in this context: "+
6030
e->GetParString( p));
6032
DStructDesc* desc = parStruct->Desc();
6033
for( SizeT t=0; t< desc->NTags(); ++t)
6035
instance->NewTag( desc->TagName( t),
6036
parStruct->GetTag( t)->Dup());
6041
// add tag value pair
6042
DStringGDL* tagNames = e->GetParAs<DStringGDL>( p);
6043
SizeT nTags = tagNames->N_Elements();
6045
SizeT tagStart = p+1;
6046
SizeT tagEnd = p+nTags;
6047
if( tagEnd >= nParam)
6048
e->Throw( "Incorrect number of arguments.");
6052
BaseGDL* value = e->GetParDefined( p);
6055
instance->NewTag( TagName( e, (*tagNames)[ p-tagStart]),
6062
if( oStructDesc != NULL)
6064
if( oStructDesc != nStructDesc)
6066
oStructDesc->AssureIdentical(nStructDesc);
6067
instance->DStructGDL::SetDesc(oStructDesc);
6068
//delete nStructDesc; // auto_ptr
6073
// release from guard (if not NULL)
6074
nStructDescGuard.release();
6075
// insert into struct list
6076
structList.push_back(nStructDesc);
6079
instance_guard.release();
6085
// Handle case of single structure parameter
6087
nParam = e->NParam(1);
6088
BaseGDL* par = e->GetParDefined( 0);
6089
DStructGDL* parStruct = dynamic_cast<DStructGDL*>( par);
6090
if (nParam != 1 || parStruct == NULL)
6091
nParam=e->NParam(2);
6093
DStructDesc* nStructDesc = new DStructDesc( "$truct");
6094
// instance takes care of nStructDesc since it is unnamed
6095
// dimension dim( 1);
6096
// DStructGDL* instance = new DStructGDL( nStructDesc, dim);
6097
DStructGDL* instance = new DStructGDL( nStructDesc);
6098
auto_ptr<DStructGDL> instance_guard(instance);
6100
for( SizeT p=0; p<nParam;)
6102
BaseGDL* par = e->GetParDefined( p);
6103
DStructGDL* parStruct = dynamic_cast<DStructGDL*>( par);
6104
if( parStruct != NULL)
6107
if( !parStruct->Scalar())
6108
e->Throw("Expression must be a scalar in this context: "+
6109
e->GetParString( p));
6111
DStructDesc* desc = parStruct->Desc();
6112
for( SizeT t=0; t< desc->NTags(); ++t)
6114
instance->NewTag( desc->TagName( t),
6115
parStruct->GetTag( t)->Dup());
6121
// add tag value pair
6122
DStringGDL* tagNames = e->GetParAs<DStringGDL>( p);
6123
SizeT nTags = tagNames->N_Elements();
6125
SizeT tagStart = p+1;
6126
SizeT tagEnd = p+nTags;
6127
if( tagEnd >= nParam)
6128
e->Throw( "Incorrect number of arguments.");
6130
for(++p; p<=tagEnd; ++p)
6132
BaseGDL* value = e->GetParDefined( p);
6135
instance->NewTag( TagName( e, (*tagNames)[ p-tagStart]),
6141
instance_guard.release();
6146
BaseGDL* rotate( EnvT* e)
6149
BaseGDL* p0 = e->GetParDefined( 0);
6151
if( p0->Rank() == 0)
6152
e->Throw( "Expression must be an array in this context: " + e->GetParString( 0));
6154
if( p0->Rank() != 1 && p0->Rank() != 2)
6155
e->Throw( "Only 1 or 2 dimensions allowed: " + e->GetParString( 0));
6157
if( p0->Type() == GDL_STRUCT)
6158
e->Throw( "STRUCT expression not allowed in this context: "+
6159
e->GetParString( 0));
6162
e->AssureLongScalarPar( 1, dir);
6164
return p0->Rotate( dir);
6167
// SA: based on the code of rotate() (above)
6168
BaseGDL* reverse( EnvT* e)
6171
BaseGDL* p0 = e->GetParDefined(0);
6172
if (p0->Rank() == 0) return p0->Dup();
6175
if (e->GetPar(1) != NULL)
6176
e->AssureLongScalarPar(1, dim);
6177
if (p0->Rank() != 0 && (dim > p0->Rank() || dim < 1))
6178
e->Throw("Subscript_index must be positive and less than or equal to number of dimensions.");
6181
// IDL doc states that OVERWRITE is ignored for one- or two-dim. arrays
6182
// but it seems to behave differently
6183
// if (p0->Rank() > 2 && e->KeywordSet("OVERWRITE") && e->GlobalPar(0))
6184
if (e->KeywordSet("OVERWRITE"))
6187
bool stolen = e->StealLocalPar( 0);
6188
if( !stolen) e->GetPar(0) = NULL;
6191
else ret = p0->DupReverse(dim - 1);
6195
// SA: parse_url based on the PHP parse_url() function code
6196
// by Jim Winstead / The PHP Group (PHP license v. 3.01)
6197
// (http://svn.php.net/viewvc/php/php-src/trunk/ext/standard/url.c)
6198
// PHP is free software available at http://www.php.net/software/
6201
// - IDL does not support IPv6 URLs, GDL does
6202
// - IDL includes characters after '#' in the QUERY part, GDL
6203
// just skips them and issues a warning (perhaps not needed)
6204
// - IDL preserves controll characters in URLs, GDL preserves
6205
// them as well but a warning is issued
6206
// - IDL sets 80 as a default value for PORT, even if the url has
6207
// an ftp:// schema indicated - GDL does not have any default value
6208
// - IDL excludes the leading "/" from the path, GDL preserves it
6209
// ... these differences seem just rational for me but please do change
6210
// it if IDL-compatibility would be beneficial for any reason here
6212
BaseGDL* parse_url(EnvT* env)
6214
// sanity check for number of parameters
6215
SizeT nParam = env->NParam();
6217
// 1-nd argument : the url string
6219
env->AssureScalarPar<DStringGDL>(0, url);
6221
// sanity check for controll characters
6222
string::iterator it;
6223
for (it = url.begin(); it < url.end(); it++) if (iscntrl(*it))
6225
Warning("PARSE_URL: URL contains a control character");
6229
// creating the output anonymous structure
6230
DStructDesc* urlstru_desc = new DStructDesc("$truct");
6232
urlstru_desc->AddTag("SCHEME", &aString);
6233
static size_t ixSCHEME = 0;
6234
urlstru_desc->AddTag("USERNAME", &aString);
6235
urlstru_desc->AddTag("PASSWORD", &aString);
6236
urlstru_desc->AddTag("HOST", &aString);
6237
urlstru_desc->AddTag("PORT", &aString);
6238
static size_t ixPORT = 4;
6239
urlstru_desc->AddTag("PATH", &aString);
6240
urlstru_desc->AddTag("QUERY", &aString);
6241
DStructGDL* urlstru = new DStructGDL(urlstru_desc, dimension());
6242
auto_ptr<DStructGDL> urlstru_guard(urlstru);
6245
char const *str = url.c_str();
6246
size_t length = url.length();
6248
char const *s, *e, *p, *pp, *ue;
6254
if ((e = (const char*)memchr(s, ':', length)) && (e - s))
6256
// validating scheme
6260
// scheme = 1*[ lowalpha | digit | "+" | "-" | "." ]
6261
if (!isalpha(*p) && !isdigit(*p) && *p != '+' && *p != '.' && *p != '-')
6263
if (e + 1 < ue) goto parse_port;
6264
else goto just_path;
6268
if (*(e + 1) == '\0')
6270
// only scheme is available
6271
urlstru->InitTag("SCHEME", DStringGDL(string(s, (e - s))));
6274
// schemas without '/' (like mailto: and zlib:)
6277
// check if the data we get is a port this allows us to correctly parse things like a.com:80
6279
while (isdigit(*p)) p++;
6280
if ((*p == '\0' || *p == '/') && (p - e) < 7) goto parse_port;
6281
urlstru->InitTag("SCHEME", DStringGDL(string(s, (e - s))));
6288
urlstru->InitTag("SCHEME", DStringGDL(string(s, (e - s))));
6292
if (!strncasecmp("file",
6293
(*static_cast<DStringGDL*>(urlstru->GetTag(ixSCHEME)))[0].c_str(),
6297
if (*(e + 3) == '/')
6299
// support windows drive letters as in: file:///c:/somedir/file.txt
6300
if (*(e + 5) == ':') s = e + 4;
6307
if (!strncasecmp("file",
6308
(*static_cast<DStringGDL*>(urlstru->GetTag(ixSCHEME)))[0].c_str(),
6326
// no scheme, look for port
6330
while (pp-p < 6 && isdigit(*pp)) pp++;
6331
if (pp-p < 6 && (*pp == '/' || *pp == '\0'))
6333
memcpy(port_buf, p, (pp-p));
6334
port_buf[pp-p] = '\0';
6335
urlstru->InitTag("PORT", DStringGDL(port_buf));
6337
else goto just_path;
6346
if (!(p = (const char*)memchr(s, '/', (ue - s))))
6348
if ((p = (const char*)memchr(s, '?', (ue - s)))) e = p;
6349
else if ((p = (const char*)memchr(s, '#', (ue - s)))) e = p;
6352
// check for login and password
6355
if ((pos = string(s, e - s).find_last_of("@")) != string::npos)
6358
if ((pp = (const char*)memchr(s, ':', (p-s))))
6360
if ((pp-s) > 0) urlstru->InitTag("USERNAME", DStringGDL(string(s, (pp - s))));
6362
if (p-pp > 0) urlstru->InitTag("PASSWORD", DStringGDL(string(pp, (p - pp))));
6364
else urlstru->InitTag("USERNAME", DStringGDL(string(s, (p - s))));
6369
if (*s == '[' && *(e-1) == ']') p = s; // IPv6 embedded address
6370
else for(p = e; *p != ':' && p >= s; p--); // memrchr is a GNU extension
6371
if (p >= s && *p == ':')
6373
if ((*static_cast<DStringGDL*>(urlstru->GetTag(ixPORT)))[0].length() == 0)
6376
if (e-p > 5) env->Throw("port cannot be longer then 5 characters");
6379
memcpy(port_buf, p, (e-p));
6380
port_buf[e-p] = '\0';
6381
urlstru->InitTag("PORT", DStringGDL(port_buf));
6387
// check if we have a valid host, if we don't reject the string as url
6388
if ((p-s) < 1) env->Throw("invalid host");
6389
urlstru->InitTag("HOST", DStringGDL(string(s, (p - s))));
6390
if (e == ue) goto end;
6393
if ((p = (const char*)memchr(s, '?', (ue - s))))
6395
pp = strchr(s, '#');
6399
pp = strchr(pp+2, '#');
6401
if (p - s) urlstru->InitTag("PATH", DStringGDL(string(s, (p - s))));
6404
if (pp - ++p) urlstru->InitTag("QUERY", DStringGDL(string(p, (pp - p))));
6408
else if (++p - ue) urlstru->InitTag("QUERY", DStringGDL(string(p, (ue - p))));
6410
else if ((p = (const char*)memchr(s, '#', (ue - s))))
6412
if (p - s) urlstru->InitTag("PATH", DStringGDL(string(s, (p - s))));
6415
if (ue - p) Warning("PARSE_URL: URL fragment left out: #" + string(p, (ue-p)));
6417
else urlstru->InitTag("PATH", DStringGDL(string(s, (ue - s))));
6420
// returning the result
6421
urlstru_guard.release();
6425
BaseGDL* locale_get(EnvT* e)
6427
#ifdef HAVE_LOCALE_H
6429
// make GDL inherit the calling process locale
6430
setlocale(LC_ALL, "");
6431
// note doen the inherited locale
6432
DStringGDL *locale = new DStringGDL(setlocale(LC_CTYPE, NULL));
6433
// return to the C locale
6434
setlocale(LC_ALL, "C");
6438
e->Throw("OS does not provide locale information");
6442
// SA: relies on the contents of the lib::command_line_args vector
6443
// defined and filled with data (pointers) in gdl.cpp
6444
BaseGDL* command_line_args_fun(EnvT* e)
6446
#ifdef PYTHON_MODULE
6447
e->Throw("no command line arguments available (GDL built as a Python module)");
6449
static int countIx = e->KeywordIx("COUNT");
6450
extern std::vector<char*> command_line_args;
6452
// setting the COUNT keyword value
6453
if (e->KeywordPresent(countIx))
6455
e->AssureGlobalKW(countIx);
6456
e->SetKW(countIx, new DLongGDL(command_line_args.size()));
6459
// returning empty string or an array of arguments
6460
if (command_line_args.empty()) return new DStringGDL("");
6463
BaseGDL* ret = new DStringGDL(dimension(command_line_args.size()));
6464
for (size_t i = 0; i < command_line_args.size(); i++)
6465
(*static_cast<DStringGDL*>(ret))[i] = command_line_args[i];
6471
// SA: relies in the uname() from libc (must be there if POSIX)
6472
BaseGDL* get_login_info( EnvT* e)
6476
#define MAX_TCHAR_BUF 256
6478
char login[MAX_TCHAR_BUF];
6479
char info[MAX_TCHAR_BUF];
6481
DWORD N_TCHAR = MAX_TCHAR_BUF;
6484
TCHAR t_buf[MAX_TCHAR_BUF];
6485
GetUserName(t_buf, &N_TCHAR);
6486
WideCharToMultiByte(CP_ACP, 0, t_buf, N_TCHAR, login, N_TCHAR, NULL, NULL);
6487
GetComputerName( t_buf, &N_TCHAR );
6488
WideCharToMultiByte(CP_ACP, 0, t_buf, N_TCHAR, info, N_TCHAR, NULL, NULL);
6490
GetUserName(login, &N_TCHAR);
6491
GetComputerName(info, &N_TCHAR);
6494
char* login = getlogin();
6495
if (login == NULL) e->Throw("Failed to get user name from the OS");
6496
struct utsname info;
6497
if (0 != uname(&info)) e->Throw("Failed to get machine name from the OS");
6499
// creating the output anonymous structure
6500
DStructDesc* stru_desc = new DStructDesc("$truct");
6502
stru_desc->AddTag("MACHINE_NAME", &aString);
6503
stru_desc->AddTag("USER_NAME", &aString);
6504
DStructGDL* stru = new DStructGDL(stru_desc, dimension());
6506
// returning the info
6507
stru->InitTag("USER_NAME", DStringGDL(login));
6509
stru->InitTag("MACHINE_NAME", DStringGDL(info));
6511
stru->InitTag("MACHINE_NAME", DStringGDL(info.nodename));
6516
// SA: base64 logic in base64.hpp, based on code by Bob Withers (consult base64.hpp)
6517
BaseGDL* idl_base64(EnvT* e)
6519
BaseGDL* p0 = e->GetPar(0);
6522
if (p0->Rank() == 0 && p0->Type() == GDL_STRING)
6525
string* str = &((*static_cast<DStringGDL*>(p0))[0]);
6526
if (str->length() == 0) return new DByteGDL(0);
6527
if (str->length() % 4 != 0)
6528
e->Throw("Input string length must be a multiple of 4");
6529
unsigned int retlen = base64::decodeSize(*str);
6530
if (retlen == 0 || retlen > str->length()) e->Throw("No data in the input string");
6531
DByteGDL* ret = new DByteGDL(dimension(retlen));
6532
if (!base64::decode(*str, (char*)&((*ret)[0]), ret->N_Elements()))
6533
e->Throw("Base64 decoder failed");
6536
if (p0->Rank() >= 1 && p0->Type() == GDL_BYTE)
6539
return new DStringGDL(
6540
base64::encode((char*)&(*static_cast<DByteGDL*>(p0))[0], p0->N_Elements())
6544
e->Throw("Expecting string or byte array as a first parameter");
6547
BaseGDL* get_drive_list(EnvT* e)
6549
if (e->KeywordPresent(0)) e->SetKW(0, new DLongGDL(0));
6550
return new DStringGDL("");
6553
// note: changes here MUST be reflected in scope_varfetch_reference() as well
6554
// because DLibFun of this function is used for scope_varfetch_reference() the keyword
6555
// indices must match
6556
BaseGDL* scope_varfetch_value( EnvT* e)
6558
SizeT nParam=e->NParam();
6560
EnvStackT& callStack = e->Interpreter()->CallStack();
6561
// DLong curlevnum = callStack.size()-1;
6562
// 'e' is not on the stack
6563
DLong curlevnum = callStack.size();
6565
// static int variablesIx = e->KeywordIx( "VARIABLES" );
6566
static int levelIx = e->KeywordIx( "LEVEL" );
6568
DLongGDL* level = e->IfDefGetKWAs<DLongGDL>( levelIx);
6570
DLong desiredlevnum = 0;
6573
desiredlevnum = (*level)[0];
6575
if (desiredlevnum <= 0) desiredlevnum += curlevnum;
6576
if (desiredlevnum < 1) desiredlevnum = 1;
6577
else if (desiredlevnum > curlevnum) desiredlevnum = curlevnum;
6579
DSubUD* pro = static_cast<DSubUD*>(callStack[desiredlevnum-1]->GetPro());
6581
SizeT nVar = pro->Size(); // # var in GDL for desired level
6582
int nKey = pro->NKey();
6586
e->AssureScalarPar<DStringGDL>( 0, varName);
6587
varName = StrUpCase( varName);
6589
int xI = pro->FindVar( varName);
6592
// BaseGDL*& par = ((EnvT*)(callStack[desiredlevnum-1]))->GetPar( xI);
6593
BaseGDL*& par = callStack[desiredlevnum-1]->GetKW( xI);
6596
e->Throw( "Variable is undefined: " + varName);
6601
e->Throw( "Variable not found: " + varName);
6602
return new DLongGDL(0); // compiler shut-up
6605
// this routine is special, only called as an l-function (from FCALL_LIB::LEval())
6606
// it MUST use an EnvT set up for scope_varfetch_value
6607
BaseGDL** scope_varfetch_reference( EnvT* e)
6609
SizeT nParam=e->NParam();
6611
EnvStackT& callStack = e->Interpreter()->CallStack();
6612
// DLong curlevnum = callStack.size()-1;
6613
// 'e' is not on the stack
6614
DLong curlevnum = callStack.size();
6616
// static int variablesIx = e->KeywordIx( "VARIABLES" );
6617
static int levelIx = e->KeywordIx( "LEVEL" );
6619
DLongGDL* level = e->IfDefGetKWAs<DLongGDL>( levelIx);
6621
DLong desiredlevnum = 0;
6624
desiredlevnum = (*level)[0];
6626
if (desiredlevnum <= 0) desiredlevnum += curlevnum;
6627
if (desiredlevnum < 1) desiredlevnum = 1;
6628
else if (desiredlevnum > curlevnum) desiredlevnum = curlevnum;
6630
DSubUD* pro = static_cast<DSubUD*>(callStack[desiredlevnum-1]->GetPro());
6632
SizeT nVar = pro->Size(); // # var in GDL for desired level
6633
int nKey = pro->NKey();
6637
e->AssureScalarPar<DStringGDL>( 0, varName);
6638
varName = StrUpCase( varName);
6639
int xI = pro->FindVar( varName);
6642
// BaseGDL*& par = ((EnvT*)(callStack[desiredlevnum-1]))->GetPar( xI);
6643
BaseGDL*& par = callStack[desiredlevnum-1]->GetKW( xI);
6646
// e->Throw( "Variable is undefined: " + varName);
6651
e->Throw( "LVariable not found: " + varName);
6652
return NULL; // compiler shut-up