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