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) Lumiera.org
5  2016, 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 
43 #include "lib/error.hpp"
44 #include "lib/format-obj.hpp"
45 #include "lib/ios-savepoint.hpp"
46 //#include "lib/format-string.hpp"
48 #include "lib/symbol.hpp"
49 #include "lib/util.hpp"
50 
51 #ifdef __GNUG__
52 #include <cxxabi.h>
53 #endif
54 
55 #include <limits>
56 #include <iomanip>
57 #include <sstream>
58 #include <string>
59 #include <regex>
60 
61 //using util::_Fmt;
62 using util::removePrefix;
63 using util::removeSuffix;
64 using util::isnil;
65 using std::string;
66 
67 using std::regex;
68 using std::regex_replace;
69 
70 
71 namespace { // hard-wired configuration for debugging output....
72 
73  // precision for rendering of double values
74  const auto DIAGNOSTICS_DOUBLE_PRECISION = 8;
75  const auto DIAGNOSTICS_FLOAT_PRECISION = 5;
76 
79 
80 
82  template<typename F>
83  constexpr size_t PRECISION_DECIMAL = std::numeric_limits<F>::digits10;
84 
86  template<typename F>
87  constexpr size_t PRECISION_COMPLETE = std::numeric_limits<F>::max_digits10;
88 }
89 
90 
91 
92 namespace lib {
93 namespace meta {
94 
95  // pre-allocated failure indicators, which can be returned failsafe.
96 
97  extern const string BOTTOM_INDICATOR = "⟂";
98  extern const string FAILURE_INDICATOR = "↯";
99  extern const string VOID_INDICATOR = "void";
100  extern const string FUNCTION_INDICATOR= "Function";
101 
102  extern const string BOOL_FALSE_STR = "false";
103  extern const string BOOL_TRUE_STR = "true";
104 
105 
106 
107 #ifdef __GNUG__
108 
145  string
146  demangleCxx (Literal rawName)
147  {
148  int error = -4;
149  UniqueMallocOwner<char> demangled (abi::__cxa_demangle (rawName,
150  NULL,
151  NULL,
152  &error));
153  return 0==error? demangled.get()
154  : string(rawName);
155  }
156 
157 
158 #else
159 #warning "Lumiera was _not_ built with a GCC compatible compiler."
160 #warning "There are good chances this works without problems, but up to now, \
161 the Lumiera developers lacked the resources to investigate that option; \
162 apologies for that."
163 
167  string
169  {
170  return string (rawName);
171  }
172 #endif
173 
174 
175 
176 
177 
198  string
200  {
201  string typeName = demangleCxx (rawType);
202 
203  #define TYP_EXP "[\\w<>\\(\\):,\\s]+"
204 
205  static regex commonPrefixes {"std::"
206  "|(\\w+::)+\\(anonymous namespace\\)::"
207  "|lib::meta::"
208  "|lib::time::"
209  "|lib::test::"
210  "|lib::diff::"
211  "|lib::"
212  "|util::"
213  "|steam::(asset::|mobject::(session::)?|play::)?"
214  "|stage::model"
215  "|stage::ctrl"
216  "|lumiera::"
217  , regex::ECMAScript | regex::optimize};
218 
219  static regex stdString {"(__cxx11::)?basic_string<char, char_traits<char>, allocator<char>\\s*>(\\s+\\B)?"
220  , regex::ECMAScript | regex::optimize};
221 
222  static regex stdAllocator {"(\\w+<(" TYP_EXP ")), allocator<\\2>\\s*"
223  , regex::ECMAScript | regex::optimize};
224 
225  static regex mapAllocator {"(map<(" TYP_EXP "), (" TYP_EXP ")),.+allocator<pair<\\2 const, \\3>\\s*>\\s*"
226  , regex::ECMAScript | regex::optimize};
227 
228  static regex uniquePtr {"unique_ptr<(\\w+), default_delete<\\1>\\s*"
229  , regex::ECMAScript | regex::optimize};
230 
231  static regex lumieraP {"P<(\\w+), shared_ptr<\\1>\\s*"
232  , regex::ECMAScript | regex::optimize};
233 
234 
235  auto pos = typeName.begin();
236  auto end = typeName.end();
237 
238  end = regex_replace(pos, pos, end, commonPrefixes, "");
239  end = regex_replace(pos, pos, end, stdString, "string");
240  end = regex_replace(pos, pos, end, stdAllocator, "$1");
241  end = regex_replace(pos, pos, end, mapAllocator, "$1");
242  end = regex_replace(pos, pos, end, uniquePtr, "unique_ptr<$1");
243  end = regex_replace(pos, pos, end, lumieraP, "P<$1");
244 
245  typeName.resize(end - typeName.begin());
246  return typeName;
247  }
248 
249 
250 
269  string
271  {
272  string typeStr = demangleCxx (rawType);
273 
274  removeSuffix (typeStr, " const");
275  removeSuffix (typeStr, " const *");
276  removeSuffix (typeStr, "*");
277  removeSuffix (typeStr, "&");
278 
279  if (isnil (typeStr)) return VOID_INDICATOR;
280  if (')' == typeStr.back()) return FUNCTION_INDICATOR;
281 
282  auto end = typeStr.end();
283  auto beg = typeStr.begin();
284  int level=0;
285  while (--end != beg)
286  {
287  if ('>' == *end)
288  ++level;
289  else if ('<' == *end and level>0)
290  --level;
291  else
292  if (level==0)
293  {
294  ++end;
295  break;
296  }
297  }
298  if (end == beg) return VOID_INDICATOR;
299 
300  auto pos = typeStr.rfind("::", end-beg);
301  typeStr = (pos==string::npos? typeStr.substr(0, end-beg)
302  : typeStr.substr(pos+2, (end-beg)-pos-2));
303  return typeStr;
304  }
305 
306 
307  string
309  {
310  return util::sanitise (humanReadableTypeID (rawName));
311  }
312 
313 
314  string
315  sanitisedSymbol (string const& text)
316  {
317  static regex identifierChars {"[A-Za-z]\\w*", regex::ECMAScript | regex::optimize};
318 
319  return regex_replace (text, identifierChars, "$&", std::regex_constants::format_no_copy);
320  } // don't copy what does not match
321 
322 
323 
324 }}// namespace lib::meta
325 
326 
327 
328 
329 
330 /* === formatting and pretty printing support utils === */
331 
332 namespace util {
333 
334  using std::hex;
335  using std::setw;
336  using std::right;
337  using std::setfill;
338  using std::uppercase;
339  using std::noshowbase;
340  using std::ostringstream;
341  using std::ostream;
342 
343  template<typename F>
344  string
345  showFloatingPoint (F val, size_t precision) noexcept
346  try {
347  ostringstream buffer;
348  buffer.precision (precision);
349  buffer << val;
350  return buffer.str();
351  }
352  catch(...)
353  { return FAILURE_INDICATOR; }
354 
362  string showDouble (double val) noexcept { return showFloatingPoint (val, DIAGNOSTICS_DOUBLE_PRECISION); }
363  string showFloat (float val) noexcept { return showFloatingPoint (val, DIAGNOSTICS_FLOAT_PRECISION); }
364 
365  string showDecimal (double val) noexcept { return showFloatingPoint (val, PRECISION_DECIMAL<double>); }
366  string showDecimal (float val) noexcept { return showFloatingPoint (val, PRECISION_DECIMAL<float>); }
367  string showDecimal (f128 val) noexcept { return showFloatingPoint (val, PRECISION_DECIMAL<f128>); }
368 
369  string showComplete (double val) noexcept { return showFloatingPoint (val, PRECISION_COMPLETE<double>); }
370  string showComplete (float val) noexcept { return showFloatingPoint (val, PRECISION_COMPLETE<float>); }
371  string showComplete (f128 val) noexcept { return showFloatingPoint (val, PRECISION_COMPLETE<f128>); }
372 
373 
374  string
375  showSize (size_t val) noexcept
376  try {
377  ostringstream buffer;
378  buffer << val;
379  return buffer.str();
380  }
381  catch(...)
382  { return FAILURE_INDICATOR; }
383 
384 
386  ostream&
387  showAddr (ostream& stream, void const* addr)
388  {
389  IosSavepoint save{stream};
390  size_t suffix_modulus = size_t(1) << DIAGNOSTICS_ADDRESS_SUFFIX_LEN * 8;
391  return stream << "╲"
392  << hex
393  << noshowbase
394  << setw (DIAGNOSTICS_ADDRESS_SUFFIX_LEN * 2) // need 2 hex digits per byte
395  << setfill('_')
396  << right
397  << size_t(addr) % suffix_modulus;
398  }
399 
400 
401  string
402  showAddr (void const* addr) noexcept
403  try {
404  ostringstream buffer;
405  showAddr (buffer, addr);
406  return buffer.str();
407  }
408  catch(...)
409  { return FAILURE_INDICATOR; }
410 
411 
412  string
413  showHash (size_t hash, uint showBytes) noexcept
414  try {
415  showBytes = util::limited (1u, showBytes, 8u);
416  size_t suffix_modulus = size_t(1) << showBytes * 8;
417  ostringstream buffer;
418  buffer << hex
419  << uppercase
420  << noshowbase
421  << setw (showBytes * 2) // need 2 hex digits per byte
422  << setfill('0')
423  << right
424  << (showBytes==8? hash : hash % suffix_modulus);
425  return buffer.str();
426  }
427  catch(...)
428  { return FAILURE_INDICATOR; }
429 
430 
431 
432 } // namespace util
string showHash(size_t hash, uint showBytes) noexcept
renders the size_t in hex, optionally only trailing bytes
Definition: format-obj.cpp:413
ostream & showAddr(ostream &stream, void const *addr)
preconfigured format for pretty-printing of addresses
Definition: format-obj.cpp:387
constexpr size_t PRECISION_COMPLETE
decimal digits require tod represent each different floating-point value
Definition: format-obj.cpp:87
inline string literal This is a marker type to indicate that
Definition: symbol.hpp:85
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:369
string showDouble(double val) noexcept
pretty-print a double in (rounded) fixed-point format
Definition: format-obj.cpp:362
Helper to deal with C-MALLOCed memory automatically.
string showDecimal(double val) noexcept
show maximum reproducible decimal representation
Definition: format-obj.cpp:365
Implementation namespace for support and library code.
string primaryTypeComponent(Literal rawType)
extract core name component from a raw type spec
Definition: format-obj.cpp:270
string sanitisedFullTypeName(lib::Literal rawName)
build a sanitised ID from full type name
Definition: format-obj.cpp:308
Marker types to indicate a literal string and a Symbol.
string demangleCxx(Literal rawName)
Fallback type-ID:
Definition: format-obj.cpp:168
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:199
constexpr size_t PRECISION_DECIMAL
maximum decimal digits able to pass through a round trip without value change
Definition: format-obj.cpp:83
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:78
NUM constexpr limited(NB lowerBound, NUM val, NB upperBound)
force a numeric to be within bounds, inclusively
Definition: util.hpp:101
string sanitisedSymbol(string const &text)
condense a string and retain only valid identifiers
Definition: format-obj.cpp:315
std::string typeStr(TY const *obj=nullptr) noexcept
failsafe human readable type display
Definition: meta/util.hpp:325