// Copyright Johannes Kapfhammer 2019. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // A debug macro: allows debugging with dbg(); // initialize with dbg_init() to enable colorized output // #ifndef SOI_DBG #define SOI_DBG #include #include #include #include #include #include #if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) #include #endif #include "soi-pretty.hpp" namespace soi { namespace detail { // ---------------------------------------------------------------------------- // detecting the type name: https://stackoverflow.com/a/20170989 #ifndef _MSC_VER #if __cplusplus < 201103 #define CONSTEXPR11_TN #define CONSTEXPR14_TN #define NOEXCEPT_TN #elif __cplusplus < 201402 #define CONSTEXPR11_TN constexpr #define CONSTEXPR14_TN #define NOEXCEPT_TN noexcept #else #define CONSTEXPR11_TN constexpr #define CONSTEXPR14_TN constexpr #define NOEXCEPT_TN noexcept #endif #else // _MSC_VER #if _MSC_VER < 1900 #define CONSTEXPR11_TN #define CONSTEXPR14_TN #define NOEXCEPT_TN #elif _MSC_VER < 2000 #define CONSTEXPR11_TN constexpr #define CONSTEXPR14_TN #define NOEXCEPT_TN noexcept #else #define CONSTEXPR11_TN constexpr #define CONSTEXPR14_TN constexpr #define NOEXCEPT_TN noexcept #endif #endif // _MSC_VER class static_string { const char *const p_; const std::size_t sz_; public: typedef const char *const_iterator; template CONSTEXPR11_TN static_string(const char (&a)[N]) NOEXCEPT_TN : p_(a), sz_(N - 1) {} CONSTEXPR11_TN static_string(const char *p, std::size_t N) NOEXCEPT_TN : p_(p), sz_(N) {} CONSTEXPR11_TN const char *data() const NOEXCEPT_TN { return p_; } CONSTEXPR11_TN std::size_t size() const NOEXCEPT_TN { return sz_; } CONSTEXPR11_TN const_iterator begin() const NOEXCEPT_TN { return p_; } CONSTEXPR11_TN const_iterator end() const NOEXCEPT_TN { return p_ + sz_; } CONSTEXPR11_TN char operator[](std::size_t n) const { return n < sz_ ? p_[n] : throw std::out_of_range("static_string"); } }; inline std::ostream &operator<<(std::ostream &os, static_string const &s) { return os.write(s.data(), s.size()); } template CONSTEXPR14_TN static_string type_name() { const int k = sizeof("constexpr soi::detail:: T") / sizeof(char); #ifdef __clang__ static_string p = __PRETTY_FUNCTION__; return static_string(p.data() + 31 + k, p.size() - 31 - k - 1); #elif defined(__GNUC__) static_string p = __PRETTY_FUNCTION__; #if __cplusplus < 201402 return static_string(p.data() + 36 + k, p.size() - 36 - k - 1); #else return static_string(p.data() + 46 + k, p.size() - 46 - k - 1); #endif #elif defined(_MSC_VER) static_string p = __FUNCSIG__; return static_string(p.data() + 38 + k, p.size() - 38 - k - 7); #endif } constexpr bool is_prefix_of(char const *suffix, char const *s) { return suffix[0] == '\0' || (suffix[0] == s[0] && is_prefix_of(suffix + 1, s + 1)); } static char const *const type_string = "string"; template CONSTEXPR14_TN static_string sanitized_type_name() { CONSTEXPR14_TN static_string t = type_name(); CONSTEXPR14_TN std::size_t offset = is_prefix_of("std::__debug::", t.data()) ? sizeof("std::__debug::") - 1 : is_prefix_of("std::", t.data()) ? sizeof("std::") - 1 : 0; return is_prefix_of("std::__cxx11::basic_string", t.data()) ? static_string(type_string, sizeof(type_string) - 2) : static_string(t.data() + offset, t.size() - offset); } // ---------------------------------------------------------------------------- // colorized output bool tty_supports_colors() { #if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) return isatty(STDERR_FILENO); #else return true; #endif } int has_environment_color_overwrite() { if (const char *color_enabled = std::getenv("SOI_COLOR")) { if (!std::strcmp(color_enabled, "1")) return 1; if (!std::strcmp(color_enabled, "0")) return 0; } return -1; } bool are_colors_enabled() { int c = has_environment_color_overwrite(); if (c == -1) return tty_supports_colors(); return static_cast(c); } // ---------------------------------------------------------------------------- // init and static variables static bool colors_enabled = false; static const char *ANSI_DEBUG = ""; static const char *ANSI_EXPRESSION = ""; static const char *ANSI_VALUE = ""; static const char *ANSI_TYPE = ""; static const char *ANSI_MESSAGE = ""; static const char *ANSI_RESET = ""; void dbg_init(bool with_colors) { if (with_colors) { bool colors_enabled = true; ANSI_DEBUG = "\x1b[37m"; ANSI_EXPRESSION = "\x1b[36m"; ANSI_VALUE = "\x1b[01m"; ANSI_TYPE = "\x1b[32m"; ANSI_MESSAGE = "\x1b[31;01m"; ANSI_RESET = "\x1b[0m"; } else { bool colors_enabled = false; ANSI_DEBUG = ""; ANSI_EXPRESSION = ""; ANSI_VALUE = ""; ANSI_TYPE = ""; ANSI_MESSAGE = ""; ANSI_RESET = ""; } } void dbg_init() { dbg_init(are_colors_enabled()); } // ---------------------------------------------------------------------------- // printer template T &&dbg_print(T &&value, static_string const &type, char const *file, int line, char const *function_name, char const *expression) { const T &ref = value; std::stringstream value_buffer; // avoid nesting of dbg macros within print functinos soi::print(value_buffer, ref); std::cerr << ANSI_DEBUG << "[" << file << ":" << line << " (" << function_name << ")] " << ANSI_RESET << ANSI_EXPRESSION << expression << ANSI_RESET << " = " << ANSI_VALUE << value_buffer.rdbuf() << ANSI_RESET << " (" << ANSI_TYPE << type << ANSI_RESET << ")" << '\n'; return std::forward(value); } template auto dbg_print(const char (&msg)[N], static_string const &, char const *file, int line, char const *function_name, char const *expression) -> decltype(msg) { std::cerr << ANSI_DEBUG << "[" << file << ":" << line << " (" << function_name << ")] " << ANSI_RESET << ANSI_MESSAGE << msg << ANSI_RESET << '\n'; return msg; } template T &&identity(T &&t) { return std::forward(t); } } // end namespace detail } // namespace soi #ifdef SOI_RELEASE #define dbg(...) dbg_macro::identity(__VA_ARGS__) #else #define dbg(...) \ soi::detail::dbg_print( \ (__VA_ARGS__), \ soi::detail::sanitized_type_name(), __FILE__, \ __LINE__, __func__, #__VA_ARGS__) #endif #endif // SOI_DBG