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 <iomanip>
56 #include <sstream>
57 #include <string>
58 #include <regex>
59 
60 //using util::_Fmt;
61 using util::removePrefix;
62 using util::removeSuffix;
63 using util::isnil;
64 using std::string;
65 
66 using std::regex;
67 using std::regex_replace;
68 
69 
70 namespace { // hard-wired configuration for debugging output....
71 
72  // precision for rendering of double values
73  const auto DIAGNOSTICS_DOUBLE_PRECISION = 8;
74  const auto DIAGNOSTICS_FLOAT_PRECISION = 5;
75 
78 }
79 
80 
81 
82 namespace lib {
83 namespace meta {
84 
85  // pre-allocated failure indicators, which can be returned failsafe.
86 
87  extern const string BOTTOM_INDICATOR = "⟂";
88  extern const string FAILURE_INDICATOR = "↯";
89  extern const string VOID_INDICATOR = "void";
90  extern const string FUNCTION_INDICATOR= "Function";
91 
92  extern const string BOOL_FALSE_STR = "false";
93  extern const string BOOL_TRUE_STR = "true";
94 
95 
96 
97 #ifdef __GNUG__
98 
135  string
136  demangleCxx (Literal rawName)
137  {
138  int error = -4;
139  UniqueMallocOwner<char> demangled (abi::__cxa_demangle (rawName,
140  NULL,
141  NULL,
142  &error));
143  return 0==error? demangled.get()
144  : string(rawName);
145  }
146 
147 
148 #else
149 #warning "Lumiera was _not_ built with a GCC compatible compiler."
150 #warning "There are good chances this works without problems, but up to now, \
151 the Lumiera developers lacked the resources to investigate that option; \
152 apologies for that."
153 
157  string
159  {
160  return string (rawName);
161  }
162 #endif
163 
164 
165 
166 
167 
188  string
190  {
191  string typeName = demangleCxx (rawType);
192 
193  #define TYP_EXP "[\\w<>\\(\\):,\\s]+"
194 
195  static regex commonPrefixes {"std::"
196  "|(\\w+::)+\\(anonymous namespace\\)::"
197  "|lib::meta::"
198  "|lib::time::"
199  "|lib::test::"
200  "|lib::diff::"
201  "|lib::"
202  "|util::"
203  "|steam::(asset::|mobject::(session::)?|play::)?"
204  "|stage::model"
205  "|stage::ctrl"
206  "|lumiera::"
207  , regex::ECMAScript | regex::optimize};
208 
209  static regex stdString {"(__cxx11::)?basic_string<char, char_traits<char>, allocator<char>\\s*>(\\s+\\B)?"
210  , regex::ECMAScript | regex::optimize};
211 
212  static regex stdAllocator {"(\\w+<(" TYP_EXP ")), allocator<\\2>\\s*"
213  , regex::ECMAScript | regex::optimize};
214 
215  static regex mapAllocator {"(map<(" TYP_EXP "), (" TYP_EXP ")),.+allocator<pair<\\2 const, \\3>\\s*>\\s*"
216  , regex::ECMAScript | regex::optimize};
217 
218  static regex uniquePtr {"unique_ptr<(\\w+), default_delete<\\1>\\s*"
219  , regex::ECMAScript | regex::optimize};
220 
221  static regex lumieraP {"P<(\\w+), shared_ptr<\\1>\\s*"
222  , regex::ECMAScript | regex::optimize};
223 
224 
225  auto pos = typeName.begin();
226  auto end = typeName.end();
227 
228  end = regex_replace(pos, pos, end, commonPrefixes, "");
229  end = regex_replace(pos, pos, end, stdString, "string");
230  end = regex_replace(pos, pos, end, stdAllocator, "$1");
231  end = regex_replace(pos, pos, end, mapAllocator, "$1");
232  end = regex_replace(pos, pos, end, uniquePtr, "unique_ptr<$1");
233  end = regex_replace(pos, pos, end, lumieraP, "P<$1");
234 
235  typeName.resize(end - typeName.begin());
236  return typeName;
237  }
238 
239 
240 
259  string
261  {
262  string typeStr = demangleCxx (rawType);
263 
264  removeSuffix (typeStr, " const");
265  removeSuffix (typeStr, " const *");
266  removeSuffix (typeStr, "*");
267  removeSuffix (typeStr, "&");
268 
269  if (isnil (typeStr)) return VOID_INDICATOR;
270  if (')' == typeStr.back()) return FUNCTION_INDICATOR;
271 
272  auto end = typeStr.end();
273  auto beg = typeStr.begin();
274  int level=0;
275  while (--end != beg)
276  {
277  if ('>' == *end)
278  ++level;
279  else if ('<' == *end and level>0)
280  --level;
281  else
282  if (level==0)
283  {
284  ++end;
285  break;
286  }
287  }
288  if (end == beg) return VOID_INDICATOR;
289 
290  auto pos = typeStr.rfind("::", end-beg);
291  typeStr = (pos==string::npos? typeStr.substr(0, end-beg)
292  : typeStr.substr(pos+2, (end-beg)-pos-2));
293  return typeStr;
294  }
295 
296 
297  string
299  {
300  return util::sanitise (humanReadableTypeID (rawName));
301  }
302 
303 
304  string
305  sanitisedSymbol (string const& text)
306  {
307  static regex identifierChars {"[A-Za-z]\\w*", regex::ECMAScript | regex::optimize};
308 
309  return regex_replace (text, identifierChars, "$&", std::regex_constants::format_no_copy);
310  } // don't copy what does not match
311 
312 
313 
314 }}// namespace lib::meta
315 
316 
317 
318 
319 
320 /* === formatting and pretty printing support utils === */
321 
322 namespace util {
323 
324  using std::hex;
325  using std::setw;
326  using std::right;
327  using std::setfill;
328  using std::noshowbase;
329  using std::ostringstream;
330  using std::ostream;
331 
332 
340  string
341  showDouble (double val) noexcept
342  try {
343  ostringstream buffer;
344  buffer.precision (DIAGNOSTICS_DOUBLE_PRECISION);
345  buffer << val;
346  return buffer.str();
347  }
348  catch(...)
349  { return FAILURE_INDICATOR; }
350 
351 
352  string
353  showFloat (float val) noexcept
354  try {
355  ostringstream buffer;
356  buffer.precision (DIAGNOSTICS_FLOAT_PRECISION);
357  buffer << val;
358  return buffer.str();
359  }
360  catch(...)
361  { return FAILURE_INDICATOR; }
362 
363 
364  string
365  showSize (size_t val) noexcept
366  try {
367  ostringstream buffer;
368  buffer << val;
369  return buffer.str();
370  }
371  catch(...)
372  { return FAILURE_INDICATOR; }
373 
374 
376  ostream&
377  showAddr (ostream& stream, void const* addr)
378  {
379  IosSavepoint save{stream};
380  size_t suffix_modulus = size_t(1) << DIAGNOSTICS_ADDRESS_SUFFIX_LEN * 8;
381  return stream << "╲"
382  << hex
383  << noshowbase
384  << setw (DIAGNOSTICS_ADDRESS_SUFFIX_LEN * 2) // need 2 hex digits per byte
385  << setfill('_')
386  << right
387  << size_t(addr) % suffix_modulus;
388  }
389 
390 
391  string
392  showAddr (void const* addr) noexcept
393  try {
394  ostringstream buffer;
395  showAddr (buffer, addr);
396  return buffer.str();
397  }
398  catch(...)
399  { return FAILURE_INDICATOR; }
400 
401 
402 
403 } // namespace util
ostream & showAddr(ostream &stream, void const *addr)
preconfigured format for pretty-printing of addresses
Definition: format-obj.cpp:377
inline string literal This is a marker type to indicate that
Definition: symbol.hpp:75
Capture previous settings of an std::ostream and restore them when leaving scope. ...
string showDouble(double val) noexcept
pretty-print a double in fixed-point format
Definition: format-obj.cpp:341
Helper to deal with C-MALLOCed memory automatically.
Implementation namespace for support and library code.
string primaryTypeComponent(Literal rawType)
extract core name component from a raw type spec
Definition: format-obj.cpp:260
string sanitisedFullTypeName(lib::Literal rawName)
build a sanitised ID from full type name
Definition: format-obj.cpp:298
Marker types to indicate a literal string and a Symbol.
string demangleCxx(Literal rawName)
Fallback type-ID:
Definition: format-obj.cpp:158
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:189
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:77
string sanitisedSymbol(string const &text)
condense a string and retain only valid identifiers
Definition: format-obj.cpp:305
std::string typeStr(TY const *obj=nullptr) noexcept
failsafe human readable type display
Definition: meta/util.hpp:297