1 /***************************************************************************
2                           ofmt.hpp  -  formatted input/output
3                              -------------------
4     begin                : July 22 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 #ifndef OFMT_HPP_
19 #define OFMT_HPP_
20 
21 #include <sstream>
22 #include <iomanip>
23 #include <ostream>
24 #include <cmath>
25 #include <bitset> // for binary output
26 //using namespace std;
27 
28 #include "datatypes.hpp"
29 #include "dstructgdl.hpp"
30 
31 #ifdef _MSC_VER
32 #define finite _finite
33 #define isnan _isnan
34 #endif
35 
36 typedef enum codeFlags_
37   {
38     fmtALIGN_LEFT = 1
39    ,fmtSHOWPOS = 2
40    ,fmtPAD = 4
41    ,fmtUPPER = 8
42   } codeFlags;
43 
44 
45 
46 
47 // for auto formatting of float types
48 // code in ofmt.cpp
49 template< typename T>
50 class AsComplex
51 {
52 #ifdef _MSC_VER
53 public: // MSC cannot handle friend template specialization properly
54 #endif
55   T   flt;
56   int width;
57   int prec;
58   int code;
59 public:
AsComplex(const T val,const int w,const int p,const int c=0)60   AsComplex( const T val, const int w, const int p, const int c=0): flt( val), width( w), prec( p), code( c)
61   {}
62 
63   template< typename T2>
64   friend std::ostream& operator<<(std::ostream& os, const AsComplex<T2>& a);
65 };
66 
67 class CheckNL
68 {
69 #ifdef _MSC_VER
70 public: // MSC cannot handle friend template specialization properly
71 #endif
72   SizeT  width;
73   SizeT* actPosPtr;
74   SizeT  nextW;
75 
76 public:
CheckNL(const SizeT w,SizeT * const a,const SizeT n)77   CheckNL( const SizeT w,
78       SizeT* const a,
79       const SizeT n): width( w), actPosPtr( a), nextW( n)
80   {}
81 
82   friend std::ostream& operator<<(std::ostream& os, const CheckNL& cc);
83 };
84 
85 // code in default_io.cpp
86 std::ostream& operator<<(std::ostream& os, const CheckNL& c);
87 
88 // formatted output functions
OutStars(std::ostream & os,const int n)89 inline void OutStars( std::ostream& os, const int n)
90 {
91   for( int i=0; i<n; ++i) os << "*";
92 }
93 
OutFixedStringVal(std::ostream & os,const std::string & symbol,const char s,int w,const int code)94 inline void OutFixedStringVal( std::ostream& os, const std::string &symbol, const char s, int w, const int code) {
95   int l=symbol.length();
96   bool dosign=( code & fmtSHOWPOS || s=='-');
97   bool dofill=( code & fmtPAD );
98   if (w <=0) w=(dosign?l+1:l);
99   if( w < (dosign?l+1:l)) { OutStars( os, w); return;}
100   if (code & fmtALIGN_LEFT)
101   {
102    os << std::left;
103    if (dosign) {os << s << std::setw( w-1 ) << symbol ; return;}
104    os << std::setw( w ) << symbol;  return;
105   }
106   if (dofill && dosign ) { os << s << std::setw( w-1 ) << std::setfill('0') << std::right << symbol << std::setfill(' ') ; return;}
107   if (dofill) { os << std::setw( w ) << std::setfill('0') << std::right << symbol << std::setfill(' ') ; return;}
108   if (dosign)  { os << std::setw( w-l ) << std::right << s << symbol; return;}
109   os << std::setw( w ) << std::right << symbol; return;
110 }
111 
112 template <typename T>
OutFixedNan(std::ostream & os,const T val,const int w,const int code)113 inline void OutFixedNan( std::ostream& os, const T val, const int w, const int code) //d is ignored for Nan/Inf
114 {
115   static std::string symbol="NaN";
116   char s=(std::signbit(val))?'-':'+';
117   OutFixedStringVal(os, symbol, s, w, code);
118 }
119 
120 template <typename T>
OutFixedInf(std::ostream & os,const T val,const int w,const int code)121 inline void OutFixedInf( std::ostream& os, const T val, const int w, const int code) //d is ignored for Nan/Inf
122 {
123   static std::string symbol="Inf";
124   char s=(std::signbit(val))?'-':'+';
125   OutFixedStringVal(os, symbol, s, w, code);
126 }
127 template <>
OutFixedInf(std::ostream & os,const DDouble val,const int w,const int code)128 inline void OutFixedInf<DDouble>( std::ostream& os, const DDouble val, const int w, const int code) //d is ignored for Nan/Inf
129 {
130   static std::string symbol="Infinity";
131   char s=(std::signbit(val))?'-':'+';
132   OutFixedStringVal(os, symbol,s, w, code);
133 }
134 
OutFixFill(std::ostream & os,const std::string & s,const int w,const int code)135 inline void OutFixFill(std::ostream& os, const std::string &s, const int w, const int code)
136 {
137    if ( code & fmtPAD ) os << std::setfill('0');
138    if ( ( code & fmtPAD ) && ((s.substr( 0, 1) == "-" ) || ( s.substr(0, 1) == "+" )) ) {  // preventing "00-1.00" or "00+1.00"
139      os << s.substr(0, 1) << std::right << std::setw(w - 1) << s.substr(1);
140    }
141    else
142     os << std::setw(w) << std::right << s;
143    if ( code & fmtPAD ) os << std::setfill(' '); //which is '0' or blank at this point.
144 }
145 
OutAdjustFill(std::ostream & os,const std::string & s,const int w,const int code)146 inline void OutAdjustFill(std::ostream& os, const std::string &s, const int w, const int code)
147 {
148    if ( code & fmtPAD ) os << std::setfill('0');
149    if ( ( code & fmtPAD ) && ((s.substr( 0, 1) == "-" ) || ( s.substr(0, 1) == "+" )) ) {  // preventing "00-1.00" or "00+1.00"
150      os << s.substr(0, 1) << std::right << std::setw(w) << s.substr(1);
151    }
152    else
153     os << std::setw(w) << std::right << s;
154    if ( code & fmtPAD ) os << std::setfill(' '); //which is '0' or blank at this point.
155 }
156 
157 template <typename T>
OutFixed(std::ostream & os,const T & val,const int w,const int d,const int code)158 void OutFixed(std::ostream& os, const T &val, const int w, const int d, const int code)
159 {
160   if (std::isfinite(val)) {
161    std::ostringstream oss;
162   if ( code & fmtSHOWPOS ) oss << std::showpos;
163    oss << std::fixed << std::setprecision(d) << val;
164    if (d==0) oss << ".";
165    if( w <= 0)
166      os << oss.str();
167    else if( oss.tellp() > w)
168      OutStars( os, w);
169    else if (code & fmtALIGN_LEFT)
170    {
171     os << std::left;
172     os << std::setw(w);
173     os << oss.str();
174     os << std::right;
175    }
176    else
177      OutFixFill(os, oss.str(), w, code);
178   } else if (std::isnan(val))    OutFixedNan<T>( os, val, w, code);
179   else OutFixedInf<T>( os, val, w, code);
180 }
181 
182 template <>
183 void OutFixed<DComplex>(std::ostream& os, const DComplex &val, const int w, const int d, const int code);
184 template <>
185 void OutFixed<DComplexDbl>(std::ostream& os, const DComplexDbl &val, const int w, const int d, const int code);
186 
187 
188 template <typename T>
OutScientific(std::ostream & os,const T & val,const int w,const int d,const int code)189 void OutScientific(std::ostream& os, const T &val, const int w, const int d, const int code) {
190  if (std::isfinite(val)) {
191   std::ostringstream oss;
192   // TODO: IDL handles both lower and upper case "E" (tracker item no. 3147155)
193   if ( code & fmtSHOWPOS ) oss << std::showpos;
194   if ( code & fmtUPPER ) oss << std::uppercase ;
195   oss << std::scientific << std::setprecision(d) << val;
196   if (w == 0 )
197    os << oss.str();
198   else if (oss.tellp() > w)
199    OutStars(os, w);
200   else if (code & fmtALIGN_LEFT)
201   {
202    os << std::left;
203    os << std::setw(w);
204    os << oss.str();
205    os << std::right;
206   }
207   else OutFixFill(os, oss.str(), w, code);
208  } else if (std::isnan(val)) OutFixedNan<T>(os, val, w, code);
209  else OutFixedInf<T>(os, val, w, code);
210 }
211 
212 template <>
213 void OutScientific<DComplex>( std::ostream& os, const DComplex &val, const int w, const int d, const int code);
214 template <>
215 void OutScientific<DComplexDbl>( std::ostream& os, const DComplexDbl &val, const int w, const int d, const int code);
216 
217 template <typename T>
OutAuto(std::ostream & os,const T & val,const int w,const int d,const int code=0)218 void OutAuto(std::ostream& os, const T &val, const int w, const int d, const int code=0) {
219 
220  if (std::isfinite(val)) {
221   std::ostringstream ossF;
222   int fixLen=1;
223 
224   if (val == T(0.0)) // handle 0.0
225   {
226    if (w <= 0) {
227     if ( code & fmtSHOWPOS ) os<<"+0"; else os<<"0";
228     return;
229    } //0 is FIXED
230    if (code & fmtSHOWPOS) ossF << std::showpos ;
231    if (code & fmtALIGN_LEFT) ossF << std::left; else ossF << std::right;
232    ossF << std::fixed << std::setprecision(d-1) << val;
233   } else {
234    int   powTen = static_cast<int>(std::floor( std::log10( std::abs( val))));
235    fixLen = powTen > 0 ? powTen+1 : 1; // number of digits before '.'
236 
237 
238    // as its used now, if w == 0 -> d != 0 (SetField())
239    // static cast here is needed for OS X, without we get a *linker* error
240    // (but only if GDL is compiled with Magick)
241 
242    if (code & fmtSHOWPOS) ossF << std::showpos ;
243    if (code & fmtALIGN_LEFT) ossF << std::left; else ossF << std::right;
244    if( w == 0 && (powTen < d && powTen > -d) && (val - std::floor( val) < std::pow( 10.0, static_cast<double>(-d))))
245      ossF << std::fixed << std::setprecision(0) << val;
246    else if( powTen == 0 || (powTen < d && powTen > -d+1)) //just like that.
247      {
248        //format for values between -1 and 1 adapts to the width as to show as many digits as possible
249        ossF << std::fixed << std::setprecision(d>fixLen?d-fixLen+((powTen<0)?-powTen:0):0) << val;
250        if( d <= fixLen && w>0) ossF << ".";
251      }
252    else
253      fixLen = 0; // marker to force scientific output
254  }
255   //get the scientific string
256   std::ostringstream ossS;
257   if (code & fmtSHOWPOS) ossS << std::showpos ;
258   if (code & fmtALIGN_LEFT) ossS << std::left; else ossS << std::right;
259   if ( code & fmtUPPER ) ossS << std::uppercase ;
260   if (w==0) ossS << std::setprecision(d>6?d:6) << val; //Auto w=0 special format: does not use "scientific" but default field-point notation.
261   else ossS << std::scientific << std::setprecision(d>0?d-1:0) << val;
262   // compare merits
263   if( fixLen == 0 || ossF.tellp() > ossS.tellp()) {
264     if( w == 0)
265       os << ossS.str();
266     else if( ossS.tellp() > w)
267       OutStars( os, w);
268     else if (code & fmtALIGN_LEFT)
269     {
270      os << std::left;
271      os << std::setw(w);
272      os << ossS.str();
273      os << std::right;
274     }
275     else
276       OutFixFill(os, ossS.str(), w, code);
277   }
278   else
279   {
280     if( w == 0)
281       os << ossF.str();
282     else if( ossF.tellp() > w)
283       OutStars( os, w);
284     else if (code & fmtALIGN_LEFT)
285     {
286      os << std::left;
287      os << std::setw(w);
288      os << ossF.str();
289      os << std::right;
290     }
291     else
292       OutFixFill(os, ossF.str(), w, code);
293   }
294  }
295  else if (std::isnan(val)) OutFixedNan<T>(os, val, w, code);
296  else OutFixedInf<T>(os, val, w, code);
297 }
298 
299 template <>
300 void OutAuto<DComplex>( std::ostream& os, const DComplex &val, const int w, const int d, const int code);
301 template <>
302 void OutAuto<DComplexDbl>( std::ostream& os, const DComplexDbl &val, const int w, const int d, const int code);
303 
304 template <typename T>
operator <<(std::ostream & os,const AsComplex<T> & a)305 std::ostream& operator<<(std::ostream& os, const AsComplex<T>& a)
306 {
307   os << "(";
308   OutAuto( os, a.flt.real(), a.width, a.prec, a.code);
309   os << ",";
310   OutAuto( os, a.flt.imag(), a.width, a.prec, a.code);
311   os << ")";
312   return os;
313 }
314 
315 #endif
316