TIMPI
Loading...
Searching...
No Matches
timpi_assert.h
Go to the documentation of this file.
1// The TIMPI Message-Passing Parallelism Library.
2// Copyright (C) 2002-2025 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3
4// This library is free software; you can redistribute it and/or
5// modify it under the terms of the GNU Lesser General Public
6// License as published by the Free Software Foundation; either
7// version 2.1 of the License, or (at your option) any later version.
8
9// This library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// Lesser General Public License for more details.
13
14// You should have received a copy of the GNU Lesser General Public
15// License along with this library; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18
19
20#ifndef TIMPI_TIMPI_ASSERT_H
21#define TIMPI_TIMPI_ASSERT_H
22
23// The library configuration options
24#include "timpi/timpi_config.h"
25
26// C++ includes
27#include <functional> // std::less, etc
28#include <iostream>
29#include <sstream>
30#include <type_traits> // std::decay
31
32
33// Use actual timestamps or constant dummies (to aid ccache)
34#ifdef TIMPI_ENABLE_TIMESTAMPS
35# define TIMPI_TIME __TIME__
36# define TIMPI_DATE __DATE__
37#else
38# define TIMPI_TIME "notime"
39# define TIMPI_DATE "nodate"
40#endif
41
42namespace TIMPI
43{
44
45// Assert macros generally call report_error with __FILE__, __LINE__,
46// __DATE__, and __TIME__ in the appropriate order. This should not
47// be called by users directly!
48void report_here(const char * file, int line, const char * date, const char * time);
49void report_error(const char * file, int line, const char * date, const char * time);
50
51// A function template for ignoring unused variables. This is a way
52// to shut up conditionally unused variable compiler warnings (as are
53// often created by assertions)
54template<class ...Args> inline void ignore( const Args&... ) { }
55
56// The timpi_dbg_var() macro indicates that an argument to a function
57// is used only in debug mode (i.e., when NDEBUG is not defined).
58#ifndef NDEBUG
59#define timpi_dbg_var(var) var
60#else
61#define timpi_dbg_var(var)
62#endif
63
64// The timpi_assert() macro acts like C's assert(), but throws a
65// timpi_error() (including stack trace, etc) instead of just exiting
66#ifdef NDEBUG
67
68#define timpi_assert_msg(asserted, msg) ((void) 0)
69#define timpi_assert_equal_to_msg(expr1,expr2, msg) ((void) 0)
70#define timpi_assert_not_equal_to_msg(expr1,expr2, msg) ((void) 0)
71#define timpi_assert_less_msg(expr1,expr2, msg) ((void) 0)
72#define timpi_assert_greater_msg(expr1,expr2, msg) ((void) 0)
73#define timpi_assert_less_equal_msg(expr1,expr2, msg) ((void) 0)
74#define timpi_assert_greater_equal_msg(expr1,expr2, msg) ((void) 0)
75
76#else
77
78#define timpi_assert_msg(asserted, msg) \
79 do { \
80 if (!(asserted)) { \
81 std::cerr << "Assertion `" #asserted "' failed." << std::endl; \
82 timpi_error_msg(msg); \
83 } } while (0)
84
85#define timpi_assert_equal_to_msg(expr1,expr2, msg) \
86 do { \
87 if (!((expr1) == (expr2))) { \
88 std::cerr << "Assertion `" #expr1 " == " #expr2 "' failed.\n" #expr1 " = " << (expr1) << "\n" #expr2 " = " << (expr2) << '\n' << msg << std::endl; \
89 timpi_error(); \
90 } } while (0)
91
92#define timpi_assert_not_equal_to_msg(expr1,expr2, msg) \
93 do { \
94 if (!((expr1) != (expr2))) { \
95 std::cerr << "Assertion `" #expr1 " != " #expr2 "' failed.\n" #expr1 " = " << (expr1) << "\n" #expr2 " = " << (expr2) << '\n' << msg << std::endl; \
96 timpi_error(); \
97 } } while (0)
98
99// Older Clang has a parsing bug that can't seem to handle the handle the decay statement when
100// expanding these macros. We'll just fall back to the previous behavior with those older compilers
101#if defined(__clang__) && (__clang_major__ <= 3)
102
103#define timpi_assert_less_msg(expr1,expr2, msg) \
104 do { \
105 if (!((expr1) < (expr2))) { \
106 std::cerr << "Assertion `" #expr1 " < " #expr2 "' failed.\n" #expr1 " = " << (expr1) << "\n" #expr2 " = " << (expr2) << '\n' << msg << std::endl; \
107 timpi_error(); \
108 } } while (0)
109
110#define timpi_assert_greater_msg(expr1,expr2, msg) \
111 do { \
112 if (!((expr1) > (expr2))) { \
113 std::cerr << "Assertion `" #expr1 " > " #expr2 "' failed.\n" #expr1 " = " << (expr1) << "\n" #expr2 " = " << (expr2) << '\n' << msg << std::endl; \
114 timpi_error(); \
115 } } while (0)
116
117#define timpi_assert_less_equal_msg(expr1,expr2, msg) \
118 do { \
119 if (!((expr1) <= (expr2))) { \
120 std::cerr << "Assertion `" #expr1 " <= " #expr2 "' failed.\n" #expr1 " = " << (expr1) << "\n" #expr2 " = " << (expr2) << '\n' << msg << std::endl; \
121 timpi_error(); \
122 } } while (0)
123
124#define timpi_assert_greater_equal_msg(expr1,expr2, msg) \
125 do { \
126 if (!((expr1) >= (expr2))) { \
127 std::cerr << "Assertion `" #expr1 " >= " #expr2 "' failed.\n" #expr1 " = " << (expr1) << "\n" #expr2 " = " << (expr2) << '\n' << msg << std::endl; \
128 timpi_error(); \
129 } } while (0)
130
131// Newer clangs and all other supported compilers
132#else
133
134template <template <class> class Comp>
136
137 template <typename T1, typename T2>
138 bool operator()(const T1 & e1, const T2 & e2) const
139 {
140 typedef typename std::decay<T1>::type DT1;
141 typedef typename std::decay<T2>::type DT2;
142 return (Comp<DT2>()(static_cast<DT2>(e1), e2) &&
143 Comp<DT1>()(e1, static_cast<DT1>(e2)));
144 }
145
146 template <typename T1>
147 bool operator()(const T1 & e1, const T1 & e2) const
148 {
149 return Comp<T1>()(e1, e2);
150 }
151};
152
153#define timpi_assert_less_msg(expr1,expr2, msg) \
154 do { \
155 if (!TIMPI::casting_compare<std::less>()(expr1, expr2)) { \
156 std::cerr << "Assertion `" #expr1 " < " #expr2 "' failed.\n" #expr1 " = " << (expr1) << "\n" #expr2 " = " << (expr2) << '\n' << msg << std::endl; \
157 timpi_error(); \
158 } } while (0)
159
160#define timpi_assert_greater_msg(expr1,expr2, msg) \
161 do { \
162 if (!TIMPI::casting_compare<std::greater>()(expr1, expr2)) { \
163 std::cerr << "Assertion `" #expr1 " > " #expr2 "' failed.\n" #expr1 " = " << (expr1) << "\n" #expr2 " = " << (expr2) << '\n' << msg << std::endl; \
164 timpi_error(); \
165 } } while (0)
166
167#define timpi_assert_less_equal_msg(expr1,expr2, msg) \
168 do { \
169 if (!TIMPI::casting_compare<std::less_equal>()(expr1, expr2)) { \
170 std::cerr << "Assertion `" #expr1 " <= " #expr2 "' failed.\n" #expr1 " = " << (expr1) << "\n" #expr2 " = " << (expr2) << '\n' << msg << std::endl; \
171 timpi_error(); \
172 } } while (0)
173
174#define timpi_assert_greater_equal_msg(expr1,expr2, msg) \
175 do { \
176 if (!TIMPI::casting_compare<std::greater_equal>()(expr1, expr2)) { \
177 std::cerr << "Assertion `" #expr1 " >= " #expr2 "' failed.\n" #expr1 " = " << (expr1) << "\n" #expr2 " = " << (expr2) << '\n' << msg << std::endl; \
178 timpi_error(); \
179 } } while (0)
180
181#endif // clang <4.0
182
183#endif
184
185
186#define timpi_assert(asserted) timpi_assert_msg(asserted, "")
187#define timpi_assert_equal_to(expr1,expr2) timpi_assert_equal_to_msg(expr1,expr2, "")
188#define timpi_assert_not_equal_to(expr1,expr2) timpi_assert_not_equal_to_msg(expr1,expr2, "")
189#define timpi_assert_less(expr1,expr2) timpi_assert_less_msg(expr1,expr2, "")
190#define timpi_assert_greater(expr1,expr2) timpi_assert_greater_msg(expr1,expr2, "")
191#define timpi_assert_less_equal(expr1,expr2) timpi_assert_less_equal_msg(expr1,expr2, "")
192#define timpi_assert_greater_equal(expr1,expr2) timpi_assert_greater_equal_msg(expr1,expr2, "")
193
194
195// Macro to notate and debug functions which should only be called in
196// parallel on every processor at once
197
198#ifndef NDEBUG
199#define timpi_parallel_only(comm_obj) do { \
200 timpi_assert_msg((comm_obj).verify(std::string(__FILE__).length()), \
201 "Different ranks are at different timpi_parallel_only points"); \
202 timpi_assert_msg((comm_obj).verify(std::string(__FILE__)), \
203 "Different ranks are at different timpi_parallel_only points"); \
204 timpi_assert_msg((comm_obj).verify(__LINE__), \
205 "Different ranks are at different timpi_parallel_only points"); \
206 } while (0)
207#else
208#define timpi_parallel_only(comm_obj) ((void) 0)
209#endif
210
211
212#ifdef TIMPI_ENABLE_EXCEPTIONS
213#define TIMPI_THROW(e) do { throw e; } while (0)
214#else
215#define TIMPI_THROW(e) do { std::abort(); } while (0)
216#endif
217
218// The timpi_error() macro prints a message and throws a LogicError
219// exception
220//
221// The timpi_not_implemented() macro prints a message and throws a
222// NotImplemented exception
223
224#define timpi_error_msg(msg) \
225 do { \
226 std::cerr << msg << std::endl; \
227 std::stringstream msg_stream; \
228 msg_stream << msg; \
229 TIMPI::report_error(__FILE__, __LINE__, TIMPI_DATE, TIMPI_TIME); \
230 TIMPI_THROW(std::logic_error(msg_stream.str())); \
231 } while (0)
232
233#define timpi_error() timpi_error_msg("")
234
235#define timpi_not_implemented_msg(msg) \
236 do { \
237 std::cerr << msg << std::endl; \
238 TIMPI::report_error(__FILE__, __LINE__, TIMPI_DATE, TIMPI_TIME); \
239 TIMPI_THROW(std::logic_error("Error: not implemented!")); \
240 } while (0)
241
242#define timpi_not_implemented() timpi_not_implemented_msg("")
243
244// The timpi_do_once macro helps us avoid redundant repeated
245// repetitions of the same warning messages
246#undef timpi_do_once
247#define timpi_do_once(do_this) \
248 do { \
249 static bool did_this_already = false; \
250 if (!did_this_already) { \
251 did_this_already = true; \
252 do_this; \
253 } } while (0)
254
255
256// The timpi_warning macro outputs a file/line/time stamped warning
257// message, if warnings are enabled.
258#ifdef TIMPI_ENABLE_WARNINGS
259#define timpi_warning(message) \
260 timpi_do_once(std::cout << message \
261 << __FILE__ << ", line " << __LINE__ << ", compiled " << TIMPI_DATE << " at " << TIMPI_TIME << " ***" << std::endl;)
262#else
263#define timpi_warning(message) ((void) 0)
264#endif
265
266// The timpi_experimental macro warns that you are using
267// bleeding-edge code
268#undef timpi_experimental
269#define timpi_experimental() \
270 timpi_warning("*** Warning, This code is untested, experimental, or likely to see future API changes: ");
271
272
273// The timpi_deprecated macro warns that you are using obsoleted code
274#undef timpi_deprecated
275#ifndef TIMPI_ENABLE_DEPRECATED
276#define timpi_deprecated() \
277 timpi_error_msg("*** Error, This code is deprecated, and likely to be removed in future library versions! ");
278#else
279#define timpi_deprecated() \
280 timpi_warning("*** Warning, This code is deprecated, and likely to be removed in future library versions! ");
281#endif
282
283// A function template for ignoring unused variables. This is a way
284// to shut up unused variable compiler warnings on a case by case
285// basis.
286template<class ...Args> inline void timpi_ignore( const Args&... ) { }
287
288
289// cast_int asserts that the value of the castee is within the
290// bounds which are exactly representable by the output type, if we're
291// in debug or development modes, but it just does a faster static
292// cast if we're in optimized mode.
293//
294// Use these casts when you're certain that a cast will succeed in
295// correct code but you want to be able to double-check.
296template <typename Tnew, typename Told>
298{
300 (oldvar, static_cast<Told>(static_cast<Tnew>(oldvar)));
301
302 return(static_cast<Tnew>(oldvar));
303}
304
305} // namespace TIMPI
306
307
308#endif // TIMPI_TIMPI_ASSERT_H
void timpi_ignore(const Args &...)
void report_here(const char *file, int line, const char *date, const char *time)
Tnew cast_int(Told oldvar)
void report_error(const char *file, int line, const char *date, const char *time)
void ignore(const Args &...)
bool operator()(const T1 &e1, const T2 &e2) const
bool operator()(const T1 &e1, const T1 &e2) const