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 } \
140 } while (false)
141
142//! Check that X == Y or die miserably, but output the values of X and Y for
143//! better debugging. Only active if NDEBUG is not defined.
144#ifdef NDEBUG
145#define tlx_assert_equal(X, Y)
146#else
147#define tlx_assert_equal(X, Y) die_unequal(X, Y)
148#endif
149
150//! Check that X == Y or die miserably, but output the values of X and Y for
151//! better debugging. Same as tlx_die_unequal() except the user additionally
152//! pass a message.
153#define tlx_die_verbose_unequal(X, Y, msg) \
154 do { \
155 auto x__ = (X); /* NOLINT */ \
156 auto y__ = (Y); /* NOLINT */ \
157 if (!::tlx::die_equal_compare(x__, y__)) { \
158 tlx_die_with_sstream("DIE-UNEQUAL: " #X " != " #Y " : " \
159 "\"" << x__ << "\" != \"" << y__ << "\"\n" << \
160 msg << '\n'); \
161 } \
162 } while (false)
163
164/******************************************************************************/
165// die_unequal_eps()
166
167//! simple replacement for std::abs
168template <typename Type>
169inline Type die_unequal_eps_abs(const Type& t) {
170 return t < 0 ? -t : t;
171}
172
173//! helper method to compare two values in die_unequal_eps()
174template <typename TypeA, typename TypeB>
175inline bool die_equal_eps_compare(TypeA x, TypeB y, double eps) {
176 // special case for NAN
177 return x != x ? y != y : die_unequal_eps_abs(x - y) <= eps;
178}
179
180//! Check that ABS(X - Y) <= eps or die miserably, but output the values of X
181//! and Y for better debugging.
182#define tlx_die_unequal_eps(X, Y, eps) \
183 do { \
184 auto x__ = (X); /* NOLINT */ \
185 auto y__ = (Y); /* NOLINT */ \
186 if (!::tlx::die_equal_eps_compare(x__, y__, eps)) { \
187 tlx_die("DIE-UNEQUAL-EPS: " #X " != " #Y " : " \
188 << std::setprecision(18) \
189 << "\"" << x__ << "\" != \"" << y__ << "\""); \
190 } \
191 } while (false)
192
193//! Check that ABS(X - Y) <= eps or die miserably, but output the values of X
194//! and Y for better debugging. Same as tlx_die_unequal_eps() except the user
195//! additionally passes a message.
196#define tlx_die_verbose_unequal_eps(X, Y, eps, msg) \
197 do { \
198 auto x__ = (X); /* NOLINT */ \
199 auto y__ = (Y); /* NOLINT */ \
200 if (!::tlx::die_equal_eps_compare(x__, y__, eps)) { \
201 tlx_die("DIE-UNEQUAL-EPS: " #X " != " #Y " : " \
202 << std::setprecision(18) \
203 << "\"" << x__ << "\" != \"" << y__ << "\"\n" << \
204 msg << '\n'); \
205 } \
206 } while (false)
207
208//! Check that ABS(X - Y) <= 0.000001 or die miserably, but output the values of
209//! X and Y for better debugging.
210#define tlx_die_unequal_eps6(X, Y) \
211 die_unequal_eps(X, Y, 1e-6)
212
213//! Check that ABS(X - Y) <= 0.000001 or die miserably, but output the values of
214//! X and Y for better debugging. Same as tlx_die_unequal_eps6() except the user
215//! additionally passes a message.
216#define tlx_die_verbose_unequal_eps6(X, Y, msg) \
217 die_verbose_unequal_eps(X, Y, 1e-6, msg)
218
219/******************************************************************************/
220// die_equal()
221
222//! Die miserably if X == Y, but first output the values of X and Y for better
223//! debugging.
224#define tlx_die_equal(X, Y) \
225 do { \
226 auto x__ = (X); /* NOLINT */ \
227 auto y__ = (Y); /* NOLINT */ \
228 if (::tlx::die_equal_compare(x__, y__)) { \
229 tlx_die_with_sstream("DIE-EQUAL: " #X " == " #Y " : " \
230 "\"" << x__ << "\" == \"" << y__ << "\""); \
231 } \
232 } while (false)
233
234//! Die miserably if X == Y, but first output the values of X and Y for better
235//! debugging. Only active if NDEBUG is not defined.
236#ifdef NDEBUG
237#define tlx_assert_unequal(X, Y)
238#else
239#define tlx_assert_unequal(X, Y) die_equal(X, Y)
240#endif
241
242//! Die miserably if X == Y, but first output the values of X and Y for better
243//! debugging. Same as tlx_die_equal() except the user additionally passes a
244//! message.
245#define tlx_die_verbose_equal(X, Y, msg) \
246 do { \
247 auto x__ = (X); /* NOLINT */ \
248 auto y__ = (Y); /* NOLINT */ \
249 if (::tlx::die_equal_compare(x__, y__)) { \
250 tlx_die_with_sstream("DIE-EQUAL: " #X " == " #Y " : " \
251 "\"" << x__ << "\" == \"" << y__ << "\"\n" << \
252 msg << '\n'); \
253 } \
254 } while (false)
255
256/******************************************************************************/
257// die_unless_throws()
258
259//! Define to check that [code] throws and exception of given type
260#define tlx_die_unless_throws(code, exception_type) \
261 do { \
262 try { \
263 code; \
264 } \
265 catch (const exception_type&) { \
266 break; \
267 } \
268 ::tlx::die_with_message( \
269 "DIE-UNLESS-THROWS: " #code " - NO EXCEPTION " #exception_type, \
270 __FILE__, __LINE__); \
271 } while (false)
272
273} // namespace tlx
274
275#endif // !TLX_DIE_CORE_HEADER
276
277/******************************************************************************/
DieException(const std::string &message)
Definition core.cpp:49
Type die_unequal_eps_abs(const Type &t)
simple replacement for std::abs
Definition core.hpp:169
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:175