65 #ifndef DEBUGPRINTER_HEADER 66 #define DEBUGPRINTER_HEADER 71 #define DEBUGPRINTER_OFF 74 #ifndef DEBUGPRINTER_OFF 84 #include <type_traits> 86 #ifndef DEBUGPRINTER_NO_EXECINFO 88 #endif // DEBUGPRINTER_NO_EXECINFO 90 #ifndef DEBUGPRINTER_NO_CXXABI 92 #endif // DEBUGPRINTER_NO_CXXABI 94 #ifndef DEBUGPRINTER_NO_SIGNALS 97 #endif // DEBUGPRINTER_NO_SIGNALS 99 #if defined (WIN32) || defined (_WIN32) // TODO: this can be improved a lot 100 #define DEBUGPRINTER_DIRSEP '\\' 102 #define DEBUGPRINTER_DIRSEP '/' 105 #endif // DEBUGPRINTER_OFF 110 #ifndef DEBUGPRINTER_OFF 169 #ifndef DEBUGPRINTER_NO_SIGNALS 170 struct sigaction act;
171 act.sa_handler = signal_handler;
172 for(
auto const & sig: sig_names()) {
173 sigaction(sig.first, &act, NULL);
175 #endif // DEBUGPRINTER_NO_SIGNALS 185 template <
typename T>
189 std::ostream& (*pf)(std::ostream&));
204 inline void operator=(std::ostream & os) noexcept { outstream = &os; }
220 template <
typename T>
222 -> std::enable_if_t<std::is_move_assignable<T>::value
223 && std::is_rvalue_reference<decltype(os)>::value> {
224 outstream_mm = std::shared_ptr<std::ostream>(
new T(std::move(os)));
225 outstream = outstream_mm.get();
235 inline void set_precision(
const std::streamsize prec) noexcept { prec_ = prec; }
250 if(is_number(str.substr(0,1)) && is_number(str.substr(2,2))) {
251 hcol_ =
"\033[" + str +
"m";
254 throw std::runtime_error(
"DebugPrinter error: invalid set_color() argument");
283 template <
typename T,
typename U>
285 const std::string sc =
": ")
const {
286 print_stream_impl< has_stream<T> && has_stream<U> >(label, obj, sc);
299 template <
typename T>
306 #ifndef DEBUGPRINTER_NO_EXECINFO 325 const int backtrace_size = max_backtrace,
326 const bool compact =
false,
330 std::ostream & out = *outstream;
332 using uint =
unsigned int;
334 uint end = begin + backtrace_size;
335 if(end > max_backtrace)
338 void *
stack[max_backtrace];
339 uint r = backtrace(stack, end);
340 if(end == max_backtrace)
343 char ** symbols = backtrace_symbols(stack, end);
346 out <<
"DebugPrinter obtained " << end-begin <<
" stack frames:" 350 #ifndef DEBUGPRINTER_NO_CXXABI 352 for(uint i = begin; i < end; ++i) {
353 std::string line = std::string(symbols[i]);
354 std::string prog = prog_part(line);
355 std::string mangled = mangled_part(line);
356 std::string offset = offset_part(line);
357 std::string mainoffset = address_part(line);
359 std::cerr <<
"DebugPrinter error: No dynamic symbol (you probably didn't compile with -rdynamic)" 362 std::string demangled = demangle(mangled, status);
365 out <<
"DebugPrinter error: Could not allocate memory!" << std::endl;
368 out <<
"DebugPrinter error: Invalid argument to demangle()" << std::endl;
375 out <<
" " << prog <<
": " << demangled <<
"\t+" 376 << offset <<
"\t[+" << mainoffset <<
"]"<< std::endl;
378 out << demangled << std::endl;
381 if(compact ==
false) out << std::endl;
383 #else // DEBUGPRINTER_NO_CXXABI 385 for(uint i = begin; i < end; ++i) {
387 out <<
" " << symbols[i] << std::endl;
389 out << mangled_part(std::string(symbols[i])) << std::endl;
392 if(compact ==
false) out << std::endl;
393 out <<
"echo '' && c++filt";
394 for(uint i = begin; i < end; ++i)
395 out <<
" " << mangled_part(std::string(symbols[i]));
396 out <<
" && echo ''" << std::endl;
397 if(compact ==
false) out << std::endl;
399 #endif // DEBUGPRINTER_NO_CXXABI 404 #else // DEBUGPRINTER_NO_EXECINFO 406 void stack(...)
const {
407 *outstream <<
"DebugPrinter::stack() not available" << std::endl;
410 #endif // DEBUGPRINTER_NO_EXECINFO 422 template<
typename T>
struct fwdtype {};
425 #define DEBUGPRINTER_TYPE_SPEC(mods) \ 426 template <typename T> \ 427 inline void type(detail::fwdtype<T mods>, \ 428 const std::string valness = "", \ 429 const std::string expr = "") const { \ 431 std::string info = ""; \ 433 info = " {" + valness + " " + expr + "}"; \ 434 auto mod = super.mod_split(std::string(#mods)); \ 435 super << mod.first << super.demangle(typeid(T).name(), dummy) \ 436 << mod.second << info << std::endl; \ 438 DEBUGPRINTER_TYPE_SPEC()
439 DEBUGPRINTER_TYPE_SPEC(&)
440 DEBUGPRINTER_TYPE_SPEC(&&)
441 DEBUGPRINTER_TYPE_SPEC(
const)
442 DEBUGPRINTER_TYPE_SPEC(
const &)
443 DEBUGPRINTER_TYPE_SPEC(
const &&)
444 DEBUGPRINTER_TYPE_SPEC(
volatile)
445 DEBUGPRINTER_TYPE_SPEC(
volatile &)
446 DEBUGPRINTER_TYPE_SPEC(
volatile &&)
447 DEBUGPRINTER_TYPE_SPEC(
const volatile)
448 DEBUGPRINTER_TYPE_SPEC(
const volatile &)
449 DEBUGPRINTER_TYPE_SPEC(
const volatile &&)
450 #undef DEBUGPRINTER_TYPE_SPEC 454 const std::string valueness(T &&)
const noexcept {
455 return super.valueness_impl(fwdtype<T>());
464 inline void type_name(
const std::string & name,
465 const std::string & traits =
"") {
467 *(super.outstream) << traits << super.demangle(name, dummy) << std::endl;
470 inline void pause(std::string reason)
const {
471 if(reason !=
"") reason =
" (" + reason +
")";
472 std::cout <<
"DebugPrinter paused" << reason
473 <<
". Press ENTER to continue." << std::flush;
475 std::cin.ignore(std::numeric_limits<std::streamsize>::max(),
'\n');
477 template <
typename T>
478 static const T & pausecheck(
const T & t) {
481 static bool pausecheck() {
return true; }
483 inline std::string filemacro_name(
const std::string str)
const {
484 return str.substr(str.rfind(DEBUGPRINTER_DIRSEP)+1);
487 }
const detail_{*
this};
496 std::ostream * outstream;
497 std::shared_ptr<std::ostream> outstream_mm;
498 std::streamsize prec_;
502 static const unsigned int max_backtrace = 50;
503 static const unsigned int max_demangled = 4096;
505 #ifndef DEBUGPRINTER_NO_SIGNALS 506 using sig_type = int;
507 static std::map<sig_type, std::string> sig_names() {
508 std::map<sig_type, std::string> res;
509 res[SIGABRT] =
"SIGABRT";
510 res[SIGFPE] =
"SIGFPE";
511 res[SIGSEGV] =
"SIGSEGV";
512 res[SIGSYS] =
"SIGSYS";
516 static void signal_handler(
int signum) {
518 d <<
"DebugPrinter handler caught signal " 519 << sig_names()[signum] <<
" (" << signum <<
")" << std::endl;
521 d.
stack(max_backtrace,
false, 3);
522 struct sigaction act;
523 act.sa_handler = SIG_DFL;
524 sigaction(signum, &act, NULL);
526 #endif // DEBUGPRINTER_NO_SIGNALS 528 #ifndef DEBUGPRINTER_NO_CXXABI 530 inline std::string demangle(
const std::string & str,
int & status)
const {
531 std::unique_ptr<char, void(*)(void*)>
532 dmgl(abi::__cxa_demangle(str.c_str(), 0, 0, &status), std::free);
533 return (status==0) ? dmgl.get() : str;
536 #else // DEBUGPRINTER_NO_CXXABI 538 inline std::string demangle(
const std::string & str,
int &)
const noexcept {
542 #endif // DEBUGPRINTER_NO_CXXABI 546 inline std::string prog_part(
const std::string str)
const {
547 std::stringstream ss(str);
549 ss >> res; ss >> res;
552 inline std::string mangled_part(
const std::string str)
const {
553 std::stringstream ss(str);
555 ss >> res; ss >> res; ss >> res; ss >> res;
558 inline std::string offset_part(
const std::string str)
const {
559 std::stringstream ss(str);
561 ss >> res; ss >> res; ss >> res; ss >> res; ss >> res; ss >> res;
564 inline std::string address_part(
const std::string str)
const {
565 std::stringstream ss(str);
567 ss >> res; ss >> res; ss >> res;
571 inline std::string prog_part(
const std::string str)
const {
572 return str.substr(0, str.find(
"("));
574 inline std::string mangled_part(
const std::string str)
const {
575 std::string::size_type pos = str.find(
"(") + 1;
576 if(str.find(
"+", pos) == std::string::npos)
return "";
577 return str.substr(pos, str.find(
"+", pos) - pos);
579 inline std::string offset_part(
const std::string str)
const {
580 std::string::size_type pos = str.find(
"+");
581 if(pos == std::string::npos)
return "";
582 else return str.substr(pos+1, str.find(
")", pos) - pos-1);
584 inline std::string address_part(
const std::string str)
const {
585 std::string::size_type pos = str.find(
"[");
586 if(pos == std::string::npos)
return "";
587 else return str.substr(pos+1, str.find(
"]", pos) - pos-1);
592 bool is_number(
const std::string& s)
const {
593 return !s.empty() && std::find_if(s.begin(), s.end(),
594 [](
char c) {
return !std::isdigit(c); }) == s.end();
598 template <
bool B,
typename U,
typename V>
600 print_stream_impl(
const U& label,
const V& obj,
const std::string&)
const {
601 auto typ = [
this](
const auto & obj)
602 {
int dummy = 0;
return demangle(
typeid(obj).name(), dummy); };
603 *outstream <<
"DebugPrinter error: object of type " 604 << ( has_stream<U> ? typ(obj) : typ(label) ) << std::endl
605 <<
" has no suitable " << typ(*outstream)
606 <<
" operator<< overload." << std::endl;
608 template <
bool B,
typename U,
typename V>
610 print_stream_impl(
const U& label,
const V& obj,
const std::string& sc)
const {
611 *outstream << hcol_ << label << sc << obj
612 << hcol_r_ << std::endl;
618 template <
bool B,
typename... T>
620 using type = std::integral_constant<bool , B>;
623 template <
bool B,
typename T,
typename... U>
624 struct m_and_impl<B, T, U...> {
625 using type =
typename m_and_impl<B && T::value, U...>::type;
627 template <
typename... T>
628 struct m_and :
public m_and_impl<true, T...>::type {
631 template<
typename T,
typename S>
632 struct has_stream_impl {
633 template <
typename T_,
typename S_>
634 static auto check(T_ && t, S_ && s) -> decltype(
637 static std::false_type check(...);
638 using type = decltype(check( std::declval<T>(), std::declval<S>()));
640 template<
typename T,
typename S = std::ostream&>
641 struct has_stream_t :
public has_stream_impl<T, S>::type {};
642 template<
typename T,
typename S = std::ostream&>
643 static constexpr
bool has_stream = has_stream_impl<T, S>::type::value;
648 std::pair<std::string, std::string> mod_split(
const std::string & s)
const {
649 auto pos = s.find(
'&');
650 pos = pos==std::string::npos ? s.size() : pos;
651 std::string first = s.substr(0, pos), second = s.substr(pos);
653 if(first.size() > 0 && first.back()!=
' ') first +=
" ";
654 if(second.size() > 0) second =
" " + second;
655 return std::make_pair(first, second);
659 template <
typename T>
660 const std::string valueness_impl(detail::fwdtype<T>)
const noexcept
661 {
return "r-value"; }
662 template <
typename T>
663 const std::string valueness_impl(detail::fwdtype<T&>)
const noexcept
664 {
return "l-value"; }
673 template <
typename T>
675 std::ostream & out = *d.outstream;
676 std::streamsize savep = out.precision();
677 std::ios_base::fmtflags savef =
678 out.setf(std::ios_base::fixed, std::ios::floatfield);
679 out << std::setprecision(static_cast<int>(d.prec_)) << std::fixed << output
680 << std::setprecision(static_cast<int>(savep));
681 out.setf(savef, std::ios::floatfield);
688 std::ostream& (*pf)(std::ostream&)) {
689 std::ostream & out = *d.outstream;
695 template <
typename T>
702 std::ostream& (*pf)(std::ostream&)) {
731 #define dout_HERE fsc::dout(fsc::dout.detail_.filemacro_name(__FILE__), \ 732 std::to_string(__LINE__) \ 733 + " (" + std::string(__func__) + ")",":"); // 750 #define dout_FUNC fsc::dout.stack(1, true); 768 #define dout_VAL(...) fsc::dout(#__VA_ARGS__, (__VA_ARGS__), " = "); 779 #define dout_TYPE(...) fsc::dout.detail_.type( \ 780 fsc::DebugPrinter::detail::fwdtype<__VA_ARGS__>() \ 795 #define dout_TYPE_OF(...) fsc::dout.detail_.type( \ 796 fsc::DebugPrinter::detail::fwdtype<decltype(__VA_ARGS__)>() \ 797 , fsc::dout.detail_.valueness(__VA_ARGS__) \ 819 #define dout_STACK fsc::dout.stack(); 835 #define dout_PAUSE(...) \ 836 if(fsc::dout.detail_.pausecheck(__VA_ARGS__)) \ 837 fsc::dout.detail_.pause(#__VA_ARGS__); // 843 #else // DEBUGPRINTER_OFF 847 inline void operator=(std::ostream &) noexcept {}
848 inline void operator=(std::ostream &&) {}
852 inline void stack(...)
const {}
855 template <
typename T>
858 std::ostream& (*)(std::ostream&)) {
return d;}
859 template <
typename T>
862 std::ostream& (*)(std::ostream&)) {
return d;}
868 #define dout_VAL(...) ; 869 #define dout_TYPE(...) ; 870 #define dout_TYPE_OF(...) ; 872 #define dout_PAUSE(...) ; 874 #endif // DEBUGPRINTER_OFF 878 namespace dont_even_ask {
880 inline void function() { (void)dout; }
888 #endif // DEBUGPRINTER_HEADER void operator()(const T &label, U const &obj, const std::string sc=": ") const
Print highlighted label and object.
DebugPrinter()
Constructor for dout and user specified DebugPrinter objects.
Class for global static dout object.
void set_color(const std::string str)
Highlighting color.
DebugPrinter & operator,(DebugPrinter &d, const T &output)
operator, overload for std::ostream
void stack(const int backtrace_size=max_backtrace, const bool compact=false, const int begin=1) const
Print a stack trace.
friend DebugPrinter & operator<<(DebugPrinter &, const T &)
operator<< overload for std::ostream
auto operator=(T &&os) -> std::enable_if_t< std::is_move_assignable< T >::value &&std::is_rvalue_reference< decltype(os)>::value >
Assignment operator for moving streams.
void operator()(const T &obj) const
Print highlighted object.
void set_color() noexcept
Remove highlighting color.
void operator=(std::ostream &os) noexcept
Assignment operator for changing streams.
void set_precision(const std::streamsize prec) noexcept
Number of displayed decimal digits.