compose.hpp

00001 /* Defines String::compose(fmt, arg...) for easy, i18n-friendly
00002  * composition of strings.
00003  *
00004  * Version 1.0.
00005  *
00006  * Copyright (c) 2002 Ole Laursen <olau@hardworking.dk>.
00007  *
00008  * This library is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Lesser General Public License
00010  * as published by the Free Software Foundation; either version 2.1 of
00011  * the License, or (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with this library; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00021  * USA.
00022  */
00023 
00024 //
00025 // Basic usage is like
00026 //
00027 //   std::cout << String::compose("This is a %1x%2 matrix.", rows, cols);
00028 //
00029 // See http://www.cs.aau.dk/~olau/compose/ or the included README.compose for
00030 // more details.
00031 //
00032 
00033 #ifndef STRING_COMPOSE_H
00034 #define STRING_COMPOSE_H
00035 
00036 #include <sstream>
00037 #include <string>
00038 #include <list>
00039 #include <map>          // for multimap
00040 
00041 namespace StringPrivate
00042 {
00043   // the actual composition class - using string::compose is cleaner, so we
00044   // hide it here
00045   class Composition
00046   {
00047   public:
00048     // initialize and prepare format string on the form "text %1 text %2 etc."
00049     explicit Composition(std::string fmt);
00050 
00051     // supply an replacement argument starting from %1
00052     template <typename T>
00053     Composition &arg(const T &obj);
00054 
00055     // compose and return string
00056     std::string str() const;
00057 
00058   private:
00059     std::ostringstream os;
00060     int arg_no;
00061 
00062     // we store the output as a list - when the output string is requested, the
00063     // list is concatenated to a string; this way we can keep iterators into
00064     // the list instead of into a string where they're possibly invalidated on
00065     // inserting a specification string
00066     typedef std::list<std::string> output_list;
00067     output_list output;
00068 
00069     // the initial parse of the format string fills in the specification map
00070     // with positions for each of the various %?s
00071     typedef std::multimap<int, output_list::iterator> specification_map;
00072     specification_map specs;
00073   };
00074 
00075   // helper for converting spec string numbers
00076   inline int char_to_int(char c)
00077   {
00078     switch (c) {
00079     case '0': return 0;
00080     case '1': return 1;
00081     case '2': return 2;
00082     case '3': return 3;
00083     case '4': return 4;
00084     case '5': return 5;
00085     case '6': return 6;
00086     case '7': return 7;
00087     case '8': return 8;
00088     case '9': return 9;
00089     default: return -1000;
00090     }
00091   }
00092 
00093   inline bool is_number(int n)
00094   {
00095     switch (n) {
00096     case '0':
00097     case '1':
00098     case '2':
00099     case '3':
00100     case '4':
00101     case '5':
00102     case '6':
00103     case '7':
00104     case '8':
00105     case '9':
00106       return true;
00107     
00108     default:
00109       return false;
00110     }
00111   }
00112 
00113 
00114   // implementation of class Composition
00115   template <typename T>
00116   inline Composition &Composition::arg(const T &obj)
00117   {
00118     os << obj;
00119 
00120     std::string rep = os.str();
00121   
00122     if (!rep.empty())
00123     {       // manipulators don't produce output
00124       for (specification_map::const_iterator i = specs.lower_bound(arg_no),
00125          end = specs.upper_bound(arg_no); i != end; ++i)
00126          {
00127             output_list::iterator pos = i->second;
00128                 ++pos;
00129                 output.insert(pos, rep);
00130                 }
00131     
00132         os.str(std::string());
00133       //os.clear();
00134       ++arg_no;
00135     }
00136   
00137     return *this;
00138   }
00139 
00140   inline Composition::Composition(std::string fmt)
00141     : arg_no(1)
00142   {
00143     std::string::size_type b = 0, i = 0;
00144   
00145     // fill in output with the strings between the %1 %2 %3 etc. and
00146     // fill in specs with the positions
00147     while (i < fmt.length()) {
00148       if (fmt[i] == '%' && i + 1 < fmt.length()) {
00149     if (fmt[i + 1] == '%') {    // catch %%
00150       fmt.replace(i, 2, "%");
00151       ++i;
00152     }
00153     else if (is_number(fmt[i + 1])) { // aha! a spec!
00154       // save string
00155       output.push_back(fmt.substr(b, i - b));
00156     
00157       int n = 1;        // number of digits
00158       int spec_no = 0;
00159 
00160       do {
00161         spec_no += char_to_int(fmt[i + n]);
00162         spec_no *= 10;
00163         ++n;
00164       } while (i + n < fmt.length() && is_number(fmt[i + n]));
00165 
00166       spec_no /= 10;
00167       output_list::iterator pos = output.end();
00168       --pos;        // safe since we have just inserted a string>
00169     
00170       specs.insert(specification_map::value_type(spec_no, pos));
00171     
00172       // jump over spec string
00173       i += n;
00174       b = i;
00175     }
00176     else
00177       ++i;
00178       }
00179       else
00180     ++i;
00181     }
00182   
00183     if (i - b > 0)      // add the rest of the string
00184       output.push_back(fmt.substr(b, i - b));
00185   }
00186 
00187   inline std::string Composition::str() const
00188   {
00189     // assemble string
00190     std::string str;
00191   
00192     for (output_list::const_iterator i = output.begin(), end = output.end();
00193      i != end; ++i)
00194       str += *i;
00195   
00196     return str;
00197   }
00198 }
00199 
00200 // now for the real thing(s)
00201 namespace String 
00202 {
00203     inline std::string compose(const std::string &fmt)
00204     {
00205             StringPrivate::Composition c(fmt);
00206             return c.str();
00207     }
00208   // a series of functions which accept a format string on the form "text %1
00209   // more %2 less %3" and a number of templated parameters and spits out the
00210   // composited string
00211   template <typename T1>
00212   inline std::string compose(const std::string &fmt, const T1 &o1)
00213   {
00214     StringPrivate::Composition c(fmt);
00215     c.arg(o1);
00216     return c.str();
00217   }
00218 
00219   template <typename T1, typename T2>
00220   inline std::string compose(const std::string &fmt,
00221                  const T1 &o1, const T2 &o2)
00222   {
00223     StringPrivate::Composition c(fmt);
00224     c.arg(o1).arg(o2);
00225     return c.str();
00226   }
00227 
00228   template <typename T1, typename T2, typename T3>
00229   inline std::string compose(const std::string &fmt,
00230                  const T1 &o1, const T2 &o2, const T3 &o3)
00231   {
00232     StringPrivate::Composition c(fmt);
00233     c.arg(o1).arg(o2).arg(o3);
00234     return c.str();
00235   }
00236 
00237   template <typename T1, typename T2, typename T3, typename T4>
00238   inline std::string compose(const std::string &fmt,
00239                  const T1 &o1, const T2 &o2, const T3 &o3,
00240                  const T4 &o4)
00241   {
00242     StringPrivate::Composition c(fmt);
00243     c.arg(o1).arg(o2).arg(o3).arg(o4);
00244     return c.str();
00245   }
00246 
00247   template <typename T1, typename T2, typename T3, typename T4, typename T5>
00248   inline std::string compose(const std::string &fmt,
00249                  const T1 &o1, const T2 &o2, const T3 &o3,
00250                  const T4 &o4, const T5 &o5)
00251   {
00252     StringPrivate::Composition c(fmt);
00253     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5);
00254     return c.str();
00255   }
00256 
00257   template <typename T1, typename T2, typename T3, typename T4, typename T5,
00258         typename T6>
00259   inline std::string compose(const std::string &fmt,
00260                  const T1 &o1, const T2 &o2, const T3 &o3,
00261                  const T4 &o4, const T5 &o5, const T6 &o6)
00262   {
00263     StringPrivate::Composition c(fmt);
00264     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6);
00265     return c.str();
00266   }
00267 
00268   template <typename T1, typename T2, typename T3, typename T4, typename T5,
00269         typename T6, typename T7>
00270   inline std::string compose(const std::string &fmt,
00271                  const T1 &o1, const T2 &o2, const T3 &o3,
00272                  const T4 &o4, const T5 &o5, const T6 &o6,
00273                  const T7 &o7)
00274   {
00275     StringPrivate::Composition c(fmt);
00276     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7);
00277     return c.str();
00278   }
00279 
00280   template <typename T1, typename T2, typename T3, typename T4, typename T5,
00281         typename T6, typename T7, typename T8>
00282   inline std::string compose(const std::string &fmt,
00283                  const T1 &o1, const T2 &o2, const T3 &o3,
00284                  const T4 &o4, const T5 &o5, const T6 &o6,
00285                  const T7 &o7, const T8 &o8)
00286   {
00287     StringPrivate::Composition c(fmt);
00288     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8);
00289     return c.str();
00290   }
00291 
00292   template <typename T1, typename T2, typename T3, typename T4, typename T5,
00293         typename T6, typename T7, typename T8, typename T9>
00294   inline std::string compose(const std::string &fmt,
00295                  const T1 &o1, const T2 &o2, const T3 &o3,
00296                  const T4 &o4, const T5 &o5, const T6 &o6,
00297                  const T7 &o7, const T8 &o8, const T9 &o9)
00298   {
00299     StringPrivate::Composition c(fmt);
00300     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9);
00301     return c.str();
00302   }
00303 
00304   template <typename T1, typename T2, typename T3, typename T4, typename T5,
00305         typename T6, typename T7, typename T8, typename T9, typename T10>
00306   inline std::string compose(const std::string &fmt,
00307                  const T1 &o1, const T2 &o2, const T3 &o3,
00308                  const T4 &o4, const T5 &o5, const T6 &o6,
00309                  const T7 &o7, const T8 &o8, const T9 &o9,
00310                  const T10 &o10)
00311   {
00312     StringPrivate::Composition c(fmt);
00313     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
00314       .arg(o10);
00315     return c.str();
00316   }
00317   
00318   template <typename T1, typename T2, typename T3, typename T4, typename T5,
00319         typename T6, typename T7, typename T8, typename T9, typename T10,
00320         typename T11>
00321   inline std::string compose(const std::string &fmt,
00322                  const T1 &o1, const T2 &o2, const T3 &o3,
00323                  const T4 &o4, const T5 &o5, const T6 &o6,
00324                  const T7 &o7, const T8 &o8, const T9 &o9,
00325                  const T10 &o10, const T11 &o11)
00326   {
00327     StringPrivate::Composition c(fmt);
00328     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
00329       .arg(o10).arg(o11);
00330     return c.str();
00331   }
00332 
00333   template <typename T1, typename T2, typename T3, typename T4, typename T5,
00334         typename T6, typename T7, typename T8, typename T9, typename T10,
00335         typename T11, typename T12>
00336   inline std::string compose(const std::string &fmt,
00337                  const T1 &o1, const T2 &o2, const T3 &o3,
00338                  const T4 &o4, const T5 &o5, const T6 &o6,
00339                  const T7 &o7, const T8 &o8, const T9 &o9,
00340                  const T10 &o10, const T11 &o11, const T12 &o12)
00341   {
00342     StringPrivate::Composition c(fmt);
00343     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
00344       .arg(o10).arg(o11).arg(o12);
00345     return c.str();
00346   }
00347 
00348   template <typename T1, typename T2, typename T3, typename T4, typename T5,
00349         typename T6, typename T7, typename T8, typename T9, typename T10,
00350         typename T11, typename T12, typename T13>
00351   inline std::string compose(const std::string &fmt,
00352                  const T1 &o1, const T2 &o2, const T3 &o3,
00353                  const T4 &o4, const T5 &o5, const T6 &o6,
00354                  const T7 &o7, const T8 &o8, const T9 &o9,
00355                  const T10 &o10, const T11 &o11, const T12 &o12,
00356                  const T13 &o13)
00357   {
00358     StringPrivate::Composition c(fmt);
00359     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
00360       .arg(o10).arg(o11).arg(o12).arg(o13);
00361     return c.str();
00362   }
00363 
00364   template <typename T1, typename T2, typename T3, typename T4, typename T5,
00365         typename T6, typename T7, typename T8, typename T9, typename T10,
00366         typename T11, typename T12, typename T13, typename T14>
00367   inline std::string compose(const std::string &fmt,
00368                  const T1 &o1, const T2 &o2, const T3 &o3,
00369                  const T4 &o4, const T5 &o5, const T6 &o6,
00370                  const T7 &o7, const T8 &o8, const T9 &o9,
00371                  const T10 &o10, const T11 &o11, const T12 &o12,
00372                  const T13 &o13, const T14 &o14)
00373   {
00374     StringPrivate::Composition c(fmt);
00375     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
00376       .arg(o10).arg(o11).arg(o12).arg(o13).arg(o14);
00377     return c.str();
00378   }
00379 
00380   template <typename T1, typename T2, typename T3, typename T4, typename T5,
00381         typename T6, typename T7, typename T8, typename T9, typename T10,
00382         typename T11, typename T12, typename T13, typename T14,
00383         typename T15>
00384   inline std::string compose(const std::string &fmt,
00385                  const T1 &o1, const T2 &o2, const T3 &o3,
00386                  const T4 &o4, const T5 &o5, const T6 &o6,
00387                  const T7 &o7, const T8 &o8, const T9 &o9,
00388                  const T10 &o10, const T11 &o11, const T12 &o12,
00389                  const T13 &o13, const T14 &o14, const T15 &o15)
00390   {
00391     StringPrivate::Composition c(fmt);
00392     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
00393       .arg(o10).arg(o11).arg(o12).arg(o13).arg(o14).arg(o15);
00394     return c.str();
00395   }
00396 }
00397 
00398 
00399 #endif // STRING_COMPOSE_H

Generated on Sat Jun 23 16:07:23 2007 for Stechec/TBT by  doxygen 1.4.7