use runtime function to pretty print type name

This commit is contained in:
Johannes Kapfhammer 2019-10-06 20:56:37 +02:00
parent 492a0f3c55
commit daeda942ad
2 changed files with 57 additions and 88 deletions

View File

@ -15,5 +15,7 @@ signed main() {
dbg(vector<pair<int, vector<string>>>{{3,{"hi"}},{4,{"hello", "world"}}}); dbg(vector<pair<int, vector<string>>>{{3,{"hi"}},{4,{"hello", "world"}}});
dbg(set<int>{3,1,4}); dbg(set<int>{3,1,4});
dbg(map<int, string>{{3,"three"},{1,"one"}}); dbg(map<int, string>{{3,"three"},{1,"one"}});
dbg(unordered_map<int, string>{{3,"three"},{1,"one"}});
dbg(unordered_set<int>{3,1,4});
cout << "hi\n"; cout << "hi\n";
} }

View File

@ -17,6 +17,12 @@
#include <sstream> #include <sstream>
#include <stdexcept> #include <stdexcept>
#ifdef __GNUG__
#include <cstdlib>
#include <memory>
#include <cxxabi.h>
#endif
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) #if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
#include <unistd.h> #include <unistd.h>
#endif #endif
@ -28,102 +34,63 @@ namespace soi {
namespace detail { namespace detail {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// detecting the type name: https://stackoverflow.com/a/20170989 // pretty printing the type name
#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 { struct string_view
const char *const p_; {
const std::size_t sz_; char const* data;
std::size_t size;
public:
typedef const char *const_iterator;
template <std::size_t N>
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) { template<class T>
return os.write(s.data(), s.size()); constexpr 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)};
}
}
return {};
} }
template <class T> CONSTEXPR14_TN static_string type_name() { std::string replace_all(std::string str, const std::string& from, const std::string& to) {
const int k = sizeof("constexpr soi::detail:: T") / sizeof(char); size_t start_pos = 0;
#ifdef __clang__ while((start_pos = str.find(from, start_pos)) != std::string::npos) {
static_string p = __PRETTY_FUNCTION__; str.replace(start_pos, from.length(), to);
return static_string(p.data() + 31 + k, p.size() - 31 - k - 1); start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
#elif defined(__GNUC__) }
static_string p = __PRETTY_FUNCTION__; return str;
#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) { std::string sanitize_type(std::string s) {
return suffix[0] == '\0' || auto f = [&](const char *a, const char *b) {
(suffix[0] == s[0] && is_prefix_of(suffix + 1, s + 1)); s = replace_all(std::move(s), a, b);
};
f("std::", "");
f("__debug::", "");
f("__cxx11::", "");
f("basic_string<char>", "string");
f("long int", "int");
return s;
} }
static char const *const type_string = "string"; template <class T> std::string sanitized_type_name() {
auto t = get_name<T>();
template <class T> CONSTEXPR14_TN static_string sanitized_type_name() { return sanitize_type(std::string(t.data, t.size));
CONSTEXPR14_TN static_string t = type_name<T>();
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<char>", t.data())
? static_string(type_string, sizeof(type_string) - 2)
: static_string(t.data() + offset, t.size() - offset);
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -191,7 +158,7 @@ void dbg_init() { dbg_init(are_colors_enabled()); }
// printer // printer
template <typename T> template <typename T>
T &&dbg_print(T &&value, static_string const &type, char const *file, int line, T &&dbg_print(T &&value, std::string const &type, char const *file, int line,
char const *function_name, char const *expression) { char const *function_name, char const *expression) {
const T &ref = value; const T &ref = value;
std::stringstream std::stringstream
@ -208,7 +175,7 @@ T &&dbg_print(T &&value, static_string const &type, char const *file, int line,
} }
template <unsigned int N> template <unsigned int N>
auto dbg_print(const char (&msg)[N], static_string const &, char const *file, auto dbg_print(const char (&msg)[N], std::string const &, char const *file,
int line, char const *function_name, char const *expression) int line, char const *function_name, char const *expression)
-> decltype(msg) { -> decltype(msg) {
std::cerr << ANSI_DEBUG << "[" << file << ":" << line << " (" << function_name std::cerr << ANSI_DEBUG << "[" << file << ":" << line << " (" << function_name