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/symbol.hpp"
112 #include "lib/nocopy.hpp"
113 #include "lib/meta/util.hpp"
114 #include "lib/meta/size-trait.hpp"
115 
116 #include <string>
117 
118 
119 
120 namespace std {// forward declaration to avoid including <iostream>
121 
122  template<typename C>
123  struct char_traits;
124 
125  template<typename C, class _TRAITS>
126  class basic_ostream;
127 
128  using ostream = basic_ostream<char, char_traits<char>>;
129 }
130 
131 
132 namespace lib {
133  class Literal;
134  class Symbol;
135 }
136 
137 
138 namespace util {
139 
140  using std::string;
141 
142  typedef unsigned char uchar;
143 
144  LUMIERA_ERROR_DECLARE (FORMAT_SYNTAX);
145 
146 
147 
157  class _Fmt
159  {
161  enum{ FORMATTER_SIZE = lib::meta::SizeTrait::BOOST_FORMAT };
162 
163  typedef std::byte Implementation[FORMATTER_SIZE];
164 
165 
167  alignas(size_t) mutable Implementation formatter_;
168 
169 
171  template<typename VAL>
172  static void format (const VAL, Implementation&);
173 
175  template<typename VAL, class SEL =void>
176  struct Converter;
177 
178 
179 
180  public:
181  ~_Fmt ();
182  _Fmt (string formatString);
183 
184  operator string() const;
185 
186  template<typename VAL>
187  _Fmt&
188  operator% (VAL const&);
189 
190 
191  friend std::ostream&
192  operator<< (std::ostream& os, _Fmt const&);
193 
194  friend bool operator== (_Fmt const&, _Fmt const&);
195  friend bool operator== (_Fmt const&, string const&);
196  friend bool operator== (_Fmt const&, const char * const);
197  friend bool operator== (string const& , _Fmt const&);
198  friend bool operator== (const char * const, _Fmt const&);
199 
200  template<typename X>
201  friend bool operator != (_Fmt const& fmt, X const& x) { return not (fmt == x); }
202  template<typename X>
203  friend bool operator != (X const& x, _Fmt const& fmt) { return not (x == fmt); }
204  };
205 
206 
207 
208 
209 
210  /* ===== forwarding into the implementation ====== */
211 
228  template<typename VAL>
229  inline _Fmt&
230  _Fmt::operator% (VAL const& val)
231  {
232  Converter<VAL>::dump (val, formatter_);
233  return *this;
234  }
235 
236 
237 
238  namespace { // helpers to pick a suitable specialisation....
239 
240  using std::__and_;
241  using std::__not_;
242 
248  template<typename X>
249  struct _allow_call : std::false_type {};
250 
251  /* the following definitions enable some primitive types
252  * to be handed over to the boost::format implementation */
253  template<> struct _allow_call<string> : std::true_type { };
254  template<> struct _allow_call<char> : std::true_type { };
255  template<> struct _allow_call<uchar> : std::true_type { };
256  template<> struct _allow_call<int16_t> : std::true_type { };
257  template<> struct _allow_call<uint16_t>: std::true_type { };
258  template<> struct _allow_call<int32_t> : std::true_type { };
259  template<> struct _allow_call<uint32_t>: std::true_type { };
260  template<> struct _allow_call<int64_t> : std::true_type { };
261  template<> struct _allow_call<uint64_t>: std::true_type { };
262  template<> struct _allow_call<float> : std::true_type { };
263  template<> struct _allow_call<double> : std::true_type { };
264 #ifndef __x86_64__
265  template<> struct _allow_call<long> : std::true_type { };
266  template<> struct _allow_call<ulong> : std::true_type { };
267 #endif
268 
269  template<typename X>
271  : _allow_call<std::remove_cv_t<X>>
272  { };
273 
274  template<typename X>
276  : __and_<__not_<_shall_format_directly<X>>
277  , std::bool_constant<lib::meta::can_convertToString<X>::value>
278  >
279  { };
280 
281 
282  template<typename SP>
284  : std::false_type
285  { };
286  template<typename T>
287  struct _is_smart_wrapper<std::shared_ptr<T>>
288  : std::true_type
289  { };
290  template <typename T, typename D>
291  struct _is_smart_wrapper<std::unique_ptr<T,D>>
292  : std::true_type
293  { };
294 
295 
296 
297  template<typename SP>
299  : __and_<__not_<_shall_convert_toString<SP>>
300  ,_is_smart_wrapper<std::remove_reference_t<std::remove_cv_t<SP>>>
301  >
302  { };
303 
304 
305 
306 
307 
308  inline void
309  _clear_errorflag()
310  {
311  const char* errID = lumiera_error();
312  TRACE_IF (errID, progress, "Lumiera errorstate '%s' cleared.", errID);
313  }
314 
315  inline string
316  _log_and_stringify (std::exception const& ex)
317  {
318  _clear_errorflag();
319  WARN (progress, "Error while invoking custom string conversion: %s", ex.what());
320  try {
321  return string("<string conversion failed: ")+ex.what()+">";
322  }
323  catch(...) { /* secondary errors ignored */ }
324  return "(formatting failure)";
325  }
326 
327  inline string
328  _log_unknown_exception()
329  {
330  const char* errID = lumiera_error();
331  if (errID)
332  ERROR (progress, "Unknown error while invoking custom string conversion. Lumiera error flag = %s", errID);
333  else
334  ERROR (progress, "Unknown error while invoking custom string conversion. No Lumiera error flag set.");
335  return "<Unknown error in string conversion>";
336  }
337 
338  }//(End) guards/helpers
339 
340 
341 
342 
343  /* === explicit specialisations to control the kind of conversion === */
344 
346  template<typename VAL, class SEL>
347  struct _Fmt::Converter
348  {
349  static void
350  dump (VAL const&, Implementation& impl)
351  {
352  format ("«"+typeStr<VAL>()+"»", impl);
353  }
354  };
355 
356  template<typename VAL>
357  struct _Fmt::Converter<VAL*>
358  {
359  static void
360  dump (const VAL *pVal, Implementation& impl)
361  {
362  if (pVal)
363  Converter<VAL>::dump(*pVal, impl);
364  else
365  format (BOTTOM_INDICATOR, impl);
366  }
367  };
368 
369  template<>
370  struct _Fmt::Converter<void *>
371  {
372  static void
373  dump (const void* address, Implementation& impl)
374  {
375  format (address, impl);
376  }
377  };
378 
379  template<>
380  struct _Fmt::Converter<const char *>
381  {
382  static void
383  dump (const char* cString, Implementation& impl)
384  {
385  format (cString? cString : BOTTOM_INDICATOR, impl);
386  }
387  };
388 
389  template<>
390  struct _Fmt::Converter<bool>
391  {
392  static void
393  dump (bool yes, Implementation& impl)
394  {
395  format (yes? "true":"false", impl);
396  }
397  };
398 
399  template<>
400  struct _Fmt::Converter<lib::Literal>
401  {
402  static void
403  dump (lib::Literal const& literal, Implementation& impl)
404  {
405  format (literal.empty()? "" : literal.c(), impl);
406  }
407  };
408 
409  template<>
410  struct _Fmt::Converter<lib::Symbol>
411  {
412  static void
413  dump (lib::Symbol const& symbol, Implementation& impl)
414  {
415  format (symbol.c(), impl);
416  }
417  };
418 
420  template<typename VAL>
421  struct _Fmt::Converter<VAL, lib::meta::enable_if<_shall_convert_toString<VAL>> >
422  {
423  static void
424  dump (VAL const& val, Implementation& impl)
425  try {
426  format (string(val), impl);
427  }
428  catch(std::exception const& ex)
429  {
430  format (_log_and_stringify(ex), impl);
431  }
432  catch(...)
433  {
434  format (_log_unknown_exception(), impl);
435  }
436  };
437 
438  template<typename SP>
439  struct _Fmt::Converter<SP, lib::meta::enable_if<_shall_show_smartWrapper<SP>> >
440  {
441  static void
442  dump (SP const& smP, Implementation& impl)
443  try {
444  format (showSmartPtr (smP, lib::meta::typeSymbol(smP)), impl);
445  }
446  catch(std::exception const& ex)
447  {
448  format (_log_and_stringify(ex), impl);
449  }
450  catch(...)
451  {
452  format (_log_unknown_exception(), impl);
453  }
454  };
455 
458  template<typename VAL>
459  struct _Fmt::Converter<VAL, lib::meta::enable_if<_shall_format_directly<VAL>> >
460  {
461  static void
462  dump (const VAL val, Implementation& impl)
463  {
464  format (val, impl);
465  }
466  };
467 
468 
469 
470  /* === comparison of formatter objects === */
471 
472  inline bool
473  operator== (_Fmt const& left, _Fmt const& right)
474  {
475  return string(left) == string(right);
476  }
477 
478  inline bool
479  operator== (_Fmt const& fmt, string const& str)
480  {
481  return string(fmt) == str;
482  }
483 
484  inline bool
485  operator== (_Fmt const& fmt, const char * const cString)
486  {
487  return string(fmt) == string(cString);
488  }
489 
490  inline bool
491  operator== (string const& str, _Fmt const& fmt)
492  {
493  return fmt == str;
494  }
495 
496  inline bool
497  operator== (const char * const cString, _Fmt const& fmt)
498  {
499  return fmt == cString;
500  }
501 
502 
503 
504 } // namespace util
505 #endif
ostream & operator<<(ostream &os, const Option &ops)
for outputting the help messages.
Definition: option.cpp:160
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:85
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:126
Mix-Ins to allow or prohibit various degrees of copying and cloning.
Metaprogramming definitions to deal with dependency on implementation size and layout.
Marker types to indicate a literal string and a Symbol.
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