00001
00008
00009
00010
00011
00012 #ifndef ECL_FORMATTERS_FLOATS_HPP_
00013 #define ECL_FORMATTERS_FLOATS_HPP_
00014
00015
00016
00017
00018
00019 #include <cstdio>
00020 #include <cstring>
00021 #include "common.hpp"
00022 #include <ecl/exceptions/standard_exception.hpp>
00023
00024 #if _MSC_VER
00025 #define snprintf _snprintf
00026 #endif
00027
00028
00029
00030
00031
00032 namespace ecl {
00033
00034
00035
00036
00042 enum FloatBase
00043 {
00044 Fixed,
00045 Sci,
00046 };
00047
00048 namespace interfaces {
00049
00050
00051
00052
00053
00060 template <typename Number>
00061 class FormatFloat {
00062 public:
00063
00064
00065
00073 FormatFloat(const int w = -1, const unsigned int p = 4, const ecl::Alignment a = NoAlign, const ecl::FloatBase b = Fixed) :
00074 prm_width(w),
00075 prm_precision(p),
00076 prm_alignment(a),
00077 prm_base(b),
00078 width_(&prm_width),
00079 precision_(&prm_precision),
00080 alignment_(&prm_alignment),
00081 base_(&prm_base),
00082 ready_to_format(false) {}
00083
00084 virtual ~FormatFloat() {}
00085
00086
00087
00088
00097 FormatFloat<Number>& precision(const unsigned int p) { *precision_ = p; return *this; }
00106 FormatFloat<Number>& width(const int w);
00115 FormatFloat<Number>& align(const ecl::Alignment a);
00124 FormatFloat<Number>& base(const ecl::FloatBase b);
00125
00126
00127
00128
00133 int precision() { return *precision_; }
00134
00140 int width() { return *width_; }
00141
00142
00143
00144
00151 FormatFloat<Number>& operator()(unsigned int p, const int w);
00160 FormatFloat<Number>& operator()(const unsigned int p, const int w, const ecl::Alignment align, const ecl::FloatBase b);
00161
00162
00163
00164
00175 FormatFloat<Number>& operator() (const Number n);
00176
00177
00178
00179
00186 FormatFloat<Number>& operator() (const Number n, const unsigned int p, const int w);
00195 FormatFloat<Number>& operator() (const Number n, const unsigned int p, const int w, const ecl::Alignment align, const ecl::FloatBase b);
00196
00197
00198
00199
00208 template <typename OutputStream, typename N>
00209 friend OutputStream& operator << (OutputStream& ostream, FormatFloat<N>& formatter) ecl_assert_throw_decl(StandardException);
00210
00211 protected:
00212
00213
00214
00215 int prm_width,tmp_width;
00216 int prm_precision,tmp_precision;
00217 ecl::Alignment prm_alignment,tmp_alignment;
00218 ecl::FloatBase prm_base,tmp_base;
00219 int *width_, *precision_;
00220 ecl::Alignment *alignment_;
00221 ecl::FloatBase *base_;
00222 bool ready_to_format;
00223 Number value_;
00224
00225
00226
00227
00228 template <typename OutputStream> void pad(int n, OutputStream &ostream) const;
00229 template <typename OutputStream> void prePad(int n, OutputStream &ostream) const;
00230 template <typename OutputStream> void postPad(int n, OutputStream &ostream) const;
00231
00232
00233
00234
00235 template <typename OutputStream> void formatFixed(OutputStream &ostream) const;
00236 template <typename OutputStream> void formatSci(OutputStream &ostream) const;
00237 };
00238
00239
00240
00241
00247 template <typename Number>
00248 FormatFloat<Number>& FormatFloat<Number>::base(const ecl::FloatBase b)
00249 {
00250 *base_ = b;
00251 return *this;
00252 }
00257 template <typename Number>
00258 FormatFloat<Number>& FormatFloat<Number>::width(const int w)
00259 {
00260 *width_ = w;
00261 if ( ( *width_ > 0 ) && ( *alignment_ == NoAlign ) )
00262 {
00263 *alignment_ = RightAlign;
00264 }
00265 return *this;
00266 }
00267
00273 template <typename Number>
00274 FormatFloat<Number>& FormatFloat<Number>::align(const ecl::Alignment a)
00275 {
00276 *alignment_ = a;
00277 if ( *alignment_ == NoAlign )
00278 {
00279 *width_ = 0;
00280 }
00281 return *this;
00282 }
00283
00284
00285
00286
00287
00288 template <typename Number>
00289 FormatFloat<Number>& FormatFloat<Number>::operator () (const unsigned int p, const int w)
00290 {
00291 width(w);
00292 precision(p);
00293 return *this;
00294 }
00295
00296 template <typename Number>
00297 FormatFloat<Number>& FormatFloat<Number>::operator () (const unsigned int p, const int w, const ecl::Alignment a, const ecl::FloatBase b)
00298 {
00299 width(w);
00300 precision(p);
00301 align(a);
00302 base(b);
00303 return *this;
00304 }
00305
00306
00307
00308
00309 template <typename Number>
00310 FormatFloat<Number>& FormatFloat<Number>::operator()(const Number n)
00311 {
00312 value_ = n;
00313 ready_to_format = true;
00314 return *this;
00315 }
00316
00317
00318
00319 template <typename Number>
00320 FormatFloat<Number>& FormatFloat<Number>::operator() (const Number n, unsigned int p, const int w)
00321 {
00322 width_ = &tmp_width;
00323 width(w);
00324
00325 precision_ = &tmp_precision;
00326 precision(p);
00327
00328 alignment_ = &tmp_alignment;
00329 align(prm_alignment);
00330
00331 base_ = &tmp_base;
00332 base(prm_base);
00333
00334 value_ = n;
00335 ready_to_format = true;
00336 return *this;
00337 }
00338
00339 template <typename Number>
00340 FormatFloat<Number>& FormatFloat<Number>::operator() (const Number n, const unsigned int p, const int w, const ecl::Alignment a, const ecl::FloatBase b)
00341 {
00342 width_ = &tmp_width;
00343 width(w);
00344
00345 precision_ = &tmp_precision;
00346 precision(p);
00347
00348 alignment_ = &tmp_alignment;
00349 align(a);
00350
00351 base_ = &tmp_base;
00352 base(b);
00353
00354 value_ = n;
00355 ready_to_format = true;
00356 return *this;
00357 }
00358
00359
00360
00361
00362
00363 template <typename Number>
00364 template <typename OutputStream>
00365 void FormatFloat<Number>::formatFixed(OutputStream &ostream) const
00366 {
00367 static char format_specifier[6] = "%.xff";
00368 if ( *precision_ < 10 ) {
00369 format_specifier[2] = '0'+*precision_;
00370 format_specifier[3] = 'f';
00371 format_specifier[4] = '\0';
00372 } else if ( *precision_ < 20 ) {
00373 format_specifier[2] = '1';
00374 format_specifier[3] = '0'+(*precision_ - 10);
00375 format_specifier[4] = 'f';
00376 } else {
00377 format_specifier[2] = '2';
00378 format_specifier[3] = '0';
00379 format_specifier[4] = 'f';
00380 }
00381 static const int buffer_size = 30;
00382 static char buffer[buffer_size];
00383
00384 snprintf(buffer, buffer_size, format_specifier, value_);
00385
00386
00387
00388
00389 int length = strlen(buffer);
00390 prePad(*width_ - length,ostream);
00391 ostream << buffer;
00392 postPad(*width_ - length,ostream);
00393 }
00394
00395 template <typename Number>
00396 template <typename OutputStream>
00397 void FormatFloat<Number>::formatSci(OutputStream &ostream) const
00398 {
00399 ostream << "Scientific format is not yet supported." << "\n";
00400 ostream.flush();
00401 }
00402
00403 template <typename Number>
00404 template <typename OutputStream>
00405 void FormatFloat<Number>::prePad(int n, OutputStream &ostream) const
00406 {
00407 if ( n <= 0 ) { return; }
00408 switch ( *alignment_ )
00409 {
00410 case ( NoAlign ) : { break; }
00411 case ( LeftAlign ) : { break; }
00412 case ( RightAlign ) : { pad(n,ostream); break; }
00413 case ( CentreAlign ) : { pad(n/2+ n%2,ostream); break; }
00414 default : break;
00415 }
00416 }
00417
00418 template <typename Number>
00419 template <typename OutputStream>
00420 void FormatFloat<Number>::postPad(int n, OutputStream &ostream) const
00421 {
00422 if ( n <= 0 ) { return; }
00423 switch ( *alignment_ )
00424 {
00425 case ( NoAlign ) : { break; }
00426 case ( LeftAlign ) : { pad(n,ostream); break; }
00427 case ( RightAlign ) : { break; }
00428 case ( CentreAlign ) : { pad(n/2,ostream); break; }
00429 default : break;
00430 }
00431 }
00432
00433 template <typename Number>
00434 template <typename OutputStream>
00435 void FormatFloat<Number>::pad(int n, OutputStream &ostream) const
00436 {
00437 for (int i = n; i > 0; --i )
00438 {
00439 ostream << ' ';
00440 }
00441 }
00442
00443
00444
00445
00446 template <typename OutputStream, typename N>
00447 OutputStream& operator << (OutputStream &ostream, FormatFloat<N>& formatter ) ecl_assert_throw_decl(StandardException)
00448 {
00449 bool ready = formatter.ready_to_format;
00450
00451 ecl_assert_throw(ready, StandardException(LOC,UsageError,"The formatter cannot print any data - "
00452 "either there is no data available, or you have tried to use the "
00453 "formatter more than once in a single streaming operation. "
00454 "C++ produces unspecified results when functors are used multiply "
00455 "in the same stream sequence, so this is not permitted here.") );
00456
00457 if ( ready )
00458 {
00459 switch(*(formatter.base_) )
00460 {
00461 case(Fixed) : {
00462 formatter.formatFixed(ostream);
00463 break;
00464 }
00465 case(Sci) : {
00466 formatter.formatSci(ostream);
00467 break;
00468 }
00469 }
00470
00471
00472 if ( formatter.width_ != &(formatter.prm_width) ) {
00473 formatter.width_ = &(formatter.prm_width);
00474 formatter.precision_ = &(formatter.prm_precision);
00475 formatter.alignment_ = &(formatter.prm_alignment);
00476 formatter.base_ = &(formatter.prm_base);
00477 }
00478 formatter.ready_to_format = false;
00479 }
00480 return ostream;
00481 }
00482
00483 }
00484
00485
00486
00487
00495 template <>
00496 class Format<float> : public interfaces::FormatFloat<float>
00497 {
00498 public:
00506 Format(int w = -1, int p = 4, Alignment a = NoAlign, FloatBase b = Fixed) :
00507 interfaces::FormatFloat<float>(w, p, a, b) {}
00508
00509 virtual ~Format() {}
00510 };
00518 template <>
00519 class Format<double> : public interfaces::FormatFloat<double>
00520 {
00521 public:
00529 Format(int w = -1, int p = 4, Alignment a = NoAlign, FloatBase b = Fixed) :
00530 interfaces::FormatFloat<double>(w, p, a, b) {
00531 }
00532
00533 virtual ~Format() {}
00534 };
00535
00536 };
00537
00538 #endif