Lumiera  0.pre.03
»edit your freedom«
format-obj.cpp
Go to the documentation of this file.
1 /*
2  FormatObj - simple means to display an object
3 
4  Copyright (C)
5  2016, Hermann Vosseler <Ichthyostega@web.de>
6 
7   **Lumiera** is free software; you can redistribute it and/or modify it
8   under the terms of the GNU General Public License as published by the
9   Free Software Foundation; either version 2 of the License, or (at your
10   option) any later version. See the file COPYING for further details.
11 
12 * *****************************************************************/
13 
34 #include "lib/error.hpp"
35 #include "lib/format-obj.hpp"
36 #include "lib/ios-savepoint.hpp"
37 //#include "lib/format-string.hpp"
39 #include "lib/symbol.hpp"
40 #include "lib/util.hpp"
41 
42 #ifdef __GNUG__
43 #include <cxxabi.h>
44 #endif
45 
46 #include <limits>
47 #include <iomanip>
48 #include <sstream>
49 #include <string>
50 #include <regex>
51 
52 //using util::_Fmt;
53 using util::removePrefix;
54 using util::removeSuffix;
55 using util::isnil;
56 using std::string;
57 
58 using std::regex;
59 using std::regex_replace;
60 
61 
62 namespace { // hard-wired configuration for debugging output....
63 
64  // precision for rendering of double values
65  const auto DIAGNOSTICS_DOUBLE_PRECISION = 8;
66  const auto DIAGNOSTICS_FLOAT_PRECISION = 5;
67 
70 
71 
73  template<typename F>
74  constexpr size_t PRECISION_DECIMAL = std::numeric_limits<F>::digits10;
75 
77  template<typename F>
78  constexpr size_t PRECISION_COMPLETE = std::numeric_limits<F>::max_digits10;
79 }
80 
81 
82 
83 namespace lib {
84 namespace meta {
85 
86  // pre-allocated failure indicators, which can be returned failsafe.
87 
88  extern const string BOTTOM_INDICATOR = "⟂";
89  extern const string FAILURE_INDICATOR = "↯";
90  extern const string VOID_INDICATOR = "void";
91  extern const string FUNCTION_INDICATOR= "Function";
92 
93  extern const string BOOL_FALSE_STR = "false";
94  extern const string BOOL_TRUE_STR = "true";
95 
96 
97 
98 #ifdef __GNUG__
99 
136  string
137  demangleCxx (Literal rawName)
138  {
139  int error = -4;
140  UniqueMallocOwner<char> demangled (abi::__cxa_demangle (rawName,
141  NULL,
142  NULL,
143  &error));
144  return 0==error? demangled.get()
145  : string(rawName);
146  }
147 
148 
149 #else
150 #warning "Lumiera was _not_ built with a GCC compatible compiler."
151 #warning "There are good chances this works without problems, but up to now, \
152 the Lumiera developers lacked the resources to investigate that option; \
153 apologies for that."
154 
158  string
160  {
161  return string (rawName);
162  }
163 #endif
164 
165 
166 
167 
168 
189  string
191  {
192  string typeName = demangleCxx (rawType);
193 
194  #define TYP_EXP "[\\w<>\\(\\):,\\s]+"
195 
196  static regex commonPrefixes {"std::"
197  "|(\\w+::)+\\(anonymous namespace\\)::"
198  "|lib::meta::"
199  "|lib::time::"
200  "|lib::test::"
201  "|lib::diff::"
202  "|lib::"
203  "|util::"
204  "|steam::(asset::|mobject::(session::)?|play::)?"
205  "|stage::model"
206  "|stage::ctrl"
207  "|lumiera::"
208  , regex::ECMAScript | regex::optimize};
209 
210  static regex lolong {"long long"
211  , regex::ECMAScript | regex::optimize};
212  static regex unSigned {"unsigned (\\w+)"
213  , regex::ECMAScript | regex::optimize};
214 
215  static regex stdString {"(__cxx11::)?basic_string<char, char_traits<char>, allocator<char>\\s*>(\\s+\\B)?"
216  , regex::ECMAScript | regex::optimize};
217 
218  static regex stdAllocator {"(\\w+<(" TYP_EXP ")), allocator<\\2>\\s*"
219  , regex::ECMAScript | regex::optimize};
220 
221  static regex mapAllocator {"(map<(" TYP_EXP "), (" TYP_EXP ")),.+allocator<pair<\\2 const, \\3>\\s*>\\s*"
222  , regex::ECMAScript | regex::optimize};
223 
224  static regex uniquePtr {"unique_ptr<(\\w+), default_delete<\\1>\\s*"
225  , regex::ECMAScript | regex::optimize};
226 
227  static regex lumieraP {"P<(\\w+), shared_ptr<\\1>\\s*"
228  , regex::ECMAScript | regex::optimize};
229 
230 
231  auto pos = typeName.begin();
232  auto end = typeName.end();
233 
234  end = regex_replace(pos, pos, end, commonPrefixes, "");
235  end = regex_replace(pos, pos, end, lolong, "llong");
236  end = regex_replace(pos, pos, end, unSigned, "u$1");
237  end = regex_replace(pos, pos, end, stdString, "string");
238  end = regex_replace(pos, pos, end, stdAllocator, "$1");
239  end = regex_replace(pos, pos, end, mapAllocator, "$1");
240  end = regex_replace(pos, pos, end, uniquePtr, "unique_ptr<$1");
241  end = regex_replace(pos, pos, end, lumieraP, "P<$1");
242 
243  typeName.resize(end - typeName.begin());
244  return typeName;
245  }
246 
247 
248 
267  string
269  {
270  string typeStr = demangleCxx (rawType);
271 
272  removeSuffix (typeStr, " const");
273  removeSuffix (typeStr, " const *");
274  removeSuffix (typeStr, "*");
275  removeSuffix (typeStr, "&");
276 
277  if (isnil (typeStr)) return VOID_INDICATOR;
278  if (')' == typeStr.back()) return FUNCTION_INDICATOR;
279 
280  auto end = typeStr.end();
281  auto beg = typeStr.begin();
282  int level=0;
283  while (--end != beg)
284  {
285  if ('>' == *end)
286  ++level;
287  else if ('<' == *end and level>0)
288  --level;
289  else
290  if (level==0)
291  {
292  ++end;
293  break;
294  }
295  }
296  if (end == beg) return VOID_INDICATOR;
297 
298  auto pos = typeStr.rfind("::", end-beg);
299  typeStr = (pos==string::npos? typeStr.substr(0, end-beg)
300  : typeStr.substr(pos+2, (end-beg)-pos-2));
301  return typeStr;
302  }
303 
304 
305  string
307  {
308  return util::sanitise (humanReadableTypeID (rawName));
309  }
310 
311 
312  string
313  sanitisedSymbol (string const& text)
314  {
315  static regex identifierChars {"[A-Za-z]\\w*", regex::ECMAScript | regex::optimize};
316 
317  return regex_replace (text, identifierChars, "$&", std::regex_constants::format_no_copy);
318  } // don't copy what does not match
319 
320 
321 
322 }}// namespace lib::meta
323 
324 
325 
326 
327 
328 /* === formatting and pretty printing support utils === */
329 
330 namespace util {
331 
332  using std::hex;
333  using std::setw;
334  using std::right;
335  using std::setfill;
336  using std::uppercase;
337  using std::noshowbase;
338  using std::ostringstream;
339  using std::ostream;
340 
341  template<typename F>
342  string
343  showFloatingPoint (F val, size_t precision) noexcept
344  try {
345  ostringstream buffer;
346  buffer.precision (precision);
347  buffer << val;
348  return buffer.str();
349  }
350  catch(...)
351  { return FAILURE_INDICATOR; }
352 
360  string showDouble (double val) noexcept { return showFloatingPoint (val, DIAGNOSTICS_DOUBLE_PRECISION); }
361  string showFloat (float val) noexcept { return showFloatingPoint (val, DIAGNOSTICS_FLOAT_PRECISION); }
362 
363  string showDecimal (double val) noexcept { return showFloatingPoint (val, PRECISION_DECIMAL<double>); }
364  string showDecimal (float val) noexcept { return showFloatingPoint (val, PRECISION_DECIMAL<float>); }
365  string showDecimal (f128 val) noexcept { return showFloatingPoint (val, PRECISION_DECIMAL<f128>); }
366 
367  string showComplete (double val) noexcept { return showFloatingPoint (val, PRECISION_COMPLETE<double>); }
368  string showComplete (float val) noexcept { return showFloatingPoint (val, PRECISION_COMPLETE<float>); }
369  string showComplete (f128 val) noexcept { return showFloatingPoint (val, PRECISION_COMPLETE<f128>); }
370 
371 
372  string
373  showSize (size_t val) noexcept
374  try {
375  ostringstream buffer;
376  buffer << val;
377  return buffer.str();
378  }
379  catch(...)
380  { return FAILURE_INDICATOR; }
381 
382 
384  ostream&
385  showAdr (ostream& stream, void const* addr)
386  {
387  IosSavepoint save{stream};
388  size_t suffix_modulus = size_t(1) << DIAGNOSTICS_ADDRESS_SUFFIX_LEN * 8;
389  return stream << "╲"
390  << hex
391  << noshowbase
392  << setw (DIAGNOSTICS_ADDRESS_SUFFIX_LEN * 2) // need 2 hex digits per byte
393  << setfill('_')
394  << right
395  << size_t(addr) % suffix_modulus;
396  }
397 
398 
399  string
400  showAdr (void const* addr) noexcept
401  try {
402  ostringstream buffer;
403  showAdr (buffer, addr);
404  return buffer.str();
405  }
406  catch(...)
407  { return FAILURE_INDICATOR; }
408 
409 
410  string
411  showHash (size_t hash, uint showBytes) noexcept
412  try {
413  showBytes = util::limited (1u, showBytes, 8u);
414  size_t suffix_modulus = size_t(1) << showBytes * 8;
415  ostringstream buffer;
416  buffer << hex
417  << uppercase
418  << noshowbase
419  << setw (showBytes * 2) // need 2 hex digits per byte
420  << setfill('0')
421  << right
422  << (showBytes==8? hash : hash % suffix_modulus);
423  return buffer.str();
424  }
425  catch(...)
426  { return FAILURE_INDICATOR; }
427 
428 
429 
430 } // namespace util
string showHash(size_t hash, uint showBytes) noexcept
renders the size_t in hex, optionally only trailing bytes
Definition: format-obj.cpp:411
constexpr size_t PRECISION_COMPLETE
decimal digits require tod represent each different floating-point value
Definition: format-obj.cpp:78
inline string literal This is a marker type to indicate that
Definition: symbol.hpp:76
Capture previous settings of an std::ostream and restore them when leaving scope. ...
string showComplete(double val) noexcept
show enough decimal digits to represent every distinct value
Definition: format-obj.cpp:367
string showDouble(double val) noexcept
pretty-print a double in (rounded) fixed-point format
Definition: format-obj.cpp:360
Helper to deal with C-MALLOCed memory automatically.
string showDecimal(double val) noexcept
show maximum reproducible decimal representation
Definition: format-obj.cpp:363
Implementation namespace for support and library code.
string primaryTypeComponent(Literal rawType)
extract core name component from a raw type spec
Definition: format-obj.cpp:268
string sanitisedFullTypeName(lib::Literal rawName)
build a sanitised ID from full type name
Definition: format-obj.cpp:306
Marker types to indicate a literal string and a Symbol.
string demangleCxx(Literal rawName)
Fallback type-ID:
Definition: format-obj.cpp:159
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
string humanReadableTypeID(Literal rawType)
pretty-print an internal C++ type representation
Definition: format-obj.cpp:190
constexpr size_t PRECISION_DECIMAL
maximum decimal digits able to pass through a round trip without value change
Definition: format-obj.cpp:74
RAII helper to capture and restore output stream format settings.
Lumiera error handling (C++ interface).
Simple functions to represent objects, for debugging and diagnostics.
const size_t DIAGNOSTICS_ADDRESS_SUFFIX_LEN
show only this amount of trailing bytes from an address
Definition: format-obj.cpp:69
NUM constexpr limited(NB lowerBound, NUM val, NB upperBound)
force a numeric to be within bounds, inclusively
Definition: util.hpp:91
string sanitisedSymbol(string const &text)
condense a string and retain only valid identifiers
Definition: format-obj.cpp:313
ostream & showAdr(ostream &stream, void const *addr)
preconfigured format for pretty-printing of addresses
Definition: format-obj.cpp:385
std::string typeStr(TY const *obj=nullptr) noexcept
failsafe human readable type display
Definition: meta/util.hpp:316