fmtd.h

Go to the documentation of this file.
00001 #ifndef CXX_fmtd_header_included_p
00002 #define CXX_fmtd_header_included_p
00003 
00004 #include <iostream>
00005 #include <portable_io.h>
00006 #include <cxxtls/classTraits.h>
00007 
00008 namespace cxxtls
00009 {
00010 
00015 
00016 
00017 namespace fmtdalgo
00022 {
00023   // you can't specialize a template inside a class body, so this namespace is required 
00024   // to perform the specializations below.
00025 
00026   // helper --------------------------------------------------------------------
00027   inline void int2ascii(char *&scan, int d)
00034   {
00035     char buffer[26];
00036 
00037     char *end = &buffer[25];
00038 
00039     *end = 0;
00040 
00041     char *ptr = end;
00042 
00043     while(d)
00044     {
00045       *(--ptr) = '0' + (d%10);
00046       d /= 10;
00047     }
00048 
00049     while(ptr != end)
00050       *scan++ = *ptr++;
00051 
00052 
00053   }
00054 
00055   // helper --------------------------------------------------------------------
00056   inline void setup(char *&scan, 
00057                     int    fieldWidth, 
00058                     int    precision, 
00059                     bool   lJust, 
00060                     bool   padding, 
00061                     char   pad
00062                    )
00066   {
00067        *scan++ = '%';
00068 
00069        if(lJust && fieldWidth != 0)
00070          *scan++ = '-';
00071 
00072        if(!lJust && pad == '0')
00073          *scan++ = '0';
00074 
00075        if(fieldWidth)
00076          int2ascii(scan, fieldWidth);
00077 
00078        if(precision)
00079        {
00080          *scan++ = '.';
00081          int2ascii(scan, precision);
00082        }
00083   }
00084 
00085   // formatter --------------------------------------------------------------------
00086   template<class T, int fieldWidth, int precision, int lJust, int padding, int pad, int base, int errchr>
00087   struct StringFormatter
00095   {
00096 
00097     size_t operator()(std::string const &v,
00098                       char              *buffer,
00099                       int                buffsize
00100                      )
00101     {
00102       return (*this)(v.c_str(), buffer, buffsize);
00103     }
00104 
00105 
00106     size_t operator() (char const *v,
00107                      char      *buffer, 
00108                      int        buffsize
00109                     )
00117     {
00118        char cs[100];
00119 
00120        char *scan = &cs[0];
00121 
00122        setup(scan,
00123              fieldWidth, 
00124              precision, 
00125              lJust, 
00126              padding, 
00127              pad
00128             );
00129 
00130 
00131        *scan++ = 's';
00132 
00133        *scan++ = 0;
00134 
00135        size_t bytesWritten = snprintf(buffer, buffsize, cs, v);
00136 
00137        size_t errorThreshold = buffsize;
00138 
00139        if(fieldWidth)
00140          errorThreshold = fieldWidth;
00141 
00142        if( bytesWritten > errorThreshold)
00143        {
00144          std::fill_n(buffer, fieldWidth, errchr);
00145          buffer[fieldWidth] = 0;
00146 
00147          bytesWritten = fieldWidth;
00148        }
00149 
00150        return bytesWritten;
00151 
00152     }
00153 
00154   };
00155 
00156 
00157 
00158   // -------------------------------------------------------------------------
00159   template<class T, int fieldWidth, int precision, int lJust, int padding, int pad, int base, int errchr>
00160   struct FloatFormatter
00165   {
00166     size_t operator() (T const   &v, 
00167                      char      *buffer, 
00168                      int        buffsize
00169                     )
00177     {
00178        char cs[100];
00179 
00180        char *scan = &cs[0];
00181 
00182        setup(scan,
00183              fieldWidth, 
00184              precision, 
00185              lJust, 
00186              padding, 
00187              pad
00188             );
00189 
00190 
00191        *scan++ = 'L';
00192 
00193        if(!lJust && precision)
00194           *scan++ = 'f';
00195        else
00196           *scan++ = 'g';
00197 
00198        *scan++ = 0;
00199 
00200        long double x = v;
00201 
00202        size_t bytesWritten = snprintf(buffer, buffsize, cs, x);
00203 
00204        size_t errorThreshold = buffsize;
00205 
00206        if(fieldWidth)
00207          errorThreshold = fieldWidth;
00208 
00209        if( bytesWritten > errorThreshold)
00210        {
00211          std::fill_n(buffer, fieldWidth, errchr);
00212          buffer[fieldWidth] = 0;
00213 
00214          bytesWritten = fieldWidth;
00215        }
00216 
00217        return bytesWritten;
00218 
00219     }
00220 
00221   };
00222 
00223   // -------------------------------------------------------------------------
00224   template<class T, int fieldWidth, int precision, int lJust, int padding, int pad, int base, int errchr>
00225   struct IntFormatter
00230   {
00231     size_t operator() (T const  &v, 
00232                      char     *buffer, 
00233                      int       buffsize 
00234                     )
00242     {
00243        char cs[100];
00244 
00245        char *scan = &cs[0];
00246 
00247        setup(scan,
00248              fieldWidth, 
00249              precision, 
00250              lJust, 
00251              padding, 
00252              pad
00253             );
00254 
00255 
00256        *scan++ = 'l';
00257        *scan++ = 'l';
00258 
00259        if(base == 16)
00260          *scan++ = 'x';
00261        else
00262        if(base == 8)
00263          *scan++ = 'o';
00264        else
00265        if(isUnsignedType<T>::value)
00266          *scan++ = 'u';
00267        else
00268          *scan++ = 'd';
00269 
00270        *scan++ = 0;
00271 
00272        long long x = v;
00273 
00274        size_t errorThreshold = buffsize;
00275 
00276        if(fieldWidth)
00277          errorThreshold = fieldWidth;
00278 
00279        size_t rv;
00280 
00281        if( (rv = snprintf(buffer, buffsize, cs, x) ) > errorThreshold)
00282        {
00283          std::fill_n(buffer, fieldWidth, errchr);
00284          buffer[fieldWidth] = 0;
00285          rv = fieldWidth;
00286        }
00287 
00288        return rv;
00289     }
00290   };
00291 
00292   // =========================================================================
00293   template<int N, 
00294            class T, 
00295            int fieldWidth, 
00296            int precision, 
00297            int lJust, 
00298            int padding, 
00299            int pad, 
00300            int base, 
00301            int errchr
00302           > 
00303   struct algo;
00307 
00308 
00309   // =========================================================================
00310   template<class T, 
00311            int fieldWidth, 
00312            int precision, 
00313            int lJust, 
00314            int padding, 
00315            int pad, 
00316            int base, 
00317            int errchr
00318           > 
00319   struct algo<bctIntegralType,
00320               T, 
00321               fieldWidth, 
00322               precision, 
00323               lJust, 
00324               padding, 
00325               pad, 
00326               base, 
00327               errchr
00328              >
00332   { 
00333     typedef IntFormatter<T, 
00334                          fieldWidth, 
00335                          precision, 
00336                          lJust, 
00337                          padding, 
00338                          pad, 
00339                          base, 
00340                          errchr
00341                         > 
00342                         type;   
00343   };
00344 
00345   // ==========================================================================
00346   template<class T, 
00347            int   fieldWidth, 
00348            int   precision, 
00349            int   lJust, 
00350            int   padding, 
00351            int   pad, 
00352            int   base, 
00353            int   errchr
00354           > 
00355   struct algo<bctFloatType, 
00356               T, 
00357               fieldWidth, 
00358               precision, 
00359               lJust, 
00360               padding, 
00361               pad, 
00362               base, 
00363               errchr
00364              >    
00368   { 
00369     typedef FloatFormatter<T, 
00370                            fieldWidth, 
00371                            precision, 
00372                            lJust, 
00373                            padding, 
00374                            pad, 
00375                            base, 
00376                            errchr
00377                           > type; 
00378   };
00379 
00380   // -------------------------------------------------------------------------
00381   template<
00382            int   fieldWidth, 
00383            int   precision, 
00384            int   lJust, 
00385            int   padding, 
00386            int   pad, 
00387            int   base, 
00388            int   errchr
00389           > 
00390   struct algo<bctClassType,   // parm named N
00391               char const *,   // parm named T
00392               fieldWidth, 
00393               precision, 
00394               lJust, 
00395               padding, 
00396               pad, 
00397               base, 
00398               errchr
00399              >    
00403   { 
00404     typedef StringFormatter<std::string,  // ignored but needed
00405                            fieldWidth, 
00406                            precision, 
00407                            lJust, 
00408                            padding, 
00409                            pad, 
00410                            base, 
00411                            errchr
00412                           > type; 
00413   };
00414 
00415 
00416 
00417 };
00418 
00419 
00420 template<int WIDTH=0, int PRECISION=0, int PAD=' ', int BASE=10, int ERRCHR='@'>
00421 struct fmtd
00492 {
00493   // implementation details
00494 
00495   // interface -----------------------------------------------------------------
00496   enum constants  { MIN_WIDTH   = 25,
00497                     BUFF_SAFETY = 10,
00498                     POS_WIDTH   = (WIDTH < 0) ? -WIDTH : WIDTH,
00499                     FIELD_WIDTH = (PRECISION > POS_WIDTH ? PRECISION : ( (POS_WIDTH == 0) ? 0 : POS_WIDTH ) ),
00500                     BUFF_SIZE   = FIELD_WIDTH + BUFF_SAFETY,
00501                     PADDING     = (POS_WIDTH != 0) || (PRECISION != 0),
00502                     LJUST       = (WIDTH< 1),
00503                   };
00504 
00505 private:
00506 
00507   char buffer_[ BUFF_SIZE ];
00508 
00509   size_t size_;
00510 
00511 public:
00512 
00513   // interface -----------------------------------------------------------------
00514 
00515   template<class T>
00516   fmtd(T const &v)
00517   {
00518     using namespace fmtdalgo;
00519 
00520     typename algo< basicClassType<T>::value, T, FIELD_WIDTH, PRECISION, LJUST, PADDING, PAD, BASE, ERRCHR>::type doit;
00521        // If the above line of code fails to compile it is most likely
00522        // related to the type, T, that you are attempting to use as a 
00523        // parameter to ftmd<>(T)! 
00524        // 
00525        // fmtd<> only supports the same data types that sprintf supports!
00526        //
00527        // Well, ok, it supports std::string too! 
00528 
00529     size_ = doit(v,buffer_,BUFF_SIZE);
00530   }
00531 
00532   // interface -----------------------------------------------------------------
00533 
00534   fmtd(char const *s)
00535   {
00536     using namespace fmtdalgo;
00537 
00538     typename algo< bctClassType, char const *, FIELD_WIDTH, PRECISION, LJUST, PADDING, PAD, BASE, ERRCHR>::type doit;
00539 
00540     size_ = doit(s,buffer_,BUFF_SIZE);
00541   }
00542 
00543   // interface -----------------------------------------------------------------
00544 
00545   fmtd(std::string const &s)
00546   {
00547     using namespace fmtdalgo;
00548 
00549     typename algo< bctClassType, char const *, FIELD_WIDTH, PRECISION, LJUST, PADDING, PAD, BASE, ERRCHR>::type doit;
00550 
00551     size_ = doit(s.c_str(),buffer_,BUFF_SIZE);
00552   }
00553 
00554 
00555 
00556   // interface -----------------------------------------------------------------
00557 
00558   operator char const *() const { return buffer_; }
00559 
00560   // interface -----------------------------------------------------------------
00561 
00562   size_t size() const { return size_; }
00563 
00564 
00565   // interface -----------------------------------------------------------------
00566 
00567   friend std::ostream &operator<< ( std::ostream &s, fmtd const &f) 
00568   { 
00569      s << f.buffer_; 
00570      return s;
00571   }
00572 
00573 
00574 };
00575 
00576 } // namespace cxxtls
00577 #endif
Generated on Wed Feb 29 22:50:04 2012 for CXXUtilities by  doxygen 1.6.3