// 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_h { 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_h::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_h::pretty_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 } // end namespace dbg_macro #ifdef SOI_RELEASE #define dbg(...) dbg_macro::identity(__VA_ARGS__) #else #define dbg(...) \ soi_h::detail::dbg_print((__VA_ARGS__), \ soi_h::detail::sanitized_type_name(), \ __FILE__, \ __LINE__, \ __func__, \ #__VA_ARGS__) #endif #endif // SOI_DBG