IOSS 2.0

Ioss_SmartAssert.h
Go to the documentation of this file.
1 // Copyright(C) 2009-2017 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 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 // * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //
12 // * Redistributions in binary form must reproduce the above
13 // copyright notice, this list of conditions and the following
14 // disclaimer in the documentation and/or other materials provided
15 // with the distribution.
16 // * Neither the name of NTESS nor the names of its
17 // contributors may be used to endorse or promote products derived
18 // from this software without specific prior written permission.
19 //
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 //
32 #if !defined(IOSS_SMART_ASSERT_H)
33 #define IOSS_SMART_ASSERT_H
34
35 #if _MSC_VER > 1000
36 #pragma once
37 #endif // _MSC_VER > 1000
38
39 #if _MSC_VER > 1000
40
41 // note:
42 // moving this after pragma push will render it useless (VC6)
43 //
44 // identifier truncated to 255 chars in debug information
45 #pragma warning(disable : 4786)
46
47 #pragma warning(push)
48 // *this used in base-member initialization; it's ok
49 #pragma warning(disable : 4355)
50 #endif
51
52 #include <iostream>
53 #include <map>
54 #include <sstream>
55 #include <string>
56 #include <utility>
57 #include <vector>
58
59 enum {
60
61 // default behavior - just loges this assert
62 // (a message is shown to the user to the console)
63 lvl_warn = 100,
64
65 // default behavior - asks the user what to do:
66 // Ignore/ Retry/ etc.
67 lvl_debug = 200,
68
69 // default behavior - throws a smart_assert_error
70 lvl_error = 300,
71
72 // default behavior - dumps all assert context to console,
73 // and aborts
74 lvl_fatal = 1000
75 };
76
77 /*
78 contains details about a failed assertion
79 */
80 class assert_context
81 {
82 using string = std::string;
83
84 public:
85 assert_context() : line_(0), level_(lvl_debug) {}
86
87 // where the assertion failed: file & line
88 void set_file_line(const char *file, int line)
89 {
90 file_ = file;
91 line_ = line;
92 }
93 const string &get_context_file() const { return file_; }
94 int get_context_line() const { return line_; }
95
96 // get/ set expression
97 void set_expr(const string &str) { expr_ = str; }
98 const string &get_expr() const { return expr_; }
99
100 typedef std::pair<string, string> val_and_str;
101 using vals_array = std::vector<val_and_str>;
102 // return values array as a vector of pairs:
103 // [Value, corresponding string]
104 const vals_array &get_vals_array() const { return vals_; }
105 // adds one value and its corresponding string
106 void add_val(const string &val, const string &str) { vals_.push_back(val_and_str(val, str)); }
107
108 // get/set level of assertion
109 void set_level(int nLevel) { level_ = nLevel; }
110 int get_level() const { return level_; }
111
112 // get/set (user-friendly) message
113 void set_level_msg(const char *strMsg)
114 {
115 if (strMsg != nullptr) {
116 msg_ = strMsg;
117 }
118 else {
119 msg_.erase();
120 }
121 }
122 const string &get_level_msg() const { return msg_; }
123
124 private:
125 // where the assertion occurred
126 string file_;
127 int line_;
128
129 // expression and values
130 string expr_;
131 vals_array vals_;
132
133 // level and message
134 int level_;
135 string msg_;
136 };
137
138 namespace SmartAssert {
139
140 using assert_func = void (*)(const assert_context &);
141
142 // helpers
143 std::string get_typeof_level(int nLevel);
144 void dump_context_summary(const assert_context &context, std::ostream &out);
145 void dump_context_detail(const assert_context &context, std::ostream &out);
146
147 // defaults
148 void default_warn_handler(const assert_context &context);
149 void default_debug_handler(const assert_context &context);
150 void default_error_handler(const assert_context &context);
151 void default_fatal_handler(const assert_context &context);
152 void default_logger(const assert_context &context);
153
154 } // namespace SmartAssert
155
156 namespace Ioss {
157 namespace Private {
158 void init_assert();
159 void set_default_log_stream(std::ostream &out);
160 void set_default_log_name(const char *str);
161
162 // allows finding if a value is of type 'const char *'
163 // and is null; if so, we cannot print it to an ostream
164 // directly!!!
165 template <class T> struct is_null_finder
166 {
167 bool is(const T & /*unused*/) const { return false; }
168 };
169
170 template <> struct is_null_finder<char *>
171 {
172 bool is(char *const &val) { return val == nullptr; }
173 };
174
175 template <> struct is_null_finder<const char *>
176 {
177 bool is(const char *const &val) { return val == nullptr; }
178 };
179
180 } // namespace Private
181 } // namespace Ioss
182
183 struct Assert
184 {
185 using assert_func = SmartAssert::assert_func;
186
187 // helpers, in order to be able to compile the code
188 Assert &SMART_ASSERT_A;
189 Assert &SMART_ASSERT_B;
190
191 explicit Assert(const char *expr)
192 : SMART_ASSERT_A(*this), SMART_ASSERT_B(*this), needs_handling_(true)
193 {
194 context_.set_expr(expr);
195
196 if ((logger() == nullptr) || handlers().size() < 4) {
197 // used before main!
198 Ioss::Private::init_assert();
199 }
200 }
201
202 Assert(const Assert &other)
203 : SMART_ASSERT_A(*this), SMART_ASSERT_B(*this), context_(other.context_),
204 needs_handling_(true)
205 {
206 other.needs_handling_ = false;
207 }
208
209 ~Assert()
210 {
211 if (needs_handling_) {
212 handle_assert();
213 }
214 }
215
216 template <class type> Assert &print_current_val(const type &val, const char *my_msg)
217 {
218 std::ostringstream out;
219
220 Ioss::Private::is_null_finder<type> f;
221 bool bIsNull = f.is(val);
222 if (!bIsNull) {
223 out << val;
224 }
225 else {
226 // null string
227 out << "null";
228 }
229 context_.add_val(out.str(), my_msg);
230 return *this;
231 }
232
233 Assert &print_context(const char *file, int line)
234 {
235 context_.set_file_line(file, line);
236 return *this;
237 }
238
239 Assert &msg(const char *strMsg)
240 {
241 context_.set_level_msg(strMsg);
242 return *this;
243 }
244
245 Assert &level(int nLevel, const char *strMsg = nullptr)
246 {
247 context_.set_level(nLevel);
248 context_.set_level_msg(strMsg);
249 return *this;
250 }
251
252 Assert &warn(const char *strMsg = nullptr) { return level(lvl_warn, strMsg); }
253
254 Assert &debug(const char *strMsg = nullptr) { return level(lvl_debug, strMsg); }
255
256 Assert &error(const char *strMsg = nullptr) { return level(lvl_error, strMsg); }
257
258 Assert &fatal(const char *strMsg = nullptr) { return level(lvl_fatal, strMsg); }
259
260 // in this case, we set the default logger, and make it
261 // write everything to this file
262 static void set_log(const char *strFileName)
263 {
264 Ioss::Private::set_default_log_name(strFileName);
265 logger() = &SmartAssert::default_logger;
266 }
267
268 // in this case, we set the default logger, and make it
269 // write everything to this log
270 static void set_log(std::ostream &out)
271 {
272 Ioss::Private::set_default_log_stream(out);
273 logger() = &SmartAssert::default_logger;
274 }
275
276 static void set_log(assert_func log) { logger() = log; }
277
278 static void set_handler(int nLevel, assert_func handler) { handlers()[nLevel] = handler; }
279
280 private:
281 // handles the current assertion.
282 void handle_assert()
283 {
284 logger()(context_);
285 get_handler(context_.get_level())(context_);
286 }
287
288 /*
289 IMPORTANT NOTE:
290 The only reason logger & handlers are functions, are
291 because you might use SMART_ASSERT before main().
292
293 In this case, since they're statics, they might not
294 be initialized. However, making them functions
295 will make it work.
296 */
297
298 // the log
299 static assert_func &logger()
300 {
301 static assert_func inst;
302 return inst;
303 }
304
305 // the handler
306 typedef std::map<int, assert_func> handlers_collection;
307 static handlers_collection & handlers()
308 {
309 static handlers_collection inst;
310 return inst;
311 }
312
313 static assert_func get_handler(int nLevel)
314 {
315 handlers_collection::const_iterator found = handlers().find(nLevel);
316 if (found != handlers().end()) {
317 return (*found).second;
318 }
319
320 // we always assume the debug handler has been set
321 return (*handlers().find(lvl_debug)).second;
322 }
323
324 private:
325 assert_context context_;
326 mutable bool needs_handling_;
327 };
328
329 namespace SmartAssert {
330 inline Assert make_assert(const char *expr) { return Assert(expr); }
331 } // namespace SmartAssert
332
333 ////////////////////////////////////////////////////////
334 // macro trickery
335
336 // note: NEVER define SMART_ASSERT_DEBUG directly
337 // (it will be overridden);
338 //
339 // #define SMART_ASSERT_DEBUG_MODE instead
340
341 #ifdef SMART_ASSERT_DEBUG_MODE
342 #if SMART_ASSERT_DEBUG_MODE == 1
343 #define SMART_ASSERT_DEBUG
344 #else
345 #undef SMART_ASSERT_DEBUG
346 #endif
347
348 #else
349
350 // defaults
351 #ifndef NDEBUG
352 #define SMART_ASSERT_DEBUG
353 #else
354 #undef SMART_ASSERT_DEBUG
355 #endif
356 #endif
357
358 #ifdef SMART_ASSERT_DEBUG
359 // "debug" mode
360 #define SMART_ASSERT(expr) \
361 if ((expr)) \
362 ; \
363 else \
364 (void)::SmartAssert::make_assert(#expr).print_context(__FILE__, __LINE__).SMART_ASSERT_A /**/
365
366 #else
367 // "release" mode
368 #define SMART_ASSERT(expr) \
369 if (true) \
370 ; \
371 else \
372 (void)::SmartAssert::make_assert("").SMART_ASSERT_A /**/
373
374 #endif // ifdef SMART_ASSERT_DEBUG
375
376 #define SMART_VERIFY(expr) \
377 if ((expr)) \
378 ; \
379 else \
380 (void)::SmartAssert::make_assert(#expr) \
381 .error() \
382 .print_context(__FILE__, __LINE__) \
383 .SMART_ASSERT_A /**/
384
385 #define SMART_ASSERT_A(x) SMART_ASSERT_OP(x, B)
386 #define SMART_ASSERT_B(x) SMART_ASSERT_OP(x, A)
387
388 #define SMART_ASSERT_OP(x, next) SMART_ASSERT_A.print_current_val((x), #x).SMART_ASSERT_##next /**/
389
390 #if _MSC_VER > 1000
391 #pragma warning(pop)
392 #endif
393
394 #endif
assert_context::level_
int level_
Definition: Ioss_SmartAssert.h:134
assert_context::vals_array
std::vector< val_and_str > vals_array
Definition: Ioss_SmartAssert.h:101
assert_context::add_val
void add_val(const string &val, const string &str)
Definition: Ioss_SmartAssert.h:106
SmartAssert::dump_context_detail
void dump_context_detail(const assert_context &context, std::ostream &out)
Definition: Ioss_SmartAssert.C:100
SmartAssert::assert_func
void(*)(const assert_context &) assert_func
Definition: Ioss_SmartAssert.h:140
Ioss
The main namespace for the Ioss library.
Definition: Iocgns_DatabaseIO.h:50
Ioss::Private::init_assert
void init_assert()
Definition: Ioss_SmartAssert.C:223
Assert::context_
assert_context context_
Definition: Ioss_SmartAssert.h:325
Ioss::Private::is_null_finder
Definition: Ioss_SmartAssert.h:165
Assert::handle_assert
void handle_assert()
Definition: Ioss_SmartAssert.h:282
assert_context::get_vals_array
const vals_array & get_vals_array() const
Definition: Ioss_SmartAssert.h:104
Assert::set_log
static void set_log(std::ostream &out)
Definition: Ioss_SmartAssert.h:270
Assert::handlers_collection
std::map< int, assert_func > handlers_collection
Definition: Ioss_SmartAssert.h:306
SmartAssert
Definition: Ioss_SmartAssert.C:66
assert_context::set_level
void set_level(int nLevel)
Definition: Ioss_SmartAssert.h:109
Ioss::Private::set_default_log_stream
void set_default_log_stream(std::ostream &out)
Definition: Ioss_SmartAssert.C:233
Assert::Assert
Assert(const char *expr)
Definition: Ioss_SmartAssert.h:191
lvl_error
Definition: Ioss_SmartAssert.h:70
Ioss::Private::is_null_finder< char * >::is
bool is(char *const &val)
Definition: Ioss_SmartAssert.h:172
assert_context::val_and_str
std::pair< string, string > val_and_str
Definition: Ioss_SmartAssert.h:100
Assert::debug
Assert & debug(const char *strMsg=nullptr)
Definition: Ioss_SmartAssert.h:254
SmartAssert::default_debug_handler
void default_debug_handler(const assert_context &context)
Definition: Ioss_SmartAssert.C:151
Assert::error
Assert & error(const char *strMsg=nullptr)
Definition: Ioss_SmartAssert.h:256
SmartAssert::default_logger
void default_logger(const assert_context &context)
Definition: Ioss_SmartAssert.C:133
assert_context::assert_context
assert_context()
Definition: Ioss_SmartAssert.h:85
lvl_warn
Definition: Ioss_SmartAssert.h:63
SmartAssert::get_typeof_level
std::string get_typeof_level(int nLevel)
Definition: Ioss_SmartAssert.C:69
Assert::level
Assert & level(int nLevel, const char *strMsg=nullptr)
Definition: Ioss_SmartAssert.h:245
assert_context::vals_
vals_array vals_
Definition: Ioss_SmartAssert.h:131
assert_context::get_level_msg
const string & get_level_msg() const
Definition: Ioss_SmartAssert.h:122
Assert::handlers
static handlers_collection & handlers()
Definition: Ioss_SmartAssert.h:307
Assert::set_log
static void set_log(assert_func log)
Definition: Ioss_SmartAssert.h:276
Assert::SMART_ASSERT_B
Assert & SMART_ASSERT_B
Definition: Ioss_SmartAssert.h:189
SmartAssert::default_error_handler
void default_error_handler(const assert_context &context)
Definition: Ioss_SmartAssert.C:204
Assert::fatal
Assert & fatal(const char *strMsg=nullptr)
Definition: Ioss_SmartAssert.h:258
Ioss::Private::is_null_finder< const char * >::is
bool is(const char *const &val)
Definition: Ioss_SmartAssert.h:177
assert_context::file_
string file_
Definition: Ioss_SmartAssert.h:126
Assert::warn
Assert & warn(const char *strMsg=nullptr)
Definition: Ioss_SmartAssert.h:252
assert_context::get_context_line
int get_context_line() const
Definition: Ioss_SmartAssert.h:94
Assert::set_log
static void set_log(const char *strFileName)
Definition: Ioss_SmartAssert.h:262
Assert::SMART_ASSERT_A
Assert & SMART_ASSERT_A
Definition: Ioss_SmartAssert.h:188
Assert::assert_func
SmartAssert::assert_func assert_func
Definition: Ioss_SmartAssert.h:185
SmartAssert::default_fatal_handler
void default_fatal_handler(const assert_context &context)
Definition: Ioss_SmartAssert.C:212
assert_context::set_level_msg
void set_level_msg(const char *strMsg)
Definition: Ioss_SmartAssert.h:113
Ioss::Private::set_default_log_name
void set_default_log_name(const char *str)
Definition: Ioss_SmartAssert.C:240
Assert::msg
Assert & msg(const char *strMsg)
Definition: Ioss_SmartAssert.h:239
Assert::needs_handling_
bool needs_handling_
Definition: Ioss_SmartAssert.h:326
SmartAssert::dump_context_summary
void dump_context_summary(const assert_context &context, std::ostream &out)
Definition: Ioss_SmartAssert.C:85
lvl_debug
Definition: Ioss_SmartAssert.h:67
assert_context
Definition: Ioss_SmartAssert.h:80
Assert::print_current_val
Assert & print_current_val(const type &val, const char *my_msg)
Definition: Ioss_SmartAssert.h:216
Assert::get_handler
static assert_func get_handler(int nLevel)
Definition: Ioss_SmartAssert.h:313
assert_context::set_file_line
void set_file_line(const char *file, int line)
Definition: Ioss_SmartAssert.h:88
assert_context::msg_
string msg_
Definition: Ioss_SmartAssert.h:135
SmartAssert::make_assert
Assert make_assert(const char *expr)
Definition: Ioss_SmartAssert.h:330
Ioss::Private::is_null_finder::is
bool is(const T &) const
Definition: Ioss_SmartAssert.h:167
Assert::print_context
Assert & print_context(const char *file, int line)
Definition: Ioss_SmartAssert.h:233
assert_context::get_level
int get_level() const
Definition: Ioss_SmartAssert.h:110
assert_context::get_expr
const string & get_expr() const
Definition: Ioss_SmartAssert.h:98
assert_context::expr_
string expr_
Definition: Ioss_SmartAssert.h:130
assert_context::get_context_file
const string & get_context_file() const
Definition: Ioss_SmartAssert.h:93
Assert::Assert
Assert(const Assert &other)
Definition: Ioss_SmartAssert.h:202
Assert::set_handler
static void set_handler(int nLevel, assert_func handler)
Definition: Ioss_SmartAssert.h:278
assert_context::line_
int line_
Definition: Ioss_SmartAssert.h:127
Assert::~Assert
~Assert()
Definition: Ioss_SmartAssert.h:209
lvl_fatal
Definition: Ioss_SmartAssert.h:74
Assert::logger
static assert_func & logger()
Definition: Ioss_SmartAssert.h:299
SmartAssert::default_warn_handler
void default_warn_handler(const assert_context &context)
Definition: Ioss_SmartAssert.C:145
assert_context::set_expr
void set_expr(const string &str)
Definition: Ioss_SmartAssert.h:97
Assert
Definition: Ioss_SmartAssert.h:183