tlx
Loading...
Searching...
No Matches
core.hpp
Go to the documentation of this file.
1/*******************************************************************************
2 * tlx/die/core.hpp
3 *
4 * Part of tlx - http://panthema.net/tlx
5 *
6 * Copyright (C) 2016-2018 Timo Bingmann <tb@panthema.net>
7 *
8 * All rights reserved. Published under the Boost Software License, Version 1.0
9 ******************************************************************************/
10
11#ifndef TLX_DIE_CORE_HEADER
12#define TLX_DIE_CORE_HEADER
13
14#include <cstring>
15#include <iomanip>
16#include <sstream>
17#include <stdexcept>
18#include <string>
19
20namespace tlx {
21
22/******************************************************************************/
23// die macros
24
25//! die with message - either throw an exception or die via std::terminate()
26void die_with_message(const std::string& msg);
27
28//! die with message - either throw an exception or die via std::terminate()
29void die_with_message(const char* msg, const char* file, size_t line);
30
31//! die with message - either throw an exception or die via std::terminate()
32void die_with_message(const std::string& msg, const char* file, size_t line);
33
34//! Instead of std::terminate(), throw the output the message via an exception.
35#define tlx_die_with_sstream(msg) \
36 do { \
37 std::ostringstream oss__; \
38 oss__ << msg << " @ " << __FILE__ << ':' << __LINE__; \
39 ::tlx::die_with_message(oss__.str()); \
40 std::terminate(); /* tell compiler this never returns */ \
41 } while (false)
42
43//! Instead of std::terminate(), throw the output the message via an exception.
44#define tlx_die(msg) \
45 do { \
46 tlx_die_with_sstream("DIE: " << msg); \
47 } while (false)
48
49//! Exception thrown by die_with_message() if
50class DieException : public std::runtime_error
51{
52public:
53 explicit DieException(const std::string& message);
54};
55
56//! Switch between dying via std::terminate() and throwing an exception.
57//! Alternatively define the macro TLX_DIE_WITH_EXCEPTION=1
58bool set_die_with_exception(bool b);
59
60/******************************************************************************/
61// die_unless() and die_if()
62
63//! Check condition X and die miserably if false. Same as assert() except this
64//! is also active in Release mode.
65#define tlx_die_unless(X) \
66 do { \
67 if (!(X)) { \
68 ::tlx::die_with_message( \
69 "DIE: Assertion \"" #X "\" failed!", __FILE__, __LINE__); \
70 } \
71 } while (false)
72
73//! Check condition X and die miserably if true. Opposite of assert() except
74//! this is also active in Release mode.
75#define tlx_die_if(X) \
76 do { \
77 if (X) { \
78 ::tlx::die_with_message( \
79 "DIE: Assertion \"" #X "\" succeeded!", __FILE__, __LINE__); \
80 } \
81 } while (false)
82
83//! Check condition X and die miserably if false. Same as tlx_die_unless()
84//! except the user additionally passes a message.
85#define tlx_die_verbose_unless(X, msg) \
86 do { \
87 if (!(X)) { \
88 tlx_die_with_sstream( \
89 "DIE: Assertion \"" #X "\" failed!\n" << msg << '\n'); \
90 } \
91 } while (false)
92
93//! Check condition X and die miserably if false. Same as tlx_die_if()
94//! except the user additionally passes a message.
95#define tlx_die_verbose_if(X, msg) \
96 do { \
97 if ((X)) { \
98 tlx_die_with_sstream( \
99 "DIE: Assertion \"" #X "\" succeeded!\n" << msg << '\n'); \
100 } \
101 } while (false)
102
103/******************************************************************************/
104// die_unequal()
105
106//! helper method to compare two values in die_unequal()
107template <typename TypeA, typename TypeB>
108inline bool die_equal_compare(TypeA a, TypeB b) {
109 return a == b;
110}
111
112template <>
113inline bool die_equal_compare(const char* a, const char* b) {
114 // compare string contents
115 return std::strcmp(a, b) == 0;
116}
117
118template <>
119inline bool die_equal_compare(float a, float b) {
120 // special case for NAN
121 return a != a ? b != b : a == b;
122}
123
124template <>
125inline bool die_equal_compare(double a, double b) {
126 // special case for NAN
127 return a != a ? b != b : a == b;
128}
129
130//! Check that X == Y or die miserably, but output the values of X and Y for
131//! better debugging.
132#define tlx_die_unequal(X, Y) \
133 do { \
134 auto x__ = (X); /* NOLINT */ \
135 auto y__ = (Y); /* NOLINT */ \
136 if (!::tlx::die_equal_compare(x__, y__)) \
137 tlx_die_with_sstream("DIE-UNEQUAL: " #X " != " #Y " : " \
138 "\"" << x__ << "\" != \"" << y__ << "\""); \
139 } while (false)
140
141//! Check that X == Y or die miserably, but output the values of X and Y for
142//! better debugging. Only active if NDEBUG is not defined.
143#ifdef NDEBUG
144#define tlx_assert_equal(X, Y)
145#else
146#define tlx_assert_equal(X, Y) die_unequal(X, Y)
147#endif
148
149//! Check that X == Y or die miserably, but output the values of X and Y for
150//! better debugging. Same as tlx_die_unequal() except the user additionally
151//! pass a message.
152#define tlx_die_verbose_unequal(X, Y, msg) \
153 do { \
154 auto x__ = (X); /* NOLINT */ \
155 auto y__ = (Y); /* NOLINT */ \
156 if (!::tlx::die_equal_compare(x__, y__)) \
157 tlx_die_with_sstream("DIE-UNEQUAL: " #X " != " #Y " : " \
158 "\"" << x__ << "\" != \"" << y__ << "\"\n" << \
159 msg << '\n'); \
160 } while (false)
161
162/******************************************************************************/
163// die_unequal_eps()
164
165//! simple replacement for std::abs
166template <typename Type>
167inline Type die_unequal_eps_abs(const Type& t) {
168 return t < 0 ? -t : t;
169}
170
171//! helper method to compare two values in die_unequal_eps()
172template <typename TypeA, typename TypeB>
173inline bool die_equal_eps_compare(TypeA x, TypeB y, double eps) {
174 // special case for NAN
175 return x != x ? y != y : die_unequal_eps_abs(x - y) <= eps;
176}
177
178//! Check that ABS(X - Y) <= eps or die miserably, but output the values of X
179//! and Y for better debugging.
180#define tlx_die_unequal_eps(X, Y, eps) \
181 do { \
182 auto x__ = (X); /* NOLINT */ \
183 auto y__ = (Y); /* NOLINT */ \
184 if (!::tlx::die_equal_eps_compare(x__, y__, eps)) \
185 tlx_die("DIE-UNEQUAL-EPS: " #X " != " #Y " : " \
186 << std::setprecision(18) \
187 << "\"" << x__ << "\" != \"" << y__ << "\""); \
188 } while (false)
189
190//! Check that ABS(X - Y) <= eps or die miserably, but output the values of X
191//! and Y for better debugging. Same as tlx_die_unequal_eps() except the user
192//! additionally passes a message.
193#define tlx_die_verbose_unequal_eps(X, Y, eps, msg) \
194 do { \
195 auto x__ = (X); /* NOLINT */ \
196 auto y__ = (Y); /* NOLINT */ \
197 if (!::tlx::die_equal_eps_compare(x__, y__, eps)) \
198 tlx_die("DIE-UNEQUAL-EPS: " #X " != " #Y " : " \
199 << std::setprecision(18) \
200 << "\"" << x__ << "\" != \"" << y__ << "\"\n" << \
201 msg << '\n'); \
202 } while (false)
203
204//! Check that ABS(X - Y) <= 0.000001 or die miserably, but output the values of
205//! X and Y for better debugging.
206#define tlx_die_unequal_eps6(X, Y) \
207 die_unequal_eps(X, Y, 1e-6)
208
209//! Check that ABS(X - Y) <= 0.000001 or die miserably, but output the values of
210//! X and Y for better debugging. Same as tlx_die_unequal_eps6() except the user
211//! additionally passes a message.
212#define tlx_die_verbose_unequal_eps6(X, Y, msg) \
213 die_verbose_unequal_eps(X, Y, 1e-6, msg)
214
215/******************************************************************************/
216// die_equal()
217
218//! Die miserably if X == Y, but first output the values of X and Y for better
219//! debugging.
220#define tlx_die_equal(X, Y) \
221 do { \
222 auto x__ = (X); /* NOLINT */ \
223 auto y__ = (Y); /* NOLINT */ \
224 if (::tlx::die_equal_compare(x__, y__)) \
225 tlx_die_with_sstream("DIE-EQUAL: " #X " == " #Y " : " \
226 "\"" << x__ << "\" == \"" << y__ << "\""); \
227 } while (false)
228
229//! Die miserably if X == Y, but first output the values of X and Y for better
230//! debugging. Only active if NDEBUG is not defined.
231#ifdef NDEBUG
232#define tlx_assert_unequal(X, Y)
233#else
234#define tlx_assert_unequal(X, Y) die_equal(X, Y)
235#endif
236
237//! Die miserably if X == Y, but first output the values of X and Y for better
238//! debugging. Same as tlx_die_equal() except the user additionally passes a
239//! message.
240#define tlx_die_verbose_equal(X, Y, msg) \
241 do { \
242 auto x__ = (X); /* NOLINT */ \
243 auto y__ = (Y); /* NOLINT */ \
244 if (::tlx::die_equal_compare(x__, y__)) \
245 tlx_die_with_sstream("DIE-EQUAL: " #X " == " #Y " : " \
246 "\"" << x__ << "\" == \"" << y__ << "\"\n" << \
247 msg << '\n'); \
248 } while (false)
249
250/******************************************************************************/
251// die_unless_throws()
252
253//! Define to check that [code] throws and exception of given type
254#define tlx_die_unless_throws(code, exception_type) \
255 do { \
256 try { \
257 code; \
258 } \
259 catch (const exception_type&) { \
260 break; \
261 } \
262 ::tlx::die_with_message( \
263 "DIE-UNLESS-THROWS: " #code " - NO EXCEPTION " #exception_type, \
264 __FILE__, __LINE__); \
265 } while (false)
266
267} // namespace tlx
268
269#endif // !TLX_DIE_CORE_HEADER
270
271/******************************************************************************/
Exception thrown by die_with_message() if.
Definition: core.hpp:51
Type die_unequal_eps_abs(const Type &t)
simple replacement for std::abs
Definition: core.hpp:167
void die_with_message(const std::string &msg)
die with message - either throw an exception or die via std::terminate()
Definition: core.cpp:29
bool die_equal_compare(TypeA a, TypeB b)
helper method to compare two values in die_unequal()
Definition: core.hpp:108
bool set_die_with_exception(bool b)
Switch between dying via std::terminate() and throwing an exception.
Definition: core.cpp:52
bool die_equal_eps_compare(TypeA x, TypeB y, double eps)
helper method to compare two values in die_unequal_eps()
Definition: core.hpp:173