Rapicorn - Experimental UI Toolkit - Source Code  13.07.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
formatter.hh
Go to the documentation of this file.
00001  // Licensed GNU LGPL v3 or later: http://www.gnu.org/licenses/lgpl.html
00002 #ifndef __RAPICORN_FORMATTER_HH__
00003 #define __RAPICORN_FORMATTER_HH__
00004 
00005 #include <rcore/cxxaux.hh>
00006 #include <rcore/aida.hh>
00007 #include <sstream>
00008 
00009 namespace Rapicorn {
00010 namespace Lib { // Namespace for implementation internals
00011 
00012 // == StringFormatter ==
00014 
00021 class StringFormatter {
00022   typedef long long signed int LLong;
00023   typedef long long unsigned int ULLong;
00024   typedef long double LDouble;
00025   struct FormatArg {
00026     union { LDouble d; double f; signed char i1; short i2; int i4; long i6; LLong i8; void *p; const char *s; };
00027     char kind; // f d i u p s
00028   };
00029   inline void assign (FormatArg &farg, bool               arg) { farg.kind = '1'; farg.i1 = arg; }
00030   inline void assign (FormatArg &farg, char               arg) { farg.kind = '1'; farg.i1 = arg; }
00031   inline void assign (FormatArg &farg, signed char        arg) { farg.kind = '1'; farg.i1 = arg; }
00032   inline void assign (FormatArg &farg, unsigned char      arg) { farg.kind = '1'; farg.i1 = arg; }
00033 #if __SIZEOF_WCHAR_T__ == 1
00034   inline void assign (FormatArg &farg, wchar_t            arg) { farg.kind = '1'; farg.i1 = arg; }
00035 #endif
00036   inline void assign (FormatArg &farg, short              arg) { farg.kind = '2'; farg.i2 = arg; }
00037   inline void assign (FormatArg &farg, unsigned short     arg) { farg.kind = '2'; farg.i2 = arg; }
00038 #if __SIZEOF_WCHAR_T__ == 2
00039   inline void assign (FormatArg &farg, wchar_t            arg) { farg.kind = '2'; farg.i2 = arg; }
00040 #endif
00041   inline void assign (FormatArg &farg, int                arg) { farg.kind = '4'; farg.i4 = arg; }
00042   inline void assign (FormatArg &farg, unsigned int       arg) { farg.kind = '4'; farg.i4 = arg; }
00043 #if __SIZEOF_WCHAR_T__ == 4
00044   inline void assign (FormatArg &farg, wchar_t            arg) { farg.kind = '4'; farg.i4 = arg; }
00045 #endif
00046   inline void assign (FormatArg &farg, long               arg) { farg.kind = '6'; farg.i6 = arg; }
00047   inline void assign (FormatArg &farg, unsigned long      arg) { farg.kind = '6'; farg.i6 = arg; }
00048   inline void assign (FormatArg &farg, long long          arg) { farg.kind = '8'; farg.i8 = arg; }
00049   inline void assign (FormatArg &farg, unsigned long long arg) { farg.kind = '8'; farg.i8 = arg; }
00050   inline void assign (FormatArg &farg, float              arg) { farg.kind = 'f'; farg.f = arg; }
00051   inline void assign (FormatArg &farg, double             arg) { farg.kind = 'f'; farg.f = arg; }
00052   inline void assign (FormatArg &farg, long double        arg) { farg.kind = 'd'; farg.d = arg; }
00053   inline void assign (FormatArg &farg, char              *arg) { farg.kind = 's'; farg.s = arg; }
00054   inline void assign (FormatArg &farg, const char        *arg) { farg.kind = 's'; farg.s = arg; }
00055   inline void assign (FormatArg &farg, const std::string &arg) { assign (farg, arg.c_str()); }
00056   inline void assign (FormatArg &farg, void              *arg) { farg.kind = 'p'; farg.p = arg; }
00057   template<class T> inline void assign (FormatArg &farg, T *const &arg) { assign (farg, (void*) arg); }
00058   template<class T> typename std::enable_if<std::is_enum<T>::value, void>  // eliminated via SFINAE
00059   ::type      assign (FormatArg &farg, const T           &arg) { farg.kind = '8'; farg.i8 = arg; }
00060   template<class T> typename std::enable_if<std::is_class<T>::value, void> // eliminated via SFINAE
00061   ::type      assign (FormatArg &farg, const T           &arg)
00062   {
00063     std::ostringstream os;
00064     os << arg;
00065     temporaries_.push_back (os.str());
00066     assign (farg, temporaries_[temporaries_.size()-1]);
00067   }
00068   const FormatArg& format_arg       (size_t nth);
00069   uint32_t         arg_as_width     (size_t nth);
00070   uint32_t         arg_as_precision (size_t nth);
00071   LLong            arg_as_longlong  (size_t nth);
00072   LDouble          arg_as_ldouble   (size_t nth);
00073   const char*      arg_as_chars     (size_t nth);
00074   void*            arg_as_ptr       (size_t nth);
00075   struct Directive {
00076     char     conversion;
00077     uint32_t adjust_left : 1, add_sign : 1, use_width : 1, use_precision : 1;
00078     uint32_t alternate_form : 1, zero_padding : 1, add_space : 1, locale_grouping : 1;
00079     uint32_t field_width, precision, start, end, value_index, width_index, precision_index;
00080     Directive() :
00081       conversion (0), adjust_left (0), add_sign (0), use_width (0), use_precision (0),
00082       alternate_form (0), zero_padding (0), add_space (0), locale_grouping (0),
00083       field_width (0), precision (0), start (0), end (0), value_index (0), width_index (0), precision_index (0)
00084     {}
00085   };
00086   typedef std::function<String (const String&)> ArgTransform;
00087   FormatArg          *const fargs_;
00088   const size_t        nargs_;
00089   const int           locale_context_;
00090   const ArgTransform &arg_transform_;
00091   vector<std::string> temporaries_;
00092   static std::string            format_error     (const char *err, const char *format, size_t directive);
00093   static const char*            parse_directive  (const char **stringp, size_t *indexp, Directive *dirp);
00094   std::string                   locale_format    (size_t last, const char *format);
00095   std::string                   render_format    (size_t last, const char *format);
00096   std::string                   render_directive (const Directive &dir);
00097   template<class A> std::string render_arg       (const Directive &dir, const char *modifier, A arg);
00098   template<size_t N> inline std::string
00099   intern_format (const char *format)
00100   {
00101     return locale_format (N, format);
00102   }
00103   template<size_t N, class A, class ...Args> inline std::string
00104   intern_format (const char *format, const A &arg, const Args &...args)
00105   {
00106     assign (fargs_[N], arg);
00107     return intern_format<N+1> (format, args...);
00108   }
00109   template<size_t N> inline constexpr
00110   StringFormatter (const ArgTransform &arg_transform, size_t nargs, FormatArg (&mem)[N], int lc) :
00111     fargs_ (mem), nargs_ (nargs), locale_context_ (lc), arg_transform_ (arg_transform) {}
00112 public:
00113   enum LocaleContext {
00114     POSIX_LOCALE,
00115     CURRENT_LOCALE,
00116   };
00117   template<LocaleContext LC = POSIX_LOCALE, class ...Args>
00118   static __attribute__ ((__format__ (printf, 2, 0), noinline)) std::string
00119   format (const ArgTransform &arg_transform, const char *format, const Args &...args)
00120   {
00121     constexpr size_t N = sizeof... (Args);
00122     FormatArg mem[N ? N : 1];
00123     StringFormatter formatter (arg_transform, N, mem, LC);
00124     return formatter.intern_format<0> (format, args...);
00125   }
00126 };
00127 
00129 
00130 } // Lib
00131 } // Rapicorn
00132 
00133 #endif /* __RAPICORN_FORMATTER_HH__ */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines