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
00025
00026
00027
00028 namespace ecl {
00029
00030
00031
00032
00038 enum FloatBase
00039 {
00040 Fixed,
00041 Sci,
00042 };
00043
00044 namespace interfaces {
00045
00046
00047
00048
00049
00056 template <typename Number>
00057 class FormatFloat {
00058 public:
00059
00060
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
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
00124
00129 int precision() { return *precision_; }
00130
00136 int width() { return *width_; }
00137
00138
00139
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
00160
00171 FormatFloat<Number>& operator() (const Number n);
00172
00173
00174
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
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
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
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
00230
00231 template <typename OutputStream> void formatFixed(OutputStream &ostream) const;
00232 template <typename OutputStream> void formatSci(OutputStream &ostream) const;
00233 };
00234
00235
00236
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
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
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
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
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
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; }
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; }
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
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
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 }
00480
00481
00482
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 };
00533
00534 #endif