TIMPI
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 
42 namespace 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!
48 void report_here(const char * file, int line, const char * date, const char * time);
49 void 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)
54 template<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 
134 template <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.
286 template<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.
296 template <typename Tnew, typename Told>
297 inline Tnew cast_int (Told oldvar)
298 {
299  timpi_assert_equal_to
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 ignore(const Args &...)
Definition: timpi_assert.h:54
void report_error(const char *file, int line, const char *date, const char *time)
Definition: timpi_assert.C:43
bool operator()(const T1 &e1, const T1 &e2) const
Definition: timpi_assert.h:147
void timpi_ignore(const Args &...)
Definition: timpi_assert.h:286
void report_here(const char *file, int line, const char *date, const char *time)
Definition: timpi_assert.C:29
bool operator()(const T1 &e1, const T2 &e2) const
Definition: timpi_assert.h:138
Tnew cast_int(Told oldvar)
Definition: timpi_assert.h:297