-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdebug.hpp
171 lines (145 loc) · 4.6 KB
/
debug.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#pragma once
/*******************************************************************************
* debug.hpp
*
* Some functions for onvenient Debugging
*
* dout(): returns output object for debug messages (switchable to file out ...)
*
* counter: defines a counter type that won't do anything if debug is turned of
* (note that it still consumes 1byte)
* checker: rai encapsulates a size_t counter and checks if the counter has the
* expected value when the checker is destroyed
* (used for checking the number of acquired/released smartpointers
* within a function)
*
* Part of my utils library utils_tm - https://github.com/TooBiased/utils_tm.git
*
* Copyright (C) 2019 Tobias Maier <[email protected]>
*
* All rights reserved. Published under the BSD-2 license in the LICENSE file.
******************************************************************************/
#include <atomic>
#include <iostream>
#include <string>
#ifndef NO_EXCEPT
#include <exception>
#endif
#include "output.hpp"
namespace utils_tm
{
namespace debug_tm
{
#ifdef DEBUG
constexpr bool debug_mode = true;
constexpr bool verbose_mode = false;
#else
constexpr bool debug_mode = false;
constexpr bool verbose_mode = false;
#endif
inline out_tm::output_type& dout()
{
static out_tm::output_type static_dout;
return static_dout;
}
// DEBUG OUTPUTS *** only print if debug_mode is on ************************
// outputs a message (in yellow) if in debug mode and condition is true
inline void if_debug(std::string&& str, [[maybe_unused]] bool condition = true)
{
if constexpr (debug_mode)
{
if (condition)
{
str.append("\n");
dout() << out_tm::color::yellow + str << std::flush;
}
}
}
// outputs an error message (in red) and exits if in debug mode and condition is
// true
inline void if_debug_critical(std::string&& str,
[[maybe_unused]] bool condition = true,
[[maybe_unused]] size_t error_code = 42)
{
if constexpr (debug_mode)
{
if (condition)
{
str.append("\n");
dout() << out_tm::color::red + str << std::flush;
#ifdef NO_EXCEPT
exit(error_code);
#else
throw std::runtime_error(str);
#endif
}
}
}
// outputs the message (in blue) if in verbose mode
inline void if_verbose(std::string&& str)
{
if constexpr (verbose_mode)
{
str.append("\n");
dout() << out_tm::color::blue + str << std::flush;
}
}
// COUNTER *** (either atomic_size_t or dummy_counter) *********************
// either an atomic counter or a dummy that does nothing
class dummy_counter
{
public:
dummy_counter(size_t = 0) {}
inline void store(size_t) const {}
inline size_t load() const { return 0; }
inline size_t operator++(int) const { return 0; }
};
using counter =
std::conditional<debug_mode, std::atomic<size_t>, dummy_counter>::type;
// CHECKER *** (either real_checker or dummy_checker) **********************
// on destructor checks wether the given counter has the expected difference
// used to sanity check the number of protected hazard counters
// two implementations real and dummy (debug mode or not)
class real_checker
{
private:
using ctype = size_t;
const ctype& _counter;
size_t _start;
size_t _exp_diff;
std::string _message;
public:
real_checker(const ctype& counter,
const std::string& msg,
size_t exp_diff = 0)
: _counter(counter), _start(counter), _exp_diff(exp_diff), _message(msg)
{
}
~real_checker()
{
auto temp = _counter;
if (temp != _start + _exp_diff)
dout() << _message << " -- expected " << _exp_diff << " got "
<< temp - _start << std::endl;
}
void add_message(const std::string& str) { _message.append(str); }
void check(const std::string& msg, size_t exp_diff = 0)
{
auto temp = _counter;
if (temp != _start + exp_diff)
dout() << msg << " -- expected " << exp_diff << " got "
<< temp - _start << std::endl;
}
void change_exp_diff(size_t diff) { _exp_diff = diff; }
};
class dummy_checker
{
public:
dummy_checker(const std::atomic_size_t&, const std::string&, size_t = 0) {}
void add_message(const std::string&) {}
void check(const std::string&, size_t = 0) {}
void change_exp_diff(size_t = 0) {}
};
using checker = std::conditional<debug_mode, real_checker, dummy_checker>::type;
} // namespace debug_tm
} // namespace utils_tm