IOSS 2.0
Loading...
Searching...
No Matches
Ioss_SmartAssert.h
Go to the documentation of this file.
1// Copyright(C) 1999-2020, 2022, 2023 National Technology & Engineering Solutions
2// of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with
3// NTESS, the U.S. Government retains certain rights in this software.
4//
5// See packages/seacas/LICENSE for details
6#pragma once
7
8#include "ioss_export.h"
9
10#if _MSC_VER > 1000
11
12// note:
13// moving this after pragma push will render it useless (VC6)
14//
15// identifier truncated to 255 chars in debug information
16#pragma warning(disable : 4786)
17
18#pragma warning(push)
19// *this used in base-member initialization; it's ok
20#pragma warning(disable : 4355)
21#endif
22
23#include <iostream>
24#include <map>
25#include <sstream>
26#include <string>
27#include <utility>
28#include <vector>
29
30namespace Ioss {
31 enum {
32
33 // default behavior - just loges this assert
34 // (a message is shown to the user to the console)
35 lvl_warn = 100,
36
37 // default behavior - asks the user what to do:
38 // Ignore/ Retry/ etc.
39 lvl_debug = 200,
40
41 // default behavior - throws a smart_assert_error
42 lvl_error = 300,
43
44 // default behavior - dumps all assert context to console,
45 // and aborts
46 lvl_fatal = 1000
47 };
48
49 /*
50 contains details about a failed assertion
51 */
52 class IOSS_EXPORT assert_context
53 {
54 using string = std::string;
55
56 public:
57 assert_context() = default;
58
59 // where the assertion failed: file & line
60 void set_file_line(const char *file, int line)
61 {
62 file_ = file;
63 line_ = line;
64 }
65 const string &get_context_file() const { return file_; }
66 int get_context_line() const { return line_; }
67
68 // get/ set expression
69 void set_expr(const string &str) { expr_ = str; }
70 const string &get_expr() const { return expr_; }
71
72 using val_and_str = std::pair<string, string>;
73 using vals_array = std::vector<val_and_str>;
74 // return values array as a vector of pairs:
75 // [Value, corresponding string]
76 const vals_array &get_vals_array() const { return vals_; }
77 // adds one value and its corresponding string
78 void add_val(const string &val, const string &str) { vals_.emplace_back(val, str); }
79
80 // get/set level of assertion
81 void set_level(int nLevel) { level_ = nLevel; }
82 int get_level() const { return level_; }
83
84 // get/set (user-friendly) message
85 void set_level_msg(const char *strMsg)
86 {
87 if (strMsg != nullptr) {
88 msg_ = strMsg;
89 }
90 else {
91 msg_.erase();
92 }
93 }
94 const string &get_level_msg() const { return msg_; }
95
96 private:
97 // where the assertion occurred
98 string file_{};
99 int line_{0};
100
101 // expression and values
102 string expr_{};
103 vals_array vals_{};
104
105 // level and message
106 int level_{lvl_debug};
107 string msg_{};
108 };
109
110 namespace SmartAssert {
111
112 using assert_func = void (*)(const assert_context &);
113
114 // helpers
115 IOSS_EXPORT std::string get_typeof_level(int nLevel);
116 IOSS_EXPORT void dump_context_summary(const assert_context &context, std::ostream &out);
117 IOSS_EXPORT void dump_context_detail(const assert_context &context, std::ostream &out);
118
119 // defaults
120 IOSS_EXPORT void default_warn_handler(const assert_context &context);
121 IOSS_EXPORT void default_debug_handler(const assert_context &context);
122 IOSS_EXPORT void default_error_handler(const assert_context &context);
123 IOSS_EXPORT void default_fatal_handler(const assert_context &context);
124 IOSS_EXPORT void default_logger(const assert_context &context);
125
126 } // namespace SmartAssert
127
128 namespace Private {
129 IOSS_EXPORT void init_assert();
130 IOSS_EXPORT void set_default_log_stream(std::ostream &out);
131 IOSS_EXPORT void set_default_log_name(const char *str);
132
133 // allows finding if a value is of type 'const char *'
134 // and is null; if so, we cannot print it to an ostream
135 // directly!!!
136 template <class T> struct is_null_finder
137 {
138 bool is(const T & /*unused*/) const { return false; }
139 };
140
141 template <> struct is_null_finder<char *>
142 {
143 bool is(char *const &val) { return val == nullptr; }
144 };
145
146 template <> struct is_null_finder<const char *>
147 {
148 bool is(const char *const &val) { return val == nullptr; }
149 };
150
151 } // namespace Private
152
153 struct IOSS_EXPORT Assert
154 {
156
157 // helpers, in order to be able to compile the code
160
161 explicit Assert(const char *expr) : SMART_ASSERT_A(*this), SMART_ASSERT_B(*this)
162 {
163 context_.set_expr(expr);
164
165 if ((logger() == nullptr) || handlers().size() < 4) {
166 // used before main!
168 }
169 }
170
171 Assert(const Assert &other)
172 : SMART_ASSERT_A(*this), SMART_ASSERT_B(*this), context_(other.context_)
173 {
174 other.needs_handling_ = false;
175 }
176
178 {
179 if (needs_handling_) {
180 handle_assert();
181 }
182 }
183
184 template <class type> Assert &print_current_val(const type &val, const char *my_msg)
185 {
186 std::ostringstream out;
187
189 bool bIsNull = f.is(val);
190 if (!bIsNull) {
191 out << val;
192 }
193 else {
194 // null string
195 out << "null";
196 }
197 context_.add_val(out.str(), my_msg);
198 return *this;
199 }
200
201 Assert &print_context(const char *file, int line)
202 {
203 context_.set_file_line(file, line);
204 return *this;
205 }
206
207 Assert &msg(const char *strMsg)
208 {
209 context_.set_level_msg(strMsg);
210 return *this;
211 }
212
213 Assert &level(int nLevel, const char *strMsg = nullptr)
214 {
215 context_.set_level(nLevel);
216 context_.set_level_msg(strMsg);
217 return *this;
218 }
219
220 Assert &warn(const char *strMsg = nullptr) { return level(lvl_warn, strMsg); }
221
222 Assert &debug(const char *strMsg = nullptr) { return level(lvl_debug, strMsg); }
223
224 Assert &error(const char *strMsg = nullptr) { return level(lvl_error, strMsg); }
225
226 Assert &fatal(const char *strMsg = nullptr) { return level(lvl_fatal, strMsg); }
227
228 // in this case, we set the default logger, and make it
229 // write everything to this file
230 static void set_log(const char *strFileName)
231 {
233 logger() = &SmartAssert::default_logger;
234 }
235
236 // in this case, we set the default logger, and make it
237 // write everything to this log
238 static void set_log(std::ostream &out)
239 {
241 logger() = &SmartAssert::default_logger;
242 }
243
244 static void set_log(assert_func log) { logger() = log; }
245
246 static void set_handler(int nLevel, assert_func handler) { handlers()[nLevel] = handler; }
247
248 private:
249 // handles the current assertion.
251 {
252 logger()(context_);
253 get_handler(context_.get_level())(context_);
254 }
255
256 /*
257 IMPORTANT NOTE:
258 The only reason logger & handlers are functions, are
259 because you might use SMART_ASSERT before main().
260
261 In this case, since they're statics, they might not
262 be initialized. However, making them functions
263 will make it work.
264 */
265
266 // the log
268 {
269 static assert_func inst;
270 return inst;
271 }
272
273 // the handler
274 using handlers_collection = std::map<int, assert_func>;
276 {
277 static handlers_collection inst;
278 return inst;
279 }
280
281 static assert_func get_handler(int nLevel)
282 {
283 const auto found = handlers().find(nLevel);
284 if (found != handlers().end()) {
285 return (*found).second;
286 }
287
288 // we always assume the debug handler has been set
289 return (*handlers().find(lvl_debug)).second;
290 }
291
293 mutable bool needs_handling_{true};
294 };
295
296 namespace SmartAssert {
297 inline Assert make_assert(const char *expr) { return Assert(expr); }
298 } // namespace SmartAssert
299
300 ////////////////////////////////////////////////////////
301 // macro trickery
302
303 // note: NEVER define SMART_ASSERT_DEBUG directly
304 // (it will be overridden);
305 //
306 // #define SMART_ASSERT_DEBUG_MODE instead
307
308#ifdef SMART_ASSERT_DEBUG_MODE
309#if SMART_ASSERT_DEBUG_MODE == 1
310#define SMART_ASSERT_DEBUG
311#else
312#undef SMART_ASSERT_DEBUG
313#endif
314
315#else
316
317// defaults
318#ifndef NDEBUG
319#define SMART_ASSERT_DEBUG
320#else
321#undef SMART_ASSERT_DEBUG
322#endif
323#endif
324
325#ifdef SMART_ASSERT_DEBUG
326// "debug" mode
327#define SMART_ASSERT(expr) \
328 if ((expr)) \
329 ; \
330 else \
331 (void)::Ioss::SmartAssert::make_assert(#expr) \
332 .print_context(__FILE__, __LINE__) \
333 .SMART_ASSERT_A /**/
334
335#else
336 // "release" mode
337#define SMART_ASSERT(expr) \
338 if (true) \
339 ; \
340 else \
341 (void)::Ioss::SmartAssert::make_assert("").SMART_ASSERT_A /**/
342
343#endif // ifdef SMART_ASSERT_DEBUG
344
345#define SMART_VERIFY(expr) \
346 if ((expr)) \
347 ; \
348 else \
349 (void)::Ioss::SmartAssert::make_assert(#expr) \
350 .error() \
351 .print_context(__FILE__, __LINE__) \
352 .SMART_ASSERT_A /**/
353
354#define SMART_ASSERT_A(x) SMART_ASSERT_OP(x, B)
355#define SMART_ASSERT_B(x) SMART_ASSERT_OP(x, A)
356
357#define SMART_ASSERT_OP(x, next) SMART_ASSERT_A.print_current_val((x), #x).SMART_ASSERT_##next /**/
358} // namespace Ioss
359
360#if _MSC_VER > 1000
361#pragma warning(pop)
362#endif
#define SMART_ASSERT_A(x)
Definition Ioss_SmartAssert.h:354
#define SMART_ASSERT_B(x)
Definition Ioss_SmartAssert.h:355
Definition Ioss_SmartAssert.h:53
const string & get_level_msg() const
Definition Ioss_SmartAssert.h:94
int get_context_line() const
Definition Ioss_SmartAssert.h:66
const vals_array & get_vals_array() const
Definition Ioss_SmartAssert.h:76
const string & get_expr() const
Definition Ioss_SmartAssert.h:70
int get_level() const
Definition Ioss_SmartAssert.h:82
std::string string
Definition Ioss_SmartAssert.h:54
std::vector< val_and_str > vals_array
Definition Ioss_SmartAssert.h:73
void set_level(int nLevel)
Definition Ioss_SmartAssert.h:81
std::pair< string, string > val_and_str
Definition Ioss_SmartAssert.h:72
void set_level_msg(const char *strMsg)
Definition Ioss_SmartAssert.h:85
void set_expr(const string &str)
Definition Ioss_SmartAssert.h:69
const string & get_context_file() const
Definition Ioss_SmartAssert.h:65
assert_context()=default
void set_file_line(const char *file, int line)
Definition Ioss_SmartAssert.h:60
void add_val(const string &val, const string &str)
Definition Ioss_SmartAssert.h:78
void init_assert()
Definition Ioss_SmartAssert.C:190
void set_default_log_name(const char *str)
Definition Ioss_SmartAssert.C:207
void set_default_log_stream(std::ostream &out)
Definition Ioss_SmartAssert.C:200
void dump_context_summary(const assert_context &context, std::ostream &out)
Definition Ioss_SmartAssert.C:52
void default_warn_handler(const assert_context &context)
Definition Ioss_SmartAssert.C:113
void default_fatal_handler(const assert_context &context)
Definition Ioss_SmartAssert.C:180
void default_debug_handler(const assert_context &context)
Definition Ioss_SmartAssert.C:119
void(*)(const assert_context &) assert_func
Definition Ioss_SmartAssert.h:112
void default_error_handler(const assert_context &context)
Definition Ioss_SmartAssert.C:172
Assert make_assert(const char *expr)
Definition Ioss_SmartAssert.h:297
void default_logger(const assert_context &context)
Definition Ioss_SmartAssert.C:101
void dump_context_detail(const assert_context &context, std::ostream &out)
Definition Ioss_SmartAssert.C:67
std::string get_typeof_level(int nLevel)
Definition Ioss_SmartAssert.C:36
The main namespace for the Ioss library.
Definition Ioad_DatabaseIO.C:40
@ lvl_debug
Definition Ioss_SmartAssert.h:39
@ lvl_warn
Definition Ioss_SmartAssert.h:35
@ lvl_error
Definition Ioss_SmartAssert.h:42
@ lvl_fatal
Definition Ioss_SmartAssert.h:46
Definition Ioss_SmartAssert.h:154
std::map< int, assert_func > handlers_collection
Definition Ioss_SmartAssert.h:274
Assert & level(int nLevel, const char *strMsg=nullptr)
Definition Ioss_SmartAssert.h:213
static void set_log(const char *strFileName)
Definition Ioss_SmartAssert.h:230
Assert & SMART_ASSERT_A
Definition Ioss_SmartAssert.h:158
Assert & warn(const char *strMsg=nullptr)
Definition Ioss_SmartAssert.h:220
static assert_func & logger()
Definition Ioss_SmartAssert.h:267
Assert & debug(const char *strMsg=nullptr)
Definition Ioss_SmartAssert.h:222
bool needs_handling_
Definition Ioss_SmartAssert.h:293
static void set_log(assert_func log)
Definition Ioss_SmartAssert.h:244
Assert & print_current_val(const type &val, const char *my_msg)
Definition Ioss_SmartAssert.h:184
Assert(const char *expr)
Definition Ioss_SmartAssert.h:161
Assert & SMART_ASSERT_B
Definition Ioss_SmartAssert.h:159
static assert_func get_handler(int nLevel)
Definition Ioss_SmartAssert.h:281
static void set_handler(int nLevel, assert_func handler)
Definition Ioss_SmartAssert.h:246
Assert & error(const char *strMsg=nullptr)
Definition Ioss_SmartAssert.h:224
Assert & fatal(const char *strMsg=nullptr)
Definition Ioss_SmartAssert.h:226
SmartAssert::assert_func assert_func
Definition Ioss_SmartAssert.h:155
Assert & print_context(const char *file, int line)
Definition Ioss_SmartAssert.h:201
static void set_log(std::ostream &out)
Definition Ioss_SmartAssert.h:238
static handlers_collection & handlers()
Definition Ioss_SmartAssert.h:275
void handle_assert()
Definition Ioss_SmartAssert.h:250
Assert(const Assert &other)
Definition Ioss_SmartAssert.h:171
Assert & msg(const char *strMsg)
Definition Ioss_SmartAssert.h:207
~Assert()
Definition Ioss_SmartAssert.h:177
assert_context context_
Definition Ioss_SmartAssert.h:292
bool is(char *const &val)
Definition Ioss_SmartAssert.h:143
bool is(const char *const &val)
Definition Ioss_SmartAssert.h:148
Definition Ioss_SmartAssert.h:137
bool is(const T &) const
Definition Ioss_SmartAssert.h:138