1 /***************************************************************************
2            datatypes.hpp  -  defines all data types of GDL except DStructGDL
3                              -------------------
4     begin                : Tue Feb 13 2002
5     copyright            : (C) 2002 by Marc Schellens
6     email                : m_schellens@users.sf.net
7  ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 
18 
19 #ifndef DATATYPES_HPP_
20 #define DATATYPES_HPP_
21 
22 
23 #include "typedefs.hpp"
24 #include "basegdl.hpp"
25 #include "typetraits.hpp"
26 
27 #include <string>
28 
29 #if defined(__GNUC__) && !defined(__INTEL_COMPILER)
30 // by default intel C++ defines __GNUC__
31 #pragma interface
32 #endif
33 
34 
35 // for each group we need one definition
36 // usage: GDL_DEFINE_INTEGER_FUNCTION(retType) fName( arg list) { definition}
37 #define GDL_DEFINE_INTEGER_FUNCTION( retType ) template<typename Sp>template< typename U> typename U::template IfInteger< retType >::type Data_<Sp>::
38 #define GDL_DEFINE_FLOAT_FUNCTION( retType ) template<typename Sp>template< typename U> typename U::template IfFloat< retType >::type Data_<Sp>::
39 #define GDL_DEFINE_COMPLEX_FUNCTION( retType ) template<typename Sp>template< typename U> typename U::template IfComplex< retType >::type Data_<Sp>::
40 #define GDL_DEFINE_OTHER_FUNCTION( retType ) template<typename Sp>template< typename U> typename U::template IfOther< retType >::type Data_<Sp>::
41 
42 const size_t multiAlloc = 256;
43 
44 template<class Sp>
45 class Data_: public Sp
46 {
47 
48 // save some typing. Declares function "fName" for all four groups (with return type "retType")
49 #define GDL_DECLARE_FUNCTION( retType, fName, ... ) \
50 template< typename U = Sp > typename U::template IfInteger< retType >::type fName( __VA_ARGS__); \
51 template< typename U = Sp > typename U::template IfFloat< retType >::type fName( __VA_ARGS__); \
52 template< typename U = Sp > typename U::template IfComplex< retType >::type fName( __VA_ARGS__); \
53 template< typename U = Sp > typename U::template IfOther< retType >::type fName( __VA_ARGS__)
54 
55 
56 public:
57   typedef typename Sp::Ty    Ty;
58   typedef Sp                 Traits;
59 
60 #ifdef _MSC_VER
61 public: // MSC cannot handle friend template specialization properly
62 #else
63 private:
64 #endif
65 
66   typedef typename Sp::DataT DataT;
67 #ifdef USE_EIGEN
68   EIGEN_ALIGN16 DataT        dd; // the data
69 #else
70   DataT                      dd; // the data
71 #endif
72 
73 public:
74 
75 // #define TESTTG // TEST TEMPLATE GROUPING
76 
77 #ifdef TESTTG
78 
79 void TestTemplateGrouping();
80 
81 // #define GDL_TEMPLATE_Integer( retType ) template< typename U = Sp > typename U::template IfInteger< retType >::type
82 // #define GDL_TEMPLATE_IntegerDef( retType ) template<typename Sp>template< typename U> typename U::template IfInteger< retType >::type Data_<Sp>::
83 
84 
85 GDL_DECLARE_FUNCTION(bool,Test2);
86 
87 // template< typename U = Sp >
88 //typename U::template IfInteger<bool>::type
89 // GDL_TEMPLATE_Integer(bool) Test2();
90 // template< typename U = Sp >
91 // typename U::template IfFloat<bool>::type
92 // Test2();
93 // template< typename U = Sp >
94 // typename U::template IfComplex<bool>::type
95 // Test2();
96 // template< typename U = Sp >
97 // typename U::template IfOther<bool>::type
98 // Test2();
99 
100 #endif
101 
102 public:
103 	// memory management optimization
104 static FreeListT freeList;
105 
106 	// operator new and delete
107 static 	void* operator new( size_t bytes);
108 static	void operator delete( void *ptr);
109 
110   //structors
111   ~Data_();
112 
113   // default
114   Data_();
115 
116   // scalar
117   Data_(const Ty& d_);
118 
119   // new array, no zero or indgen
120   Data_(const dimension& dim_,  BaseGDL::InitType iT,
121         DDouble start = 0, DDouble increment = 1);
122 
123   // new array, zero fields
124   Data_(const dimension& dim_);
125 
126   // new array from Ty[], one dimensional
127   Data_( const Ty* p, SizeT nEl);
128 
129   // new array from DataT
Data_(const dimension & dim_,const DataT & dd_)130   Data_(const dimension& dim_, const DataT& dd_):
131     Sp( dim_), dd( dd_) {}
132 
133   // c-i
134   Data_(const Data_& d_);//: Sp(d_.dim), dd(d_.dd) {}
135 
136   // operators
137   // assignment.
138   Data_& operator=(const BaseGDL& right);
139 
140   // for structs
141   void InitFrom(const BaseGDL& right);
142 
143   // one dim array access (unchecked)
operator [](const SizeT d1)144   inline Ty& operator[] (const SizeT d1) { return dd[d1];}
operator [](const SizeT d1) const145   inline const Ty& operator[] (const SizeT d1) const { return dd[d1];}
146   //  Ty& operator[] (const SizeT d1) { return dd[d1];}
147 
148   template<class Sp2>
149   friend std::istream& operator>>(std::istream& i, Data_<Sp2>& data_);
150 
151   // valarrays cannot be resized (without loosing data)
152   //  inline DataT& Resize( SizeT n);
153 
154 //   // note that min and max these are not defined in BaseGDL
155 //   Ty min() const;// { return dd.min();}
156 //   Ty max() const;// { return dd.max();}
157 
158   bool Greater(SizeT i1, SizeT i2) const; // comp 2 elements
159   bool Equal(SizeT i1, SizeT i2) const; // comp 2 elements
160 
161   BaseGDL* CShift( DLong d) const;
162   BaseGDL* CShift( DLong d[MAXRANK]) const;
163 
164   BaseGDL* Transpose( DUInt* perm);
165   BaseGDL* Rotate( DLong dir);
166   void Reverse( DLong dim);
167   BaseGDL* DupReverse( DLong dim);
168 
169   // for use by MIN and MAX functions
170   void MinMax( DLong* minE, DLong* maxE, BaseGDL** minVal, BaseGDL** maxVal,
171 	       bool omitNaN,
172                SizeT start = 0, SizeT stop = 0, SizeT step = 1, DLong valIx = -1, bool useAbs = false);
173 
174   bool EqType( const BaseGDL* r) const;
175 
176   void* DataAddr();// SizeT elem=0);
177 
178   Ty Sum() const;
179 
180   SizeT N_Elements() const;
181   SizeT Size() const;
182   SizeT NBytes() const;
183   SizeT ToTransfer() const; // IO transfer count
184   SizeT Sizeof() const;
185 
186   int HashCompare( BaseGDL* p2) const;
187 
188   void Clear();
189   void Construct();     // construction (for DStructGDL)
190   void ConstructTo0();  // construction (for DStructGDL)
191   void Destruct();      // destruction (for DStructGDL)
192 
193   BaseGDL* SetBuffer( const void* b);
194   void SetBufferSize( SizeT s);
195 
196   BaseGDL* AssocVar( int, SizeT);
197 
198   std::ostream& ToStream(std::ostream& o, SizeT width = 0,
199 			 SizeT* actPosPtr = NULL);
200   std::istream& FromStream(std::istream& i);
201 
202   // used by the interpreter
203   int Scalar2Index( SizeT& st) const;
204   int Scalar2RangeT( RangeT& st) const;
205   RangeT LoopIndex() const;
206   DDouble HashValue() const;
207 
208   // used for indexing of arrays
209   SizeT GetAsIndex( SizeT i) const;
210   SizeT GetAsIndexStrict( SizeT i) const;
211 
212   // make a duplicate on the heap
213   Data_* Dup() const;
214 //   // make a duplicate at loc
215 //   Data_* Dup( void* loc) const { return ::new ( loc) Data_(*this);}
216 
217 //  bool OutOfRangeOfInt() const;
218 
Scalar() const219   bool Scalar() const { return (dd.size() == 1);}
StrictScalar() const220   bool StrictScalar() const { return (this->Rank() == 0);}
221 
Scalar(Ty & s) const222   bool Scalar(Ty& s) const {
223     if( dd.size() != 1) return false;
224     s=dd[0];
225     return true; }
StrictScalar(Ty & s) const226   bool StrictScalar(Ty& s) const {
227     if( this->Rank() != 0) return false;
228     s=dd[0];
229     return true; }
230 
231   Data_* New( const dimension& dim_, BaseGDL::InitType noZero=BaseGDL::ZERO) const;
232   Data_* NewResult() const;
233 
234   // convert *this to other 'destTy'
235   BaseGDL* Convert2( DType destTy,
236 		     BaseGDL::Convert2Mode=BaseGDL::CONVERT);
237 
238   // not all compilers can handle template friend member functions
239 #ifndef _MSC_VER
240 #  if __GNUC__ >= 4
241 #    if defined(__clang__)
242        // suppress: warning: dependent nested name specifier 'Data_<Sp2>::' for friend class declaration is not supported; turning off access control for 'Data_' [-Wunsupported-friend]
243 #      pragma clang diagnostic push
244 #      pragma clang diagnostic ignored "-Wunsupported-friend"
245   // make all other Convert2 functions friends
246   template<class Sp2>
247   friend BaseGDL* Data_<Sp2>::Convert2( DType destTy,
248 					BaseGDL::Convert2Mode);
249 #      pragma clang diagnostic pop
250 #    endif
251 #  else
252   // this explicit version does not work with GCC 4.0
253   friend BaseGDL* Data_<SpDByte>::Convert2( DType destTy, BaseGDL::Convert2Mode);
254   friend BaseGDL* Data_<SpDInt>::Convert2( DType destTy, BaseGDL::Convert2Mode);
255   friend BaseGDL* Data_<SpDUInt>::Convert2( DType destTy, BaseGDL::Convert2Mode);
256   friend BaseGDL* Data_<SpDLong>::Convert2( DType destTy, BaseGDL::Convert2Mode);
257   friend BaseGDL* Data_<SpDULong>::Convert2( DType destTy, BaseGDL::Convert2Mode);
258   friend BaseGDL* Data_<SpDLong64>::Convert2( DType destTy, BaseGDL::Convert2Mode);
259   friend BaseGDL* Data_<SpDULong64>::Convert2( DType destTy, BaseGDL::Convert2Mode);
260   friend BaseGDL* Data_<SpDFloat>::Convert2( DType destTy, BaseGDL::Convert2Mode);
261   friend BaseGDL* Data_<SpDDouble>::Convert2( DType destTy, BaseGDL::Convert2Mode);
262   friend BaseGDL* Data_<SpDString>::Convert2( DType destTy, BaseGDL::Convert2Mode);
263   friend BaseGDL* Data_<SpDPtr>::Convert2( DType destTy, BaseGDL::Convert2Mode);
264   friend BaseGDL* Data_<SpDObj>::Convert2( DType destTy, BaseGDL::Convert2Mode);
265   friend BaseGDL* Data_<SpDComplex>::Convert2( DType destTy, BaseGDL::Convert2Mode);
266   friend BaseGDL* Data_<SpDComplexDbl>::Convert2( DType destTy, BaseGDL::Convert2Mode);
267 
268 #  endif
269 #endif
270 
271   bool True();
272   bool False();
273   bool LogTrue();
274   bool LogTrue( SizeT ix);
275   void Where(DLong* &ret, SizeT &passed_count, bool comp, DLong* &comp_ret);
276   void Where(DLong64* &ret, SizeT &passed_count, bool comp, DLong64* &comp_ret);
277   Data_<SpDByte>* LogNeg();
278   int  Sgn(); // returns -1,0,1
279   bool Equal( BaseGDL*) const;
280   bool EqualNoDelete( const BaseGDL*) const;
281   bool ArrayEqual( BaseGDL*);
282   bool ArrayNeverEqual( BaseGDL*);
283   bool ForCheck( BaseGDL**, BaseGDL** =NULL);
284   bool ForCondUp( BaseGDL*);
285   bool ForCondDown( BaseGDL*);
286   bool ForAddCondUp( BaseGDL* loopInfo);
287 //   bool ForAddCondUp( ForLoopInfoT& loopInfo);
288   //  bool ForCondUpDown( BaseGDL*);
289   void ForAdd();
290   void ForAdd( BaseGDL* add);
291 
292   BaseGDL* Abs() const;
293 
294   BaseGDL* Convol( BaseGDL* kIn, BaseGDL* scaleIn, BaseGDL* bias,
295 		   bool center, bool normalize, int edgeMode,
296                    bool doNan, BaseGDL* missing, bool doMissing,
297                    BaseGDL* invalid, bool doInvalid);
298   BaseGDL* Smooth(DLong* width, int edgeMode,
299                    bool doNan, BaseGDL* missing);
300   BaseGDL* Rebin( const dimension& newDim, bool sample);
301 
302   void Assign( BaseGDL* src, SizeT nEl);
303 
304   template< typename To> typename Data_<To>::Ty GetAs( SizeT i);
305 //   {
306 //     return dd[ i];
307 //   }
308 
309   BaseGDL* Log();
310   BaseGDL* LogThis();
311 
312   BaseGDL* Log10();
313   BaseGDL* Log10This();
314 
315   // operators
316   BaseGDL* UMinus(); // UMinus for SpDString returns float
317   Data_*   NotOp();
318 // GDL_DECLARE_FUNCTION( Data_*, AndOp, BaseGDL* r);
319   Data_*   AndOp( BaseGDL* r);
320   Data_*   AndOpInv( BaseGDL* r);
321   Data_*   OrOp( BaseGDL* r);
322   Data_*   OrOpInv( BaseGDL* r);
323   Data_*   XorOp( BaseGDL* r);
324 
325   BaseGDL* Add( BaseGDL* r);
326   BaseGDL* AddInv( BaseGDL* r);
327   BaseGDL* AddS( BaseGDL* r);
328   BaseGDL* AddInvS( BaseGDL* r);
329 
330   BaseGDL* AddNew( BaseGDL* r);      // implemented
331   BaseGDL* AddInvNew( BaseGDL* r);      // implemented
332   BaseGDL* AddSNew( BaseGDL* r);         // implemented
333   BaseGDL* AddInvSNew( BaseGDL* r);    // implemented
334 
335 //   Data_*   AddNew( BaseGDL* r);
336 //   Data_*   AddInvNew( BaseGDL* r);
337   BaseGDL*   Sub( BaseGDL* r);
338   BaseGDL*   SubInv( BaseGDL* r);
339   Data_*   GtMark( BaseGDL* r);
340   Data_*   LtMark( BaseGDL* r);
341   Data_*   Mult( BaseGDL* r);
342 //   Data_*   MultNew( BaseGDL* r);
343   Data_*   Div( BaseGDL* r);
344   Data_*   DivInv( BaseGDL* r);
345   Data_*   Mod( BaseGDL* r);
346   Data_*   ModInv( BaseGDL* r);
347   Data_*   Pow( BaseGDL* r);
348   Data_*   PowInv( BaseGDL* r);
349   Data_*   PowInt( BaseGDL* r);
350 //   Data_*   PowIntNew( BaseGDL* r);
351 
352   Data_*   MatrixOp( BaseGDL* r, bool atranspose, bool btranspose);
353 
354   // operators with scalar
355   Data_*   AndOpS( BaseGDL* r);
356   Data_*   AndOpInvS( BaseGDL* r);
357   Data_*   OrOpS( BaseGDL* r);
358   Data_*   OrOpInvS( BaseGDL* r);
359   Data_*   XorOpS( BaseGDL* r);
360 //   Data_*   AddSNew( BaseGDL* r);
361 //   Data_*   AddInvSNew( BaseGDL* r);
362   Data_*   SubS( BaseGDL* r);
363   Data_*   SubInvS( BaseGDL* r);
364   Data_*   GtMarkS( BaseGDL* r);
365   Data_*   LtMarkS( BaseGDL* r);
366   Data_*   MultS( BaseGDL* r);
367 //   Data_*   MultSNew( BaseGDL* r);
368   Data_*   DivS( BaseGDL* r);
369   Data_*   DivInvS( BaseGDL* r);
370   Data_*   ModS( BaseGDL* r);
371   Data_*   ModInvS( BaseGDL* r);
372   Data_*   PowS( BaseGDL* r);
373   Data_*   PowInvS( BaseGDL* r);
374 
375   // operators returning a new value
376   Data_* AndOpNew( BaseGDL* r);
377   Data_* AndOpInvNew( BaseGDL* r);
378   Data_* OrOpNew( BaseGDL* r);
379   Data_* OrOpInvNew( BaseGDL* r);
380   Data_* XorOpNew( BaseGDL* r);
381 //   Data_* EqOpNew( BaseGDL* r);
382 //   Data_* NeOpNew( BaseGDL* r);
383 //   Data_* LeOpNew( BaseGDL* r);
384 //   Data_* GeOpNew( BaseGDL* r);
385 //   Data_* LtOpNew( BaseGDL* r);
386 //   Data_* GtOpNew( BaseGDL* r);
387   BaseGDL* SubNew( BaseGDL* r);
388   BaseGDL* SubInvNew( BaseGDL* r);
389   Data_* LtMarkNew( BaseGDL* r);
390   Data_* GtMarkNew( BaseGDL* r);
391   Data_* MultNew( BaseGDL* r);   // implemented
392   Data_* DivNew( BaseGDL* r);
393   Data_* DivInvNew( BaseGDL* r);
394   Data_* ModNew( BaseGDL* r);
395   Data_* ModInvNew( BaseGDL* r);
396   Data_* PowNew( BaseGDL* r);
397   Data_* PowInvNew( BaseGDL* r);
398   Data_* PowIntNew( BaseGDL* r);   // implemented
399 
400   // operators with scalar returning a new value
401   Data_* AndOpSNew( BaseGDL* r);
402   Data_* AndOpInvSNew( BaseGDL* r);
403   Data_* OrOpSNew( BaseGDL* r);
404   Data_* OrOpInvSNew( BaseGDL* r);
405   Data_* XorOpSNew( BaseGDL* r);
406   BaseGDL* SubSNew( BaseGDL* r);
407   BaseGDL* SubInvSNew( BaseGDL* r);
408   Data_* LtMarkSNew( BaseGDL* r);
409   Data_* GtMarkSNew( BaseGDL* r);
410   Data_* MultSNew( BaseGDL* r);      // implemented
411   Data_* DivSNew( BaseGDL* r);
412   Data_* DivInvSNew( BaseGDL* r);
413   Data_* ModSNew( BaseGDL* r);
414   Data_* ModInvSNew( BaseGDL* r);
415   Data_* PowSNew( BaseGDL* r);
416   Data_* PowInvSNew( BaseGDL* r);
417 
418 
419   BaseGDL* EqOp( BaseGDL* r);
420   BaseGDL* NeOp( BaseGDL* r);
421   BaseGDL* GtOp( BaseGDL* r);
422   BaseGDL* GeOp( BaseGDL* r);
423   BaseGDL* LtOp( BaseGDL* r);
424   BaseGDL* LeOp( BaseGDL* r);
425 
426   // used by interpreter, calls CatInsert
427   Data_* CatArray( ExprListT& exprList, const SizeT catRank,
428 		   const SizeT rank);
429   // used for concatenation, called from CatArray
430   // assumes that everything is checked (see CatInfo)
431   void CatInsert( const Data_* srcArr, const SizeT atDim, SizeT& at);
432 
433   // assigns srcIn to this at ixList, if ixList is NULL does linear copy
434   // assumes: ixList has this already set as variable
435   void AssignAt( BaseGDL* srcIn, ArrayIndexListT* ixList, SizeT offset);
436   void AssignAt( BaseGDL* srcIn, ArrayIndexListT* ixList);
437   void AssignAt( BaseGDL* srcIn);
438 
439   void AssignAtIx( RangeT ix, BaseGDL* srcIn);
440 
441   // decrement (--) and increment (++) operators
442   void DecAt( ArrayIndexListT* ixList);
443   void IncAt( ArrayIndexListT* ixList);
444   void Dec();
445   void Inc();
446 
447   // used by AccessDescT for resolving, no checking is done
448   // inserts srcIn[ ixList] at offset
449   void InsertAt( SizeT offset, BaseGDL* srcIn, ArrayIndexListT* ixList);
450 
451   // returns (*this)[ ixList]
452   Data_* Index( ArrayIndexListT* ixList);
453 
454   // return a new type of itself
455   BaseGDL* NewIx( SizeT ix);
456   Data_* NewIx( BaseGDL* ix, bool strict);
457   Data_* NewIx( AllIxBaseT* ix, const dimension* dIn);
458   Data_* NewIxFrom( SizeT s);
459   Data_* NewIxFrom( SizeT s, SizeT e);
460   Data_* NewIxFromStride( SizeT s, SizeT stride);
461   Data_* NewIxFromStride( SizeT s, SizeT e, SizeT stride);
462 
463   // binary input/output
464   std::ostream& Write( std::ostream& os, bool swapEndian, bool compress,
465 		       XDR *xdrs);
466   std::istream& Read( std::istream& os, bool swapEndian, bool compress,
467 		      XDR *xdrs);
468 
469   SizeT OFmtA( std::ostream* os, SizeT offset, SizeT num, int width, const int code=0);
470   SizeT OFmtF( std::ostream* os, SizeT offs, SizeT num, int width, int prec, const int code=0, const BaseGDL::IOMode oM = BaseGDL::FIXED);
471   SizeT OFmtI( std::ostream* os, SizeT offs, SizeT num, int width, int minN, int code=0, BaseGDL::IOMode oM = BaseGDL::DEC);
472   SizeT OFmtCal( std::ostream* os, SizeT offs, SizeT num, int width, int minN, char *f, int code=0, BaseGDL::Cal_IOMode oM = BaseGDL::DEFAULT);
473   // formatting input functions
474   SizeT IFmtA( std::istream* is, SizeT offset, SizeT num, int width);
475   SizeT IFmtF( std::istream* is, SizeT offs, SizeT num, int width);
476   SizeT IFmtI( std::istream* is, SizeT offs, SizeT num, int width,
477 		BaseGDL::IOMode oM = BaseGDL::DEC);
478   SizeT IFmtCal( std::istream* is, SizeT offs, SizeT r, int width, BaseGDL::Cal_IOMode cMode);
479 #ifdef USE_PYTHON
480 public:
481   PyObject* ToPython();
482 private:
483   PyObject* ToPythonScalar();
484 #endif
485 
486 private:
487 
488   // inserts srcIn at ixDim, used by AssignAt(...)
489   // respects the exact structure
490   void InsAt( Data_* srcIn, ArrayIndexListT* ixList, SizeT offset = 0);
491 
492   // only to be used here
493 #undef GDL_DECLARE_FUNCTION
494 
495 };
496 
497 // template<> Data_<SpDPtr>::Data_(const Ty& d_);
498 // template<> Data_<SpDObj>::Data_(const Ty& d_);
499 
500 #include "specializations.hpp"
501 
502 typedef Data_<SpDByte>       DByteGDL;
503 typedef Data_<SpDInt>        DIntGDL;
504 typedef Data_<SpDUInt>       DUIntGDL;
505 typedef Data_<SpDLong>       DLongGDL;
506 typedef Data_<SpDULong>      DULongGDL;
507 typedef Data_<SpDLong64>     DLong64GDL;
508 typedef Data_<SpDULong64>    DULong64GDL;
509 typedef Data_<SpDFloat>      DFloatGDL;
510 typedef Data_<SpDDouble>     DDoubleGDL;
511 typedef Data_<SpDString>     DStringGDL;
512 typedef Data_<SpDPtr>        DPtrGDL;
513 typedef Data_<SpDObj>        DObjGDL;
514 typedef Data_<SpDComplex>    DComplexGDL;
515 typedef Data_<SpDComplexDbl> DComplexDblGDL;
516 
517 // DStructGDL defined separately
518 
519 // on OS X isfinite is not defined
520 #if defined(__APPLE__) && defined(OLD_DARWIN) && !defined(isfinite)
521 
522 #ifdef __cplusplus
523 extern "C" {
524 #endif
525 #define      isfinite( x )      ( ( sizeof ( x ) == sizeof(double) ) ?       \
526                               __isfinited ( x ) :                            \
527                                 ( sizeof ( x ) == sizeof( float) ) ?         \
528                               __isfinitef ( x ) :                            \
529                               __isfinite  ( x ) )
530 #ifdef __cplusplus
531 }
532 #endif
533 #endif
534 
535 // isfinite & isinf for Solaris
536 #if defined(__sun__)
537 #  include <ieeefp.h>
538 #  define isfinite finite
539 #  ifndef isinf
540 #    define isinf(x) (!finite(x) && x==x)
541 #  endif
542 #endif
543 
544 #endif
545