2019-10-06 16:45:29 +02:00
|
|
|
// 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(<expression>);
|
|
|
|
// initialize with dbg_init() to enable colorized output
|
|
|
|
//
|
|
|
|
|
2019-10-06 17:16:19 +02:00
|
|
|
#ifndef SOI_DBG
|
|
|
|
#define SOI_DBG
|
2019-10-06 16:45:29 +02:00
|
|
|
|
|
|
|
#include <cstddef>
|
|
|
|
#include <cstring>
|
2019-10-06 17:19:10 +02:00
|
|
|
#include <iostream>
|
2019-10-06 18:38:23 +02:00
|
|
|
#include <ostream>
|
2019-10-06 17:19:10 +02:00
|
|
|
#include <sstream>
|
2019-10-06 18:38:23 +02:00
|
|
|
#include <stdexcept>
|
2019-10-06 16:45:29 +02:00
|
|
|
|
2019-10-06 20:56:37 +02:00
|
|
|
#ifdef __GNUG__
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <cxxabi.h>
|
2019-10-06 21:55:47 +02:00
|
|
|
#include <memory>
|
2019-10-06 20:56:37 +02:00
|
|
|
#endif
|
|
|
|
|
2019-10-06 16:45:29 +02:00
|
|
|
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "soi-pretty.hpp"
|
|
|
|
|
2019-10-06 18:37:37 +02:00
|
|
|
namespace soi {
|
2019-10-06 16:45:29 +02:00
|
|
|
|
|
|
|
namespace detail {
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
2019-10-06 20:56:37 +02:00
|
|
|
// pretty printing the type name
|
2019-10-06 16:45:29 +02:00
|
|
|
|
2019-10-06 21:55:47 +02:00
|
|
|
struct string_view {
|
|
|
|
char const *data;
|
|
|
|
std::size_t size;
|
2019-10-06 16:45:29 +02:00
|
|
|
};
|
|
|
|
|
2019-10-06 21:55:47 +02:00
|
|
|
template <class T> string_view get_name() {
|
|
|
|
char const *p = __PRETTY_FUNCTION__;
|
|
|
|
while (*p++ != '=')
|
|
|
|
;
|
|
|
|
for (; *p == ' '; ++p)
|
|
|
|
;
|
|
|
|
char const *p2 = p;
|
|
|
|
int count = 1;
|
|
|
|
for (;; ++p2) {
|
|
|
|
switch (*p2) {
|
|
|
|
case '[':
|
|
|
|
++count;
|
|
|
|
break;
|
|
|
|
case ']':
|
|
|
|
--count;
|
|
|
|
if (!count)
|
|
|
|
return {p, std::size_t(p2 - p)};
|
2019-10-06 20:56:37 +02:00
|
|
|
}
|
2019-10-06 21:55:47 +02:00
|
|
|
}
|
|
|
|
return {};
|
2019-10-06 16:45:29 +02:00
|
|
|
}
|
|
|
|
|
2019-10-06 21:55:47 +02:00
|
|
|
std::string replace_all(std::string str, const std::string &from,
|
|
|
|
const std::string &to) {
|
|
|
|
size_t start_pos = 0;
|
|
|
|
while ((start_pos = str.find(from, start_pos)) != std::string::npos) {
|
|
|
|
str.replace(start_pos, from.length(), to);
|
|
|
|
start_pos +=
|
|
|
|
to.length(); // Handles case where 'to' is a substring of 'from'
|
|
|
|
}
|
|
|
|
return str;
|
2019-10-06 16:45:29 +02:00
|
|
|
}
|
|
|
|
|
2019-10-07 14:29:45 +02:00
|
|
|
inline std::string sanitize_type(std::string s) {
|
2019-10-06 20:56:37 +02:00
|
|
|
auto f = [&](const char *a, const char *b) {
|
2019-10-06 21:55:47 +02:00
|
|
|
s = replace_all(std::move(s), a, b);
|
|
|
|
};
|
2019-10-06 20:56:37 +02:00
|
|
|
f("std::", "");
|
|
|
|
f("__debug::", "");
|
|
|
|
f("__cxx11::", "");
|
2019-10-07 13:18:07 +02:00
|
|
|
f("basic_string<char> ", "string");
|
2019-10-06 20:56:37 +02:00
|
|
|
f("basic_string<char>", "string");
|
|
|
|
f("long int", "int");
|
|
|
|
return s;
|
2019-10-06 17:33:18 +02:00
|
|
|
}
|
|
|
|
|
2019-10-06 20:56:37 +02:00
|
|
|
template <class T> std::string sanitized_type_name() {
|
|
|
|
auto t = get_name<T>();
|
|
|
|
return sanitize_type(std::string(t.data, t.size));
|
2019-10-06 16:45:29 +02:00
|
|
|
}
|
2019-10-06 17:16:19 +02:00
|
|
|
|
2019-10-07 14:29:45 +02:00
|
|
|
inline std::string extract_method_name(std::string const& pretty_function) {
|
|
|
|
size_t colons = pretty_function.find("::");
|
|
|
|
size_t begin = pretty_function.substr(0,colons).rfind(" ") + 1;
|
|
|
|
size_t end = pretty_function.rfind("(") - begin;
|
|
|
|
return pretty_function.substr(begin,end);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-10-06 16:45:29 +02:00
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// 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() {
|
2019-10-06 18:38:23 +02:00
|
|
|
if (const char *color_enabled = std::getenv("SOI_COLOR")) {
|
2019-10-06 16:45:29 +02:00
|
|
|
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<bool>(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// init and static variables
|
|
|
|
|
|
|
|
static bool colors_enabled = false;
|
2019-10-06 18:38:23 +02:00
|
|
|
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 = "";
|
2019-10-06 16:45:29 +02:00
|
|
|
|
|
|
|
void dbg_init(bool with_colors) {
|
|
|
|
if (with_colors) {
|
|
|
|
bool colors_enabled = true;
|
2019-10-06 17:36:04 +02:00
|
|
|
ANSI_DEBUG = "\x1b[37m";
|
2019-10-06 16:45:29 +02:00
|
|
|
ANSI_EXPRESSION = "\x1b[36m";
|
|
|
|
ANSI_VALUE = "\x1b[01m";
|
|
|
|
ANSI_TYPE = "\x1b[32m";
|
2019-10-06 17:36:04 +02:00
|
|
|
ANSI_MESSAGE = "\x1b[31;01m";
|
2019-10-06 16:45:29 +02:00
|
|
|
ANSI_RESET = "\x1b[0m";
|
|
|
|
} else {
|
|
|
|
bool colors_enabled = false;
|
|
|
|
ANSI_DEBUG = "";
|
|
|
|
ANSI_EXPRESSION = "";
|
|
|
|
ANSI_VALUE = "";
|
|
|
|
ANSI_TYPE = "";
|
|
|
|
ANSI_MESSAGE = "";
|
|
|
|
ANSI_RESET = "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-06 18:38:23 +02:00
|
|
|
void dbg_init() { dbg_init(are_colors_enabled()); }
|
2019-10-06 16:45:29 +02:00
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// printer
|
|
|
|
|
|
|
|
template <typename T>
|
2019-10-07 14:29:45 +02:00
|
|
|
T &&dbg_print(T &&value, std::string const& type, char const *file, int line,
|
|
|
|
std::string const& function_name, char const *expression) {
|
2019-10-06 18:38:23 +02:00
|
|
|
const T &ref = value;
|
|
|
|
std::stringstream
|
2019-10-07 14:29:45 +02:00
|
|
|
value_buffer; // avoid nesting of dbg macros within print functions
|
2019-10-06 18:37:37 +02:00
|
|
|
soi::print(value_buffer, ref);
|
2019-10-06 16:45:29 +02:00
|
|
|
|
2019-10-06 18:38:23 +02:00
|
|
|
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 << ")"
|
2019-10-06 16:45:29 +02:00
|
|
|
<< '\n';
|
|
|
|
|
|
|
|
return std::forward<T>(value);
|
|
|
|
}
|
|
|
|
|
2019-10-06 18:38:23 +02:00
|
|
|
template <unsigned int N>
|
2019-10-06 20:56:37 +02:00
|
|
|
auto dbg_print(const char (&msg)[N], std::string const &, char const *file,
|
2019-10-07 14:29:45 +02:00
|
|
|
int line, std::string const& function_name, char const *expression)
|
2019-10-06 18:38:23 +02:00
|
|
|
-> decltype(msg) {
|
|
|
|
std::cerr << ANSI_DEBUG << "[" << file << ":" << line << " (" << function_name
|
|
|
|
<< ")] " << ANSI_RESET << ANSI_MESSAGE << msg << ANSI_RESET << '\n';
|
2019-10-06 16:45:29 +02:00
|
|
|
return msg;
|
|
|
|
}
|
|
|
|
|
2019-10-06 21:17:37 +02:00
|
|
|
void dbg_print_status(char const *file, int line, char const *function_name) {
|
|
|
|
std::cerr << ANSI_VALUE << "[" << file << ":" << line << " (" << function_name
|
2019-10-07 13:10:16 +02:00
|
|
|
<< ")]" << ANSI_RESET << '\n';
|
2019-10-06 21:17:37 +02:00
|
|
|
}
|
|
|
|
|
2019-10-06 18:38:23 +02:00
|
|
|
template <typename T> T &&identity(T &&t) { return std::forward<T>(t); }
|
2019-10-06 16:45:29 +02:00
|
|
|
|
|
|
|
} // end namespace detail
|
|
|
|
|
2019-10-06 18:38:23 +02:00
|
|
|
} // namespace soi
|
2019-10-06 16:45:29 +02:00
|
|
|
|
2019-10-06 17:16:19 +02:00
|
|
|
#ifdef SOI_RELEASE
|
2019-10-06 16:45:29 +02:00
|
|
|
#define dbg(...) dbg_macro::identity(__VA_ARGS__)
|
|
|
|
#else
|
2019-10-06 21:17:37 +02:00
|
|
|
|
2019-10-06 21:54:43 +02:00
|
|
|
#if defined(__clang__)
|
|
|
|
|
2019-10-06 21:55:47 +02:00
|
|
|
#define SOI_ARG16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, \
|
|
|
|
_14, _15, ...) \
|
|
|
|
_15
|
|
|
|
#define SOI_IS_NONEMPTY(...) \
|
|
|
|
SOI_ARG16(1, ##__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0)
|
2019-10-06 21:54:43 +02:00
|
|
|
#else
|
|
|
|
|
2019-10-07 14:29:45 +02:00
|
|
|
#define SOI_IS_NONEMPTY(...) __VA_OPT__(1)
|
|
|
|
#define SOI_DBG_IMPL_ SOI_DBG_IMPL_0
|
|
|
|
#endif
|
2019-10-06 21:54:43 +02:00
|
|
|
|
2019-10-07 14:29:45 +02:00
|
|
|
#define SOI_DBG_IMPL_0() \
|
2019-10-06 21:54:43 +02:00
|
|
|
soi::detail::dbg_print_status(__FILE__, __LINE__, __func__)
|
2019-10-07 14:29:45 +02:00
|
|
|
#define SOI_DBG_IMPL_1(...) \
|
2019-10-06 21:55:47 +02:00
|
|
|
soi::detail::dbg_print( \
|
|
|
|
(__VA_ARGS__), \
|
|
|
|
soi::detail::sanitized_type_name<decltype(__VA_ARGS__)>(), __FILE__, \
|
2019-10-07 14:29:45 +02:00
|
|
|
__LINE__, soi::detail::extract_method_name(__PRETTY_FUNCTION__), #__VA_ARGS__)
|
2019-10-06 21:17:37 +02:00
|
|
|
|
|
|
|
#define SOI_CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__)
|
2019-10-06 21:55:47 +02:00
|
|
|
#define SOI_PRIMITIVE_CAT(a, ...) a##__VA_ARGS__
|
2019-10-06 21:17:37 +02:00
|
|
|
|
2019-10-06 21:55:47 +02:00
|
|
|
#define SOI_DBG_IMPL(is_nonempty, ...) \
|
2019-10-06 21:17:37 +02:00
|
|
|
SOI_PRIMITIVE_CAT(SOI_DBG_IMPL_, is_nonempty)(__VA_ARGS__)
|
|
|
|
|
2019-10-06 21:55:47 +02:00
|
|
|
#define dbg(...) SOI_DBG_IMPL(SOI_IS_NONEMPTY(__VA_ARGS__), __VA_ARGS__)
|
2019-10-06 16:45:29 +02:00
|
|
|
#endif
|
|
|
|
|
2019-10-06 18:38:23 +02:00
|
|
|
#endif // SOI_DBG
|