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 */
81 {
82  using string = std::string;
83 
84 public:
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_;
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 {
186 
187  // helpers, in order to be able to compile the code
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!
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 
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 
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  {
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  {
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.
283  {
284  logger()(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;
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:
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::handlers
static handlers_collection & handlers()
Definition: Ioss_SmartAssert.h:307
Assert::needs_handling_
bool needs_handling_
Definition: Ioss_SmartAssert.h:326
SmartAssert::default_logger
void default_logger(const assert_context &context)
Definition: Ioss_SmartAssert.C:133
Assert::Assert
Assert(const Assert &other)
Definition: Ioss_SmartAssert.h:202
Assert::print_current_val
Assert & print_current_val(const type &val, const char *my_msg)
Definition: Ioss_SmartAssert.h:216
Assert::assert_func
SmartAssert::assert_func assert_func
Definition: Ioss_SmartAssert.h:185
assert_context::assert_context
assert_context()
Definition: Ioss_SmartAssert.h:85
Assert::get_handler
static assert_func get_handler(int nLevel)
Definition: Ioss_SmartAssert.h:313
assert_context::get_context_file
const string & get_context_file() const
Definition: Ioss_SmartAssert.h:93
assert_context::expr_
string expr_
Definition: Ioss_SmartAssert.h:130
lvl_error
Definition: Ioss_SmartAssert.h:70
Assert::print_context
Assert & print_context(const char *file, int line)
Definition: Ioss_SmartAssert.h:233
Assert::SMART_ASSERT_B
Assert & SMART_ASSERT_B
Definition: Ioss_SmartAssert.h:189
Ioss::Private::is_null_finder
Definition: Ioss_SmartAssert.h:165
SmartAssert
Definition: Ioss_SmartAssert.C:66
assert_context::set_level
void set_level(int nLevel)
Definition: Ioss_SmartAssert.h:109
Ioss
The main namespace for the Ioss library.
Definition: Ioad_DatabaseIO.C:66
Ioss::Private::is_null_finder::is
bool is(const T &) const
Definition: Ioss_SmartAssert.h:167
Assert::debug
Assert & debug(const char *strMsg=nullptr)
Definition: Ioss_SmartAssert.h:254
assert_context::level_
int level_
Definition: Ioss_SmartAssert.h:134
assert_context::set_level_msg
void set_level_msg(const char *strMsg)
Definition: Ioss_SmartAssert.h:113
assert_context::get_level
int get_level() const
Definition: Ioss_SmartAssert.h:110
SmartAssert::dump_context_summary
void dump_context_summary(const assert_context &context, std::ostream &out)
Definition: Ioss_SmartAssert.C:85
Assert::set_log
static void set_log(std::ostream &out)
Definition: Ioss_SmartAssert.h:270
Assert::SMART_ASSERT_A
Assert & SMART_ASSERT_A
Definition: Ioss_SmartAssert.h:188
Assert::context_
assert_context context_
Definition: Ioss_SmartAssert.h:325
SmartAssert::get_typeof_level
std::string get_typeof_level(int nLevel)
Definition: Ioss_SmartAssert.C:69
Ioss::Private::set_default_log_name
void set_default_log_name(const char *str)
Definition: Ioss_SmartAssert.C:240
assert_context::file_
string file_
Definition: Ioss_SmartAssert.h:126
Assert::fatal
Assert & fatal(const char *strMsg=nullptr)
Definition: Ioss_SmartAssert.h:258
SmartAssert::default_warn_handler
void default_warn_handler(const assert_context &context)
Definition: Ioss_SmartAssert.C:145
Assert
Definition: Ioss_SmartAssert.h:183
Assert::logger
static assert_func & logger()
Definition: Ioss_SmartAssert.h:299
assert_context::msg_
string msg_
Definition: Ioss_SmartAssert.h:135
Ioss::Private::is_null_finder< char * >::is
bool is(char *const &val)
Definition: Ioss_SmartAssert.h:172
Assert::set_handler
static void set_handler(int nLevel, assert_func handler)
Definition: Ioss_SmartAssert.h:278
assert_context::set_file_line
void set_file_line(const char *file, int line)
Definition: Ioss_SmartAssert.h:88
assert_context::set_expr
void set_expr(const string &str)
Definition: Ioss_SmartAssert.h:97
Assert::msg
Assert & msg(const char *strMsg)
Definition: Ioss_SmartAssert.h:239
Assert::warn
Assert & warn(const char *strMsg=nullptr)
Definition: Ioss_SmartAssert.h:252
Assert::set_log
static void set_log(assert_func log)
Definition: Ioss_SmartAssert.h:276
Ioss::Private::is_null_finder< const char * >::is
bool is(const char *const &val)
Definition: Ioss_SmartAssert.h:177
assert_context::val_and_str
std::pair< string, string > val_and_str
Definition: Ioss_SmartAssert.h:100
lvl_debug
Definition: Ioss_SmartAssert.h:67
SmartAssert::default_fatal_handler
void default_fatal_handler(const assert_context &context)
Definition: Ioss_SmartAssert.C:212
SmartAssert::default_debug_handler
void default_debug_handler(const assert_context &context)
Definition: Ioss_SmartAssert.C:151
Assert::Assert
Assert(const char *expr)
Definition: Ioss_SmartAssert.h:191
Assert::set_log
static void set_log(const char *strFileName)
Definition: Ioss_SmartAssert.h:262
Ioss::Private::set_default_log_stream
void set_default_log_stream(std::ostream &out)
Definition: Ioss_SmartAssert.C:233
assert_context::get_level_msg
const string & get_level_msg() const
Definition: Ioss_SmartAssert.h:122
assert_context::get_expr
const string & get_expr() const
Definition: Ioss_SmartAssert.h:98
assert_context::get_context_line
int get_context_line() const
Definition: Ioss_SmartAssert.h:94
SmartAssert::make_assert
Assert make_assert(const char *expr)
Definition: Ioss_SmartAssert.h:330
assert_context::add_val
void add_val(const string &val, const string &str)
Definition: Ioss_SmartAssert.h:106
assert_context::vals_array
std::vector< val_and_str > vals_array
Definition: Ioss_SmartAssert.h:101
Assert::~Assert
~Assert()
Definition: Ioss_SmartAssert.h:209
SmartAssert::default_error_handler
void default_error_handler(const assert_context &context)
Definition: Ioss_SmartAssert.C:204
Assert::level
Assert & level(int nLevel, const char *strMsg=nullptr)
Definition: Ioss_SmartAssert.h:245
SmartAssert::dump_context_detail
void dump_context_detail(const assert_context &context, std::ostream &out)
Definition: Ioss_SmartAssert.C:100
assert_context::line_
int line_
Definition: Ioss_SmartAssert.h:127
SmartAssert::assert_func
void(*)(const assert_context &) assert_func
Definition: Ioss_SmartAssert.h:140
assert_context::get_vals_array
const vals_array & get_vals_array() const
Definition: Ioss_SmartAssert.h:104
assert_context
Definition: Ioss_SmartAssert.h:80
Assert::handle_assert
void handle_assert()
Definition: Ioss_SmartAssert.h:282
lvl_warn
Definition: Ioss_SmartAssert.h:63
assert_context::vals_
vals_array vals_
Definition: Ioss_SmartAssert.h:131
lvl_fatal
Definition: Ioss_SmartAssert.h:74
Ioss::Private::init_assert
void init_assert()
Definition: Ioss_SmartAssert.C:223
Assert::error
Assert & error(const char *strMsg=nullptr)
Definition: Ioss_SmartAssert.h:256
Assert::handlers_collection
std::map< int, assert_func > handlers_collection
Definition: Ioss_SmartAssert.h:306