Lumiera  0.pre.03
»edit your freedom«
format-string.hpp
Go to the documentation of this file.
1 /*
2  FORMAT-STRING.hpp - string template formatting based on boost::format
3 
4  Copyright (C) Lumiera.org
5  2011, Hermann Vosseler <Ichthyostega@web.de>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 */
22 
23 
107 #ifndef UTIL_FORMAT_STRING_H
108 #define UTIL_FORMAT_STRING_H
109 
110 #include "lib/error.hpp"
111 #include "lib/nocopy.hpp"
112 #include "lib/meta/util.hpp"
113 #include "lib/meta/size-trait.hpp"
114 
115 #include <string>
116 
117 
118 
119 namespace std { // forward declaration to avoid including <iostream>
120 
121  template<typename C>
122  struct char_traits;
123 
124  template<typename C, class _TRAITS>
125  class basic_ostream;
126 
127  using ostream = basic_ostream<char, char_traits<char>>;
128 }
129 
130 
131 namespace lib {
132  class Literal;
133  class Symbol;
134 }
135 
136 
137 namespace util {
138 
139  using std::string;
140 
141  typedef unsigned char uchar;
142 
143  LUMIERA_ERROR_DECLARE (FORMAT_SYNTAX);
144 
145 
146 
156  class _Fmt
158  {
160  enum{ FORMATTER_SIZE = lib::meta::SizeTrait::BOOST_FORMAT };
161 
162  typedef char Implementation[FORMATTER_SIZE];
163 
164 
166  mutable Implementation formatter_;
167 
168 
170  template<typename VAL>
171  static void format (const VAL, Implementation&);
172 
174  template<typename VAL, class SEL =void>
175  struct Converter;
176 
177 
178 
179  public:
180  ~_Fmt ();
181  _Fmt (string formatString);
182 
183  operator string() const;
184 
185  template<typename VAL>
186  _Fmt&
187  operator% (VAL const&);
188 
189 
190  friend std::ostream&
191  operator<< (std::ostream& os, _Fmt const&);
192 
193  friend bool operator== (_Fmt const&, _Fmt const&);
194  friend bool operator== (_Fmt const&, string const&);
195  friend bool operator== (_Fmt const&, const char * const);
196  friend bool operator== (string const& , _Fmt const&);
197  friend bool operator== (const char * const, _Fmt const&);
198 
199  template<typename X>
200  friend bool operator != (_Fmt const& fmt, X const& x) { return not (fmt == x); }
201  template<typename X>
202  friend bool operator != (X const& x, _Fmt const& fmt) { return not (x == fmt); }
203  };
204 
205 
206 
207 
208 
209  /* ===== forwarding into the implementation ====== */
210 
227  template<typename VAL>
228  inline _Fmt&
229  _Fmt::operator% (VAL const& val)
230  {
231  Converter<VAL>::dump (val, formatter_);
232  return *this;
233  }
234 
235 
236 
237  namespace { // helpers to pick a suitable specialisation....
238 
239  using std::__and_;
240  using std::__not_;
241 
247  template<typename X>
248  struct _allow_call : std::false_type {};
249 
250  /* the following definitions enable some primitive types
251  * to be handed over to the boost::format implementation */
252  template<> struct _allow_call<string> : std::true_type { };
253  template<> struct _allow_call<char> : std::true_type { };
254  template<> struct _allow_call<uchar> : std::true_type { };
255  template<> struct _allow_call<int16_t> : std::true_type { };
256  template<> struct _allow_call<uint16_t>: std::true_type { };
257  template<> struct _allow_call<int32_t> : std::true_type { };
258  template<> struct _allow_call<uint32_t>: std::true_type { };
259  template<> struct _allow_call<int64_t> : std::true_type { };
260  template<> struct _allow_call<uint64_t>: std::true_type { };
261  template<> struct _allow_call<float> : std::true_type { };
262  template<> struct _allow_call<double> : std::true_type { };
263 #ifndef __x86_64__
264  template<> struct _allow_call<long> : std::true_type { };
265  template<> struct _allow_call<ulong> : std::true_type { };
266 #endif
267 
268  template<typename X>
270  : _allow_call<std::remove_cv_t<X>>
271  { };
272 
273  template<typename X>
275  : __and_<__not_<_shall_format_directly<X>>
276  , std::bool_constant<lib::meta::can_convertToString<X>::value>
277  >
278  { };
279 
280 
281  template<typename SP>
283  : std::false_type
284  { };
285  template<typename T>
286  struct _is_smart_wrapper<std::shared_ptr<T>>
287  : std::true_type
288  { };
289  template <typename T, typename D>
290  struct _is_smart_wrapper<std::unique_ptr<T,D>>
291  : std::true_type
292  { };
293 
294 
295 
296  template<typename SP>
298  : __and_<__not_<_shall_convert_toString<SP>>
299  ,_is_smart_wrapper<std::remove_reference_t<std::remove_cv_t<SP>>>
300  >
301  { };
302 
303 
304 
305 
306 
307  inline void
308  _clear_errorflag()
309  {
310  const char* errID = lumiera_error();
311  TRACE_IF (errID, progress, "Lumiera errorstate '%s' cleared.", errID);
312  }
313 
314  inline string
315  _log_and_stringify (std::exception const& ex)
316  {
317  _clear_errorflag();
318  WARN (progress, "Error while invoking custom string conversion: %s", ex.what());
319  try {
320  return string("<string conversion failed: ")+ex.what()+">";
321  }
322  catch(...) { /* secondary errors ignored */ }
323  return "(formatting failure)";
324  }
325 
326  inline string
327  _log_unknown_exception()
328  {
329  const char* errID = lumiera_error();
330  if (errID)
331  ERROR (progress, "Unknown error while invoking custom string conversion. Lumiera error flag = %s", errID);
332  else
333  ERROR (progress, "Unknown error while invoking custom string conversion. No Lumiera error flag set.");
334  return "<Unknown error in string conversion>";
335  }
336 
337  }//(End) guards/helpers
338 
339 
340 
341 
342  /* === explicit specialisations to control the kind of conversion === */
343 
345  template<typename VAL, class SEL>
346  struct _Fmt::Converter
347  {
348  static void
349  dump (VAL const&, Implementation& impl)
350  {
351  format ("«"+typeStr<VAL>()+"»", impl);
352  }
353  };
354 
355  template<typename VAL>
356  struct _Fmt::Converter<VAL*>
357  {
358  static void
359  dump (const VAL *pVal, Implementation& impl)
360  {
361  if (pVal)
362  Converter<VAL>::dump(*pVal, impl);
363  else
364  format (BOTTOM_INDICATOR, impl);
365  }
366  };
367 
368  template<>
369  struct _Fmt::Converter<void *>
370  {
371  static void
372  dump (const void* address, Implementation& impl)
373  {
374  format (address, impl);
375  }
376  };
377 
378  template<>
379  struct _Fmt::Converter<const char *>
380  {
381  static void
382  dump (const char* cString, Implementation& impl)
383  {
384  format (cString? cString : BOTTOM_INDICATOR, impl);
385  }
386  };
387 
388  template<>
389  struct _Fmt::Converter<bool>
390  {
391  static void
392  dump (bool yes, Implementation& impl)
393  {
394  format (yes? "true":"false", impl);
395  }
396  };
397 
398  template<>
399  struct _Fmt::Converter<lib::Literal>
400  {
401  static void
402  dump (lib::Literal const& literal, Implementation& impl)
403  {
404  format (literal.empty()? "" : literal.c(), impl);
405  }
406  };
407 
408  template<>
409  struct _Fmt::Converter<lib::Symbol>
410  {
411  static void
412  dump (lib::Symbol const& symbol, Implementation& impl)
413  {
414  format (symbol.c(), impl);
415  }
416  };
417 
419  template<typename VAL>
420  struct _Fmt::Converter<VAL, lib::meta::enable_if<_shall_convert_toString<VAL>> >
421  {
422  static void
423  dump (VAL const& val, Implementation& impl)
424  try {
425  format (string(val), impl);
426  }
427  catch(std::exception const& ex)
428  {
429  format (_log_and_stringify(ex), impl);
430  }
431  catch(...)
432  {
433  format (_log_unknown_exception(), impl);
434  }
435  };
436 
437  template<typename SP>
438  struct _Fmt::Converter<SP, lib::meta::enable_if<_shall_show_smartWrapper<SP>> >
439  {
440  static void
441  dump (SP const& smP, Implementation& impl)
442  try {
443  format (showSmartPtr (smP, lib::meta::typeSymbol(smP)), impl);
444  }
445  catch(std::exception const& ex)
446  {
447  format (_log_and_stringify(ex), impl);
448  }
449  catch(...)
450  {
451  format (_log_unknown_exception(), impl);
452  }
453  };
454 
457  template<typename VAL>
458  struct _Fmt::Converter<VAL, lib::meta::enable_if<_shall_format_directly<VAL>> >
459  {
460  static void
461  dump (const VAL val, Implementation& impl)
462  {
463  format (val, impl);
464  }
465  };
466 
467 
468 
469  /* === comparison of formatter objects === */
470 
471  inline bool
472  operator== (_Fmt const& left, _Fmt const& right)
473  {
474  return string(left) == string(right);
475  }
476 
477  inline bool
478  operator== (_Fmt const& fmt, string const& str)
479  {
480  return string(fmt) == str;
481  }
482 
483  inline bool
484  operator== (_Fmt const& fmt, const char * const cString)
485  {
486  return string(fmt) == string(cString);
487  }
488 
489  inline bool
490  operator== (string const& str, _Fmt const& fmt)
491  {
492  return fmt == str;
493  }
494 
495  inline bool
496  operator== (const char * const cString, _Fmt const& fmt)
497  {
498  return fmt == cString;
499  }
500 
501 
502 
503 } // namespace util
504 #endif
Implementation formatter_
ostream & operator<<(ostream &os, const Option &ops)
for outputting the help messages.
Definition: option.cpp:161
Simple and lightweight helpers for metaprogramming and type detection.
Any copy and copy construction prohibited.
Definition: nocopy.hpp:46
inline string literal This is a marker type to indicate that
Definition: symbol.hpp:75
STL namespace.
by default we don&#39;t allow to treat any types directly by boost::format.
#define LUMIERA_ERROR_DECLARE(err)
Forward declare an error constant.
Definition: error.h:71
A front-end for using printf-style formatting.
helper to prepare parameters for inclusion
Implementation namespace for support and library code.
Token or Atom with distinct identity.
Definition: symbol.hpp:116
Mix-Ins to allow or prohibit various degrees of copying and cloning.
Metaprogramming definitions to deal with dependency on implementation size and layout.
lumiera_err lumiera_error(void)
Get and clear current error state.
Definition: error-state.c:124
Lumiera error handling (C++ interface).
string typeSymbol()
Short readable type identifier, not necessarily unique or complete.
Definition: genfunc.hpp:87