floats.hpp
Go to the documentation of this file.
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_*/


ecl_formatters
Author(s): Daniel Stonier (d.stonier@gmail.com)
autogenerated on Thu Jan 2 2014 11:12:10