line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
#pragma once |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
#include |
4
|
|
|
|
|
|
|
#include |
5
|
|
|
|
|
|
|
#include |
6
|
|
|
|
|
|
|
#include |
7
|
|
|
|
|
|
|
#include |
8
|
|
|
|
|
|
|
#include |
9
|
|
|
|
|
|
|
#include |
10
|
|
|
|
|
|
|
#include |
11
|
|
|
|
|
|
|
#include |
12
|
|
|
|
|
|
|
#include |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
namespace panda { |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
namespace logger { |
17
|
|
|
|
|
|
|
struct CodePoint; |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
template |
20
|
|
|
|
|
|
|
S& operator <<(S& stream, const CodePoint& cp); |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
struct CodePoint { |
23
|
|
|
|
|
|
|
std::string_view file; |
24
|
|
|
|
|
|
|
uint32_t line; |
25
|
|
|
|
|
|
|
|
26
|
0
|
|
|
|
|
|
std::string to_string() const { |
27
|
0
|
0
|
|
|
|
|
std::ostringstream os; |
28
|
0
|
0
|
|
|
|
|
os << *this; |
29
|
0
|
0
|
|
|
|
|
os.flush(); |
30
|
0
|
0
|
|
|
|
|
return os.str(); |
31
|
|
|
|
|
|
|
} |
32
|
|
|
|
|
|
|
}; |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
template |
35
|
0
|
|
|
|
|
|
S& operator <<(S& stream, const CodePoint& cp) { |
36
|
0
|
|
|
|
|
|
size_t total = cp.file.size() + log10(cp.line) + 2; |
37
|
0
|
|
|
|
|
|
const char* whitespaces = " "; // 24 spaces |
38
|
0
|
0
|
|
|
|
|
if (total < 24) { |
39
|
0
|
|
|
|
|
|
whitespaces += total; |
40
|
|
|
|
|
|
|
} else { |
41
|
0
|
|
|
|
|
|
whitespaces = ""; |
42
|
|
|
|
|
|
|
} |
43
|
0
|
|
|
|
|
|
stream << cp.file << ":" << cp.line << whitespaces; |
44
|
0
|
|
|
|
|
|
return stream; |
45
|
|
|
|
|
|
|
} |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
enum Level { |
49
|
|
|
|
|
|
|
EMERGENCY, |
50
|
|
|
|
|
|
|
CRITICAL, |
51
|
|
|
|
|
|
|
WARNING, |
52
|
|
|
|
|
|
|
INFO, |
53
|
|
|
|
|
|
|
VERBOSE, |
54
|
|
|
|
|
|
|
DEBUG |
55
|
|
|
|
|
|
|
}; |
56
|
|
|
|
|
|
|
|
57
|
0
|
|
|
|
|
|
struct ILogger { |
58
|
0
|
|
|
|
|
|
virtual bool should_log(Level, CodePoint) {return true;} |
59
|
|
|
|
|
|
|
virtual void log(Level, CodePoint, const std::string&) = 0; |
60
|
|
|
|
|
|
|
}; |
61
|
|
|
|
|
|
|
} |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
class Log |
64
|
|
|
|
|
|
|
{ |
65
|
|
|
|
|
|
|
public: |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
Log(logger::CodePoint cp, logger::Level log_level = logger::DEBUG) |
68
|
|
|
|
|
|
|
: level(log_level), |
69
|
|
|
|
|
|
|
cp(cp) |
70
|
|
|
|
|
|
|
{} |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
Log(Log&& oth) = default; |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
explicit operator bool() const { |
75
|
|
|
|
|
|
|
return should_log(level, cp); |
76
|
|
|
|
|
|
|
} |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
template |
79
|
|
|
|
|
|
|
std::ostringstream& operator <<(T&& t) |
80
|
|
|
|
|
|
|
{ |
81
|
|
|
|
|
|
|
os << t; |
82
|
|
|
|
|
|
|
return os; |
83
|
|
|
|
|
|
|
} |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
~Log() |
86
|
|
|
|
|
|
|
{ |
87
|
|
|
|
|
|
|
if (!logger()) { |
88
|
|
|
|
|
|
|
return; |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
os.flush(); |
91
|
|
|
|
|
|
|
s = os.str(); |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
logger()->log(level, cp, s); |
94
|
|
|
|
|
|
|
} |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
static std::unique_ptr& logger(); |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
static bool should_log(logger::Level level, logger::CodePoint cp); |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
static void set_max_level(logger::Level val); |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
private: |
103
|
|
|
|
|
|
|
std::string s; |
104
|
|
|
|
|
|
|
std::ostringstream os; |
105
|
|
|
|
|
|
|
logger::Level level; |
106
|
|
|
|
|
|
|
logger::CodePoint cp; |
107
|
|
|
|
|
|
|
}; |
108
|
|
|
|
|
|
|
#ifdef WIN323 |
109
|
|
|
|
|
|
|
# define __FILENAME__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__) |
110
|
|
|
|
|
|
|
#else |
111
|
|
|
|
|
|
|
# define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) |
112
|
|
|
|
|
|
|
#endif // WIN32 |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
#define _panda_code_point_ panda::logger::CodePoint{__FILENAME__, __LINE__} |
115
|
|
|
|
|
|
|
#define _panda_log_impl_(LEVEL, MSG) panda::Log::should_log(panda::logger::LEVEL, _panda_code_point_) \ |
116
|
|
|
|
|
|
|
&& (panda::Log(_panda_code_point_, panda::logger::LEVEL) << MSG) |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
#define panda_debug_v(VAR) _panda_log_impl_(DEBUG, #VAR << " = " << (VAR)) |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
#define panda_log_debug(MSG) _panda_log_impl_(DEBUG, MSG) |
121
|
|
|
|
|
|
|
#define panda_log_verbose(MSG) _panda_log_impl_(VERBOSE, MSG) |
122
|
|
|
|
|
|
|
#define panda_log_info(MSG) _panda_log_impl_(INFO, MSG) |
123
|
|
|
|
|
|
|
#define panda_log_warn(MSG) _panda_log_impl_(WARNING, MSG) |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
#define panda_log_critical(MSG) _panda_log_impl_(CRITICAL, MSG) |
126
|
|
|
|
|
|
|
#define panda_log_emergency(MSG) _panda_log_impl_(EMERGENCY, MSG) |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
#define PANDA_ASSERT(VAR, MSG) if(!(auto assert_value = VAR)) {panda_log_emergency("assert failed: " << #VAR << " is " << assert_value << MSG)} |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
} |