$search
00001 00008 /***************************************************************************** 00009 ** Ifdefs 00010 *****************************************************************************/ 00011 00012 #ifndef ECL_FORMATTERS_FLOATS_HPP_ 00013 #define ECL_FORMATTERS_FLOATS_HPP_ 00014 00015 /***************************************************************************** 00016 ** Includes 00017 *****************************************************************************/ 00018 00019 #include <cstdio> // snprintf 00020 #include <cstring> // strlen 00021 #include "common.hpp" 00022 #include <ecl/exceptions/standard_exception.hpp> 00023 00024 /***************************************************************************** 00025 ** Namespaces 00026 *****************************************************************************/ 00027 00028 namespace ecl { 00029 00030 /***************************************************************************** 00031 ** Format Tags 00032 *****************************************************************************/ 00038 enum FloatBase 00039 { 00040 Fixed, 00041 Sci, 00042 }; 00043 00044 namespace interfaces { 00045 00046 /***************************************************************************** 00047 ** FormatFloat 00048 *****************************************************************************/ 00049 00056 template <typename Number> 00057 class FormatFloat { 00058 public: 00059 /****************************************** 00060 ** C&D's 00061 *******************************************/ 00069 FormatFloat(const int w = -1, const unsigned int p = 4, const ecl::Alignment a = NoAlign, const ecl::FloatBase b = Fixed) : 00070 prm_width(w), 00071 prm_precision(p), 00072 prm_alignment(a), 00073 prm_base(b), 00074 width_(&prm_width), 00075 precision_(&prm_precision), 00076 alignment_(&prm_alignment), 00077 base_(&prm_base), 00078 ready_to_format(false) {} 00079 00080 virtual ~FormatFloat() {} 00081 00082 /****************************************** 00083 ** Set Format Parameters 00084 *******************************************/ 00093 FormatFloat<Number>& precision(const unsigned int p) { *precision_ = p; return *this; } 00102 FormatFloat<Number>& width(const int w); 00111 FormatFloat<Number>& align(const ecl::Alignment a); 00120 FormatFloat<Number>& base(const ecl::FloatBase b); 00121 00122 /****************************************** 00123 ** Get Format Parameters 00124 *******************************************/ 00129 int precision() { return *precision_; } 00130 00136 int width() { return *width_; } 00137 00138 /****************************************** 00139 * Set Format Combinations 00140 ******************************************/ 00147 FormatFloat<Number>& operator()(unsigned int p, const int w); 00156 FormatFloat<Number>& operator()(const unsigned int p, const int w, const ecl::Alignment align, const ecl::FloatBase b); 00157 00158 /****************************************** 00159 ** Format a value 00160 *******************************************/ 00171 FormatFloat<Number>& operator() (const Number n); 00172 00173 /****************************************** 00174 ** Format for streaming 00175 *******************************************/ 00182 FormatFloat<Number>& operator() (const Number n, const unsigned int p, const int w); 00191 FormatFloat<Number>& operator() (const Number n, const unsigned int p, const int w, const ecl::Alignment align, const ecl::FloatBase b); 00192 00193 /****************************************** 00194 ** Insert the formatter into a stream 00195 *******************************************/ 00204 template <typename OutputStream, typename N> 00205 friend OutputStream& operator << (OutputStream& ostream, FormatFloat<N>& formatter) ecl_assert_throw_decl(StandardException); 00206 00207 protected: 00208 /****************************************** 00209 ** Parameters 00210 *******************************************/ 00211 int prm_width,tmp_width; 00212 int prm_precision,tmp_precision; 00213 ecl::Alignment prm_alignment,tmp_alignment; 00214 ecl::FloatBase prm_base,tmp_base; 00215 int *width_, *precision_; 00216 ecl::Alignment *alignment_; 00217 ecl::FloatBase *base_; 00218 bool ready_to_format; 00219 Number value_; 00220 00221 /****************************************** 00222 ** Padding 00223 *******************************************/ 00224 template <typename OutputStream> void pad(int n, OutputStream &ostream) const; 00225 template <typename OutputStream> void prePad(int n, OutputStream &ostream) const; 00226 template <typename OutputStream> void postPad(int n, OutputStream &ostream) const; 00227 00228 /****************************************** 00229 ** Formatter Functions 00230 *******************************************/ 00231 template <typename OutputStream> void formatFixed(OutputStream &ostream) const; 00232 template <typename OutputStream> void formatSci(OutputStream &ostream) const; 00233 }; 00234 00235 /***************************************************************************** 00236 * FormatFloat Implementation [single parameter configuration] 00237 *****************************************************************************/ 00243 template <typename Number> 00244 FormatFloat<Number>& FormatFloat<Number>::base(const ecl::FloatBase b) 00245 { 00246 *base_ = b; 00247 return *this; 00248 } 00253 template <typename Number> 00254 FormatFloat<Number>& FormatFloat<Number>::width(const int w) 00255 { 00256 *width_ = w; 00257 if ( ( *width_ > 0 ) && ( *alignment_ == NoAlign ) ) 00258 { 00259 *alignment_ = RightAlign; 00260 } 00261 return *this; 00262 } 00263 00269 template <typename Number> 00270 FormatFloat<Number>& FormatFloat<Number>::align(const ecl::Alignment a) 00271 { 00272 *alignment_ = a; 00273 if ( *alignment_ == NoAlign ) 00274 { 00275 *width_ = 0; 00276 } 00277 return *this; 00278 } 00279 00280 /***************************************************************************** 00281 * FormatFloat Implementation [format combination configuration] 00282 *****************************************************************************/ 00283 00284 template <typename Number> 00285 FormatFloat<Number>& FormatFloat<Number>::operator () (const unsigned int p, const int w) 00286 { 00287 width(w); 00288 precision(p); 00289 return *this; 00290 } 00291 00292 template <typename Number> 00293 FormatFloat<Number>& FormatFloat<Number>::operator () (const unsigned int p, const int w, const ecl::Alignment a, const ecl::FloatBase b) 00294 { 00295 width(w); 00296 precision(p); 00297 align(a); 00298 base(b); 00299 return *this; 00300 } 00301 00302 /***************************************************************************** 00303 * FormatFloat Implementation [value] 00304 *****************************************************************************/ 00305 template <typename Number> 00306 FormatFloat<Number>& FormatFloat<Number>::operator()(const Number n) 00307 { 00308 value_ = n; 00309 ready_to_format = true; 00310 return *this; 00311 } 00312 /***************************************************************************** 00313 * FormatFloat Implementation [temporary formatting] 00314 *****************************************************************************/ 00315 template <typename Number> 00316 FormatFloat<Number>& FormatFloat<Number>::operator() (const Number n, unsigned int p, const int w) 00317 { 00318 width_ = &tmp_width; 00319 width(w); 00320 00321 precision_ = &tmp_precision; 00322 precision(p); 00323 00324 alignment_ = &tmp_alignment; 00325 align(prm_alignment); 00326 00327 base_ = &tmp_base; 00328 base(prm_base); 00329 00330 value_ = n; 00331 ready_to_format = true; 00332 return *this; 00333 } 00334 00335 template <typename Number> 00336 FormatFloat<Number>& FormatFloat<Number>::operator() (const Number n, const unsigned int p, const int w, const ecl::Alignment a, const ecl::FloatBase b) 00337 { 00338 width_ = &tmp_width; 00339 width(w); 00340 00341 precision_ = &tmp_precision; 00342 precision(p); 00343 00344 alignment_ = &tmp_alignment; 00345 align(a); 00346 00347 base_ = &tmp_base; 00348 base(b); 00349 00350 value_ = n; 00351 ready_to_format = true; 00352 return *this; 00353 } 00354 00355 00356 /***************************************************************************** 00357 * FormatFloat Implementation [internal formatting] 00358 *****************************************************************************/ 00359 template <typename Number> 00360 template <typename OutputStream> 00361 void FormatFloat<Number>::formatFixed(OutputStream &ostream) const 00362 { 00363 static char format_specifier[6] = "%.xff"; 00364 if ( *precision_ < 10 ) { 00365 format_specifier[2] = '0'+*precision_; 00366 format_specifier[3] = 'f'; 00367 format_specifier[4] = '\0'; 00368 } else if ( *precision_ < 20 ) { 00369 format_specifier[2] = '1'; 00370 format_specifier[3] = '0'+(*precision_ - 10); 00371 format_specifier[4] = 'f'; 00372 } else { 00373 format_specifier[2] = '2'; 00374 format_specifier[3] = '0'; 00375 format_specifier[4] = 'f'; 00376 } 00377 static const int buffer_size = 30; 00378 static char buffer[buffer_size]; 00379 00380 snprintf(buffer, buffer_size, format_specifier, value_); 00381 00382 /****************************************** 00383 ** Streaming out 00384 *******************************************/ 00385 int length = strlen(buffer); 00386 prePad(*width_ - length,ostream); 00387 ostream << buffer; 00388 postPad(*width_ - length,ostream); 00389 } 00390 00391 template <typename Number> 00392 template <typename OutputStream> 00393 void FormatFloat<Number>::formatSci(OutputStream &ostream) const 00394 { 00395 ostream << "Scientific format is not yet supported." << "\n"; 00396 ostream.flush(); 00397 } 00398 00399 template <typename Number> 00400 template <typename OutputStream> 00401 void FormatFloat<Number>::prePad(int n, OutputStream &ostream) const 00402 { 00403 if ( n <= 0 ) { return; } 00404 switch ( *alignment_ ) 00405 { 00406 case ( NoAlign ) : { break; } 00407 case ( LeftAlign ) : { break; } 00408 case ( RightAlign ) : { pad(n,ostream); break; } 00409 case ( CentreAlign ) : { pad(n/2+ n%2,ostream); break; } // Add the remainder 00410 default : break; 00411 } 00412 } 00413 00414 template <typename Number> 00415 template <typename OutputStream> 00416 void FormatFloat<Number>::postPad(int n, OutputStream &ostream) const 00417 { 00418 if ( n <= 0 ) { return; } 00419 switch ( *alignment_ ) 00420 { 00421 case ( NoAlign ) : { break; } 00422 case ( LeftAlign ) : { pad(n,ostream); break; } 00423 case ( RightAlign ) : { break; } 00424 case ( CentreAlign ) : { pad(n/2,ostream); break; } // Do not add the remainder 00425 default : break; 00426 } 00427 } 00428 00429 template <typename Number> 00430 template <typename OutputStream> 00431 void FormatFloat<Number>::pad(int n, OutputStream &ostream) const 00432 { 00433 for (int i = n; i > 0; --i ) 00434 { 00435 ostream << ' '; 00436 } 00437 } 00438 00439 /***************************************************************************** 00440 * FormatFloat Implementation [streaming] 00441 *****************************************************************************/ 00442 template <typename OutputStream, typename N> 00443 OutputStream& operator << (OutputStream &ostream, FormatFloat<N>& formatter ) ecl_assert_throw_decl(StandardException) 00444 { 00445 bool ready = formatter.ready_to_format; 00446 00447 ecl_assert_throw(ready, StandardException(LOC,UsageError,"The formatter cannot print any data - " 00448 "either there is no data available, or you have tried to use the " 00449 "formatter more than once in a single streaming operation. " 00450 "C++ produces unspecified results when functors are used multiply " 00451 "in the same stream sequence, so this is not permitted here.") ); 00452 00453 if ( ready ) 00454 { 00455 switch(*(formatter.base_) ) 00456 { 00457 case(Fixed) : { 00458 formatter.formatFixed(ostream); 00459 break; 00460 } 00461 case(Sci) : { 00462 formatter.formatSci(ostream); 00463 break; 00464 } 00465 } 00466 00467 // Switch pointers back to prms if not already there. 00468 if ( formatter.width_ != &(formatter.prm_width) ) { 00469 formatter.width_ = &(formatter.prm_width); 00470 formatter.precision_ = &(formatter.prm_precision); 00471 formatter.alignment_ = &(formatter.prm_alignment); 00472 formatter.base_ = &(formatter.prm_base); 00473 } 00474 formatter.ready_to_format = false; 00475 } 00476 return ostream; 00477 } 00478 00479 } // namespace interfaces 00480 00481 /***************************************************************************** 00482 * Format Classes 00483 *****************************************************************************/ 00491 template <> 00492 class Format<float> : public interfaces::FormatFloat<float> 00493 { 00494 public: 00502 Format(int w = -1, int p = 4, Alignment a = NoAlign, FloatBase b = Fixed) : 00503 interfaces::FormatFloat<float>(w, p, a, b) {} 00504 00505 virtual ~Format() {} 00506 }; 00514 template <> 00515 class Format<double> : public interfaces::FormatFloat<double> 00516 { 00517 public: 00525 Format(int w = -1, int p = 4, Alignment a = NoAlign, FloatBase b = Fixed) : 00526 interfaces::FormatFloat<double>(w, p, a, b) { 00527 } 00528 00529 virtual ~Format() {} 00530 }; 00531 00532 }; // namespace ecl 00533 00534 #endif /*ECL_FORMATTERS_FLOATS_HPP_*/