fmtio.h

Go to the documentation of this file.
00001 #ifndef format_h_header_included_p
00002 #define format_h_header_included_p
00003 
00011 
00012 #include <portable_io.h>
00013 
00014 #include <iostream>
00015 #include <string>
00016 #include <sstream>
00017 #include <iomanip>
00018 
00019 // ========================================================================================
00020 
00021 namespace fmtio
00025 {
00026 
00027 // ========================================================================================
00028 
00029 namespace printableType
00042 {
00043   
00044 // ========================================================================================
00045 
00046   //
00047   //  The following struct declarations are unique to the style of printing of the data
00048   //  associated with the struct names.
00049   //
00050 
00051   struct Integral      {};  
00052   struct String        {};  
00053   struct StlString     {};  
00054   struct Float         {};  
00055   struct DoubleFloat   {};  
00056   struct UserDefined   {};  
00057   struct Unsigned      {};  
00058   struct Char          {};  
00059 
00060 
00061 // ========================================================================================
00062 
00063   //
00064   // The printability of types does not depend on its constness, so we need a way
00065   // to eliminate const from type signatures.  Ditto for volatile.
00066   //
00067 
00068 
00069 
00070   template<class T> struct devolify             { typedef T type; };  
00071   template<class T> struct devolify<T volatile> { typedef T type; };  
00072 
00073   template<class T> struct deconstify           { typedef typename devolify<T>::type type; }; 
00074   template<class T> struct deconstify<T const>  { typedef typename devolify<T>::type type; }; 
00075 
00076 // ========================================================================================
00077 
00078   template<int N> struct typeDetector;  
00089 
00090   template<> struct typeDetector<1> { typedef UserDefined type; }; // class objects
00091   template<> struct typeDetector<0> { typedef Integral    type; }; // enums
00092 
00093   template<class Type>
00094   struct isClassType
00099   {
00100     
00101     template <typename ClassType>
00102     static short fun(void (ClassType::*)());
00103     
00104     template <typename NonClassType>   // this has to be a template
00105     static char fun(...);
00106   
00107     enum { value = sizeof(fun<Type>(0)) == sizeof(short) };
00108   };
00109 
00110 
00111 
00112   template<class T>
00113   struct classification
00122   {
00123     typedef typename typeDetector< isClassType< typename deconstify<T>::type >::value >::type  printableClass;
00124   };
00125 
00126 
00127 
00128 // ========================================================================================
00129 
00130 
00131   template<class T>
00132   typename classification< typename deconstify<T>::type >::printableClass 
00133   classifier(T const &t) 
00134     
00135 
00136 
00137 
00138 
00139 
00140 
00141 
00142 
00143 
00144   { 
00145     return typename classification< typename deconstify<T>::type >::printableClass(); 
00146   }
00147 
00148 // ========================================================================================
00149 
00150   template<class T> struct classification<T *>    { typedef Integral printableClass; }; 
00156 
00157 
00158 // ========================================================================================
00159 
00160   template<> struct classification<int>           { typedef Integral printableClass; };  
00161   template<> struct classification<short>         { typedef Integral printableClass; };  
00162   template<> struct classification<long>          { typedef Integral printableClass; };  
00163   template<> struct classification<long long>     { typedef Integral printableClass; };  
00164 
00165   template<> struct classification<unsigned int>           { typedef Unsigned printableClass; };  
00166   template<> struct classification<unsigned short>         { typedef Unsigned printableClass; };  
00167   template<> struct classification<unsigned long>          { typedef Unsigned printableClass; };  
00168   template<> struct classification<unsigned long long>     { typedef Unsigned printableClass; };  
00169 
00170 
00171 // ========================================================================================
00172 
00173   template<> struct classification<char>          { typedef Char     printableClass; };  
00174   template<> struct classification<unsigned char> { typedef Char     printableClass; };  
00175 
00176 // ========================================================================================
00177 
00178   template<> struct classification<float>         { typedef Float       printableClass; }; 
00179   template<> struct classification<double>        { typedef DoubleFloat printableClass; }; 
00180   
00181 // ========================================================================================
00182 
00183   // note:  g++ is weird about quoted strings -- they don't seem to match template name<char const *>
00184   // and they don't seem to match template name< char const (&)[N] >, so I have worked around this
00185   // in the cs class by making operator% handle char const * as a special case.  See below.
00186 
00187   template<> struct classification<char*>                { typedef String       printableClass; }; 
00188   template<> struct classification<unsigned char*>       { typedef String       printableClass; }; 
00189   template<> struct classification<unsigned char const *>{ typedef String       printableClass; }; 
00190   template<> struct classification<std::string>          { typedef StlString    printableClass; }; 
00191 
00192 // ========================================================================================
00193 
00194   struct Exception
00196   {
00197      char expectedFormat_;
00198 
00199      char const *foundType_;
00200 
00201      Exception(char e, char const *found)
00202      : expectedFormat_(e)
00203      , foundType_(found)
00204      {
00205      }
00206 
00207   };
00208 };
00209 
00210 // ========================================================================================
00211 
00212 class cs
00322 {
00323     // ---------------------------------------------------------------------------------------
00324 
00325      mutable char expectedFormat_;  // %<expectedFormat_> in control string language
00326 
00327      mutable char const *cs_;
00328 
00329      mutable std::string buffer_;
00330 
00331      mutable int fieldWidth_;
00332      mutable int fillChar_;
00333      mutable int precision_;
00334      mutable int left_;
00335 
00336     // ---------------------------------------------------------------------------------------
00337 
00338      void reset() const
00340      {
00341        left_       = 0;
00342        fieldWidth_ = 0;
00343        fillChar_   = 0;
00344        precision_  = 0;
00345      }
00346 
00347 
00348 public:
00349 
00350     // ---------------------------------------------------------------------------------------
00351 
00352      operator std::string const &() const { return buffer_; }
00353 
00354     // ---------------------------------------------------------------------------------------
00355 
00356      cs(char const *cs)
00368      : expectedFormat_(*cs)
00369      , cs_(cs)
00370      {
00371        advanceFormat(); 
00372      }
00373 
00374      ~cs()
00375      {
00376        if(expectedFormat_ != '?' )
00377        {
00378          // should have been out of formatting directives by now
00379 
00380          throw  printableType::Exception(expectedFormat_, "<EXPECTED END OF FORMAT STRING>");  
00381 
00382        }
00383      }
00384 
00385 private:
00386 
00387     // ---------------------------------------------------------------------------------------
00388 
00389      void advanceFormat() const
00396      {
00397        reset();  // field formatting options
00398 
00399        // skip non-format text before % and handle %%
00400 
00401        while(*cs_)                     // outer loop to handle repeats after %%
00402        {
00403 
00404          while(*cs_ && *cs_ != '%')   // normal case -- just print anything not a % spec
00405            buffer_ += *cs_++;
00406   
00407          if(*cs_ == '%')              // ignore the % of a spec
00408            ++cs_;
00409 
00410          if(*cs_ == '%')
00411          {
00412            buffer_ += '%';
00413            ++cs_;
00414          }
00415          else
00416            break;
00417        }
00418 
00419        // the leading % is already removed before we get here
00420 
00421        expectedFormat_ = '?';  // set up an invalid format as the norm -- superseed
00422                                // the invalid state only if a properly formatted
00423                                // control string is found.
00424 
00425        if(*cs_ == '-')
00426        {
00427          left_ = 1;            // handle left justification
00428          ++cs_;
00429        }
00430 
00431        if(*cs_ == '0')
00432        {
00433          fillChar_ = '0';      // handle leading zeros
00434          ++cs_;
00435        }
00436 
00437        if(*cs_ >= '0' && *cs_ <='9')
00438        {
00439          fieldWidth_ = 0;                    // handle field widths 
00440 
00441          while(*cs_ >= '0' && *cs_ <= '9')
00442          {
00443            fieldWidth_ *= 10;
00444            fieldWidth_ += *cs_++ -'0';
00445          }
00446        }
00447 
00448        if(*cs_ == '.')
00449        {
00450          ++cs_;                             // handle precision
00451 
00452          precision_ = 0;
00453 
00454          while(*cs_ >= '0' && *cs_ <= '9')
00455          {
00456            precision_ *= 10;
00457            precision_ += *cs_++ -'0';
00458          }
00459 
00460        }
00461 
00462        // now, handle the formatting character:  u, x, d, o, s, c, U (U is user defined)
00463 
00464        if(*cs_)
00465        {
00466          expectedFormat_ = *cs_++;
00467        }
00468        
00469      }
00470 
00471 
00472     // ---------------------------------------------------------------------------------------
00473      void outputIntegral( long long t ) const
00477      {
00478          char b[100];
00479 
00480          char cs[40];
00481 
00482          char *scan = &cs[0];
00483 
00484          {
00485   
00486            *scan++ = '%';  // setup control string for converison
00487   
00488            if(left_)
00489              *scan++ = '-';
00490 
00491            if(fillChar_ == '0')
00492              *scan++ = '0';
00493 
00494            if(fieldWidth_)
00495            {
00496              char buffer[40];
00497 
00498              snprintf(buffer, 40, "%d", fieldWidth_);
00499 
00500              char *input = &buffer[0];
00501 
00502              while(*input)
00503                *scan++ = *input++;
00504 
00505            }
00506 
00507            if(precision_)
00508            {
00509              *scan++ = '.';
00510 
00511              char buffer[40];
00512 
00513              snprintf(buffer, 40, "%d", precision_);
00514 
00515              char *input = &buffer[0];
00516 
00517              while(*input)
00518                *scan++ = *input++;
00519 
00520            }
00521          }
00522 
00523          *scan++ = 'l';                  // always use long long output data (see cast below)
00524          *scan++ = 'l';
00525          *scan++ = expectedFormat_;
00526          *scan++ = 0;
00527 
00528 
00529          snprintf(b, sizeof(b), cs, (long long)t);
00530 
00531          buffer_ += b;
00532 
00533      }
00534 
00535     // ---------------------------------------------------------------------------------------
00536      bool isIntegralFormat() const
00540      {
00541        return    expectedFormat_ == 'd'
00542               || expectedFormat_ == 'u'
00543               || expectedFormat_ == 'o'
00544               || expectedFormat_ == 'x'
00545               ;
00546      }
00547 
00548     // ---------------------------------------------------------------------------------------
00549      template<class T>  void output(T const &t, printableType::Integral) const
00553 
00554      { 
00555          if( !isIntegralFormat() )
00556          {
00557            throw  printableType::Exception(expectedFormat_, "Integral");  
00558          }
00559 
00560          outputIntegral((long long)t);
00561 
00562      }
00563 
00564     // ---------------------------------------------------------------------------------------
00565      template<class T>  void output(T const &t, printableType::Unsigned)    const 
00569      { 
00570          if( !isIntegralFormat() )
00571          {
00572            throw  printableType::Exception(expectedFormat_, "Unsigned");  
00573          }
00574 
00575          outputIntegral((long long)t);
00576 
00577      }
00578 
00579     // ---------------------------------------------------------------------------------------
00580      template<class T>  void output(T const &t, printableType::Char)        const 
00584      {
00585          if(expectedFormat_ == 'c')
00586          {
00587               buffer_ += (t);
00588          }
00589          else
00590          if( !isIntegralFormat() )
00591          {
00592            throw  printableType::Exception(expectedFormat_, "Char");
00593          }
00594          else
00595            outputIntegral(t);
00596      }
00597 
00598 
00599     // ---------------------------------------------------------------------------------------
00600      template<class T>  void output(T const &t, printableType::String)      const 
00604      { 
00605          if(   expectedFormat_ != 's'
00606            )
00607          {
00608            throw  printableType::Exception(expectedFormat_, "String");
00609          }
00610 
00611        
00612          buffer_ += (char const *)(t);
00613      }
00614 
00615     // ---------------------------------------------------------------------------------------
00616      template<class T>  void output(T const &t, printableType::StlString)   const 
00620      { 
00621          if(   expectedFormat_ != 's'
00622            )
00623          {
00624            throw  printableType::Exception(expectedFormat_, "std::string");
00625          }
00626 
00627 
00628          buffer_ += t;
00629 
00630      }
00631 
00632     // ---------------------------------------------------------------------------------------
00633      void outputFloat(double d) const
00637      {
00638          std::stringstream tmp;
00639 
00640          if(left_)
00641          {
00642            tmp << std::left;
00643          }
00644 
00645          if(fillChar_)
00646          {
00647            tmp << std::setfill(char(fillChar_));
00648          }
00649 
00650          if(fieldWidth_)
00651          {
00652              tmp << std::setw(fieldWidth_);
00653          }
00654 
00655          if(precision_)
00656          {
00657              tmp << std::setprecision(precision_);
00658          }
00659          
00660          tmp << d;
00661 
00662          buffer_ +=tmp.str();
00663      }
00664 
00665     // ---------------------------------------------------------------------------------------
00666      template<class T>  void output(T const &t, printableType::Float)       const 
00670      { 
00671          if(   expectedFormat_ != 'f'
00672            )
00673          {
00674            throw  printableType::Exception(expectedFormat_, "Float");
00675          }
00676 
00677          outputFloat(t);
00678 
00679      }
00680 
00681     // ---------------------------------------------------------------------------------------
00682      template<class T>  void output(T const &t, printableType::DoubleFloat) const 
00686      { 
00687          if(   expectedFormat_ != 'f'
00688            )
00689          {
00690            throw  printableType::Exception(expectedFormat_, "DoubleFloat");
00691          }
00692 
00693          outputFloat(t);
00694 
00695      }
00696 
00697     // ---------------------------------------------------------------------------------------
00698      template<class T>  void output(T const &t, printableType::UserDefined) const 
00702      { 
00703          if(   expectedFormat_ != 'U'
00704            )
00705          {
00706            throw  printableType::Exception(expectedFormat_, "UserDefined");
00707          }
00708 
00709          std::stringstream tmp;
00710 
00711          if(left_)
00712          {
00713            tmp << std::left;
00714          }
00715 
00716          if(fillChar_)
00717          {
00718            tmp << std::setfill(char(fillChar_));
00719          }
00720 
00721          tmp << std::setw(fieldWidth_) << std::setprecision(precision_) << t;
00722 
00723          buffer_ += tmp.str();
00724      }
00725 
00726 public:
00727 
00728     // ---------------------------------------------------------------------------------------
00729      template< class T >
00730      cs const &operator% ( T const &rhs ) const
00743 
00744      {
00745         output(rhs, printableType::classifier(rhs));
00746 
00747         advanceFormat();
00748 
00749         return *this;
00750      }
00751 
00752     // ---------------------------------------------------------------------------------------
00753      cs const &operator% ( char const *rhs ) const
00766 
00767      {
00768         output(rhs, printableType::String() );
00769 
00770         advanceFormat();
00771 
00772         return *this;
00773      }
00774 
00775     // ---------------------------------------------------------------------------------------
00776      template<class T, int N>
00777      cs const &operator% ( T const (&rhs)[N] ) const
00792 
00793      {
00794         output(rhs, printableType::Integral() );
00795 
00796         advanceFormat();
00797 
00798         return *this;
00799      }
00800 
00801 
00802     size_t size() const { return buffer_.size(); }
00803 
00804 private:
00805 
00806     // ---------------------------------------------------------------------------------------
00807 
00808     cs(cs const &);  // not implemented:  If you get an error on this line of code, 
00809                      // you probably wrote code that looks like this:  
00810                      //
00811                      //     cout << cs("...") << something << endl;
00812                      //                             ^^^^
00813                      //  No can do big guy!  Use %, not <<
00814 
00815 
00816 
00817      template< class T > void operator<< ( T & ) const;   // not implemented
00818 
00819 };
00820 
00821 // ===========================================================================================
00822 
00823 inline std::ostream &operator<< (std::ostream &s, cs const &fmt)
00824 {
00825    if(s.good())
00826    {
00827    
00828       s << (std::string const &) fmt;
00829 
00830    }
00831 
00832    return s;
00833 }
00834 
00835 // ===========================================================================================
00836 // ===========================================================================================
00837 
00838 }
00839 #endif
Generated on Wed Feb 29 22:50:04 2012 for CXXUtilities by  doxygen 1.6.3