DMRITool  v0.1.1-139-g860d86b4
Diffusion MRI Tool
utlSmartAssert.h
Go to the documentation of this file.
1 // smart_assert.h
2 //
4 
13 #if !defined(SMART_ASSERT_H)
14 #define SMART_ASSERT_H
15 
16 #if _MSC_VER > 1000
17 #pragma once
18 #endif // _MSC_VER > 1000
19 
20 #if _MSC_VER > 1000
21 
22 // note:
23 // moving this after pragma push will render it useless (VC6)
24 //
25 // identifier truncated to 255 chars in debug information
26 #pragma warning ( disable : 4786)
27 
28 #pragma warning ( push )
29 // *this used in base-member initialization; it's ok
30 #pragma warning ( disable : 4355)
31 #endif
32 
33 #include <string>
34 #include <iostream>
35 #include <sstream>
36 #include <utility>
37 #include <vector>
38 #include <map>
39 
40 #include <fstream>
41 #include <set>
42 #include <sstream>
43 #include <stdlib.h>
44 #include <stdexcept>
45 
46 #include "utlCoreMacro.h"
47 
48 
49 #ifdef MATLAB_MEX_FILE
50 #include <mex.h>
51 #define SA_Abort(expout) mexErrMsgTxt(expout)
52 #else
53 #define SA_Abort(expout) do { std::cerr << expout <<"\n" << std::flush; abort(); } while(0)
54 #endif
55 
56 #if defined(__BORLANDC__)
57  #define __SMART_ASSERT_LOCATION__ __FUNC__
58 #elif defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(CSWIG)
59  #define __SMART_ASSERT_LOCATION__ __FUNCSIG__
60 #elif defined(__GNUC__)
61  #define __SMART_ASSERT_LOCATION__ __PRETTY_FUNCTION__
62 #else
63  #define __SMART_ASSERT_LOCATION__ __FUNCTION__
64 #endif
65 
66 
67 namespace smart_assert {
68 enum {
69 
70  // default behavior - just loggs this assert,
71  lvl_log = 0,
72 
73  // default behavior - just loggs this assert
74  // (a message is shown to the user to the console)
75  lvl_warn = 100,
76 
77  // default behavior - asks the user what to do:
78  // Ignore/ Retry/ etc.
79  lvl_debug = 200,
80 
81  // default behavior - throws a smart_assert_error
82  lvl_error = 300,
83 
84  // default behavior - dumps all assert context to console,
85  // and aborts
86  lvl_fatal = 1000
87 };
88 
89 enum{
92 };
93 
94 
95 /*
96  contains details about a failed assertion
97 */
99  typedef std::string string;
100 public:
102  }
103 
104  // where the assertion failed: file & line
105  void set_file_line( const char * file, int line) {
106  file_ = file;
107  line_ = line;
108  }
109  void set_file_line_func_cond( const char * file, int line, const char * func, int cond) {
110  file_ = file;
111  line_ = line;
112  func_ = func;
113  condition_ = cond;
114  }
115  const string & get_context_file() const { return file_; }
116  const string & get_context_func() const { return func_; }
117  int get_context_line() const { return line_; }
118 
119  // get/ set expression
120  void set_expr( const string & str) { expr_ = str; }
121  const string & get_expr() const { return expr_; }
122 
123  typedef std::pair< string, string> val_and_str;
124  typedef std::vector< val_and_str> vals_array;
125  // return values array as a vector of pairs:
126  // [Value, corresponding string]
127  const vals_array & get_vals_array() const { return vals_; }
128  // adds one value and its corresponding string
129  void add_val( const string & val, const string & str) {
130  vals_.push_back( val_and_str( val, str) );
131  }
132 
133  // get/set level of assertion
134  void set_level( int nLevel) { level_ = nLevel; }
135  int get_level() const { return level_; }
136 
137  void set_condition( int cond) { condition_ = cond; }
138  int get_condition() const { return condition_; }
139 
140  // get/set (user-friendly) message
141  void set_level_msg( const char * strMsg) {
142  if ( strMsg)
143  msg_ = strMsg;
144  else
145  msg_.erase();
146  }
147  const string & get_level_msg() const { return msg_; }
148 
149 private:
150  // where the assertion occured
151  string file_;
152  string func_;
153  int line_;
154 
155  // expression and values
156  string expr_;
157  vals_array vals_;
158 
159  // level and message
160  int level_;
162  string msg_;
163 };
164 
165 
166 
167  typedef void (*assert_func)( const assert_context & context);
168 
169  // helpers
170  inline std::string get_typeof_level( int nLevel);
171  inline void dump_context_summary( const assert_context & context, std::ostream & out);
172  inline void dump_context_detail( const assert_context & context, std::ostream & out);
173 
174  // defaults
175  inline void default_log_handler( const assert_context & context);
176  inline void default_warn_handler( const assert_context & context);
177  inline void default_debug_handler( const assert_context & context);
178  inline void default_error_handler( const assert_context & context);
179  inline void default_fatal_handler( const assert_context & context);
180  inline void default_logger( const assert_context & context);
181 
182 
183 // namespace Private {
184  inline void init_assert();
185  inline void set_default_log_stream( std::ostream & out);
186  inline void set_default_log_name( const char * str);
187 
188  // allows finding if a value is of type 'const char *'
189  // and is null; if so, we cannot print it to an ostream
190  // directly!!!
191  template< class T>
192  struct is_null_finder {
193  bool is( const T &) const {
194  return false;
195  }
196  };
197 
198  template<>
199  struct is_null_finder< char*> {
200  bool is( char * const & val) {
201  return val == 0;
202  }
203  };
204 
205  template<>
206  struct is_null_finder< const char*> {
207  bool is( const char * const & val) {
208  return val == 0;
209  }
210  };
211 
212 
213 // } // namespace Private
214 
215 
216 struct Assert {
218 
219  // helpers, in order to be able to compile the code
222 
223  Assert( const char * expr)
224  : SMART_ASSERT_A( *this),
225  SMART_ASSERT_B( *this),
226  needs_handling_( true) {
227  context_.set_expr( expr);
228 
229  if ( ( logger() == 0) || handlers().size() < 5) {
230  // used before main!
231  init_assert();
232  }
233  }
234 
235  Assert( const Assert & other)
236  : SMART_ASSERT_A( *this),
237  SMART_ASSERT_B( *this),
238  context_( other.context_),
239  needs_handling_( true) {
240  other.needs_handling_ = false;
241  }
242 
244  if ( needs_handling_)
245  handle_assert();
246  }
247 
248  template< class type>
249  Assert & print_current_val( const type & val, const char * msg) {
250  std::ostringstream out;
251 
253  bool bIsNull = f.is( val);
254  if ( !bIsNull)
255  out << val;
256  else
257  // null string
258  out << "null";
259  context_.add_val( out.str(), msg);
260  return *this;
261  }
262 
263  Assert & print_context( const char * file, int line) {
264  context_.set_file_line( file, line);
265  return *this;
266  }
267  Assert & print_context( const char * file, int line, const char* func, int cond) {
268  context_.set_file_line_func_cond( file, line, func, cond);
269  return *this;
270  }
271 
272  Assert & msg( const char * strMsg) {
273  context_.set_level_msg( strMsg);
274  return *this;
275  }
276 
277  Assert & level( int nLevel, const char * strMsg = 0) {
278  context_.set_level( nLevel);
279  context_.set_level_msg( strMsg);
280  return *this;
281  }
282 
283  Assert & log( const char * strMsg = 0) {
284  return level( lvl_log, strMsg);
285  }
286 
287  Assert & warn( const char * strMsg = 0) {
288  return level( lvl_warn, strMsg);
289  }
290 
291  Assert & debug( const char * strMsg = 0) {
292  return level( lvl_debug, strMsg);
293  }
294 
295  Assert & error( const char * strMsg = 0) {
296  return level( lvl_error, strMsg);
297  }
298 
299  Assert & fatal( const char * strMsg = 0) {
300  return level( lvl_fatal, strMsg);
301  }
302 
303  // in this case, we set the default logger, and make it
304  // write everything to this file
305  static void set_log( const char * strFileName) {
306  set_default_log_name( strFileName);
307  logger() = &smart_assert::default_logger;
308  }
309 
310  // in this case, we set the default logger, and make it
311  // write everything to this log
312  static void set_log( std::ostream & out) {
314  logger() = &smart_assert::default_logger;
315  }
316 
317  static void set_log( assert_func log) {
318  logger() = log;
319  }
320 
321  static void set_handler( int nLevel, assert_func handler) {
322  handlers()[ nLevel] = handler;
323  }
324 
325 private:
326  // handles the current assertion.
327  void handle_assert() {
328  logger()( context_);
329  get_handler( context_.get_level() )( context_);
330  }
331 
332  /*
333  IMPORTANT NOTE:
334  The only reason logger & handlers are functions, are
335  because you might use SMART_ASSERT before main().
336 
337  In this case, since they're statics, they might not
338  be initialized. However, making them functions
339  will make it work.
340  */
341 
342  // the log
343  static assert_func & logger() {
344  static assert_func inst;
345  return inst;
346  }
347 
348  // the handler
349  typedef std::map< int, assert_func> handlers_collection;
350  static handlers_collection & handlers() {
351  static handlers_collection inst;
352  return inst;
353  }
354 
355  static assert_func get_handler( int nLevel) {
356  handlers_collection::const_iterator found = handlers().find( nLevel);
357  if ( found != handlers().end() )
358  return found->second;
359  else
360  // we always assume the debug handler has been set
361  return handlers().find( lvl_debug)->second;
362  }
363 
364 private:
366  mutable bool needs_handling_;
367 
368 };
369 
370  inline Assert make_assert( const char * expr) {
371  return Assert( expr);
372  }
373 } // namespace smart_assert
374 
375 
376 
378 // macro trickery
379 
380 // note: NEVER define SMART_ASSERT_DEBUG directly
381 // (it will be overridden);
382 //
383 // #define SMART_ASSERT_DEBUG_MODE instead
384 
385 #ifdef SMART_ASSERT_DEBUG_MODE
386  #if SMART_ASSERT_DEBUG_MODE == 1
387  #define SMART_ASSERT_DEBUG
388  #else
389  #undef SMART_ASSERT_DEBUG
390  #endif
391 
392 #else
393 
394 // defaults
395  #ifndef NDEBUG
396  #define SMART_ASSERT_DEBUG
397  #else
398  #undef SMART_ASSERT_DEBUG
399  #endif
400 #endif
401 
402 #ifdef SMART_ASSERT_DEBUG
403 // "debug" mode
404 #define SMART_ASSERT( expr) \
405  if ( (expr) ) ; \
406  else ::smart_assert::make_assert( #expr).print_context( __FILE__, __LINE__,__SMART_ASSERT_LOCATION__, ::smart_assert::lvl_condition_assert).SMART_ASSERT_A \
407 
408 
409 #else
410 // "release" mode
411 #define SMART_ASSERT( expr) \
412  if ( true ) ; \
413  else ::smart_assert::make_assert("").SMART_ASSERT_A \
414 
415 
416 #endif // ifdef SMART_ASSERT_DEBUG
417 
418 
419 #define SMART_VERIFY( expr) \
420  if ( (expr) ) ; \
421  else ::smart_assert::make_assert( #expr).error().print_context( __FILE__, __LINE__,__SMART_ASSERT_LOCATION__, ::smart_assert::lvl_condition_assert).SMART_ASSERT_A \
422 
423 
424 #define SMART_EXCEPTION( expr) \
425  if ( !(expr) ) ; \
426  else ::smart_assert::make_assert( #expr).error().print_context( __FILE__, __LINE__,__SMART_ASSERT_LOCATION__, ::smart_assert::lvl_condition_exception).SMART_ASSERT_A \
427 
428 #define SMART_PRINT \
429  if ( false ) ; \
430  else ::smart_assert::make_assert("").log().print_context( __FILE__, __LINE__,__SMART_ASSERT_LOCATION__, ::smart_assert::lvl_condition_exception).SMART_ASSERT_A \
431 
432 #define SMART_ASSERT_A(x) SMART_ASSERT_OP(x, B)
433 #define SMART_ASSERT_B(x) SMART_ASSERT_OP(x, A)
434 
435 #define SMART_ASSERT_OP(x, next) \
436  SMART_ASSERT_A.print_current_val((x), #x).SMART_ASSERT_##next \
437 
438 
439 
440 #if _MSC_VER > 1000
441 #pragma warning ( pop )
442 #endif
443 
444 inline void break_into_debugger() {
445 // MSVC, BCB,
446 #if (defined _MSC_VER) || (defined __BORLANDC__)
447  __asm { int 3 };
448 #elif defined(__GNUC__)
449  // GCC
450  __asm ("int $0x3");
451 #else
452  # error Please supply instruction to break into code
453 #endif
454 }
455 
456 
457 namespace {
458  // in case we're logging using the default logger...
459  struct stream_holder {
460  stream_holder() : out_( 0), owns_( false) {}
461  ~stream_holder() {
462  if ( owns_)
463  delete out_;
464  out_ = 0;
465  }
466  std::ostream * out_;
467  bool owns_;
468  };
469  // information about the stream we write to, in case
470  // we're using the default logger
471  stream_holder default_logger_info;
472 
473  // intitializes the SMART_ASSERT library
474  struct assert_initializer {
475  assert_initializer() {
477  }
478  } init;
479 } // anonymous namespace
480 
481 
482 
483 namespace smart_assert {
484 
485  // returns a message corresponding to the type of level
486  inline std::string get_typeof_level( int nLevel) {
487  switch ( nLevel) {
488  case lvl_log: return __UTL_LOG_STRING;
489  case lvl_warn: return __UTL_WARNING_STRING;
490  case lvl_debug: return __UTL_DEBUG_STRING;
491  case lvl_error: return __UTL_ERROR_STRING;
492  case lvl_fatal: return __UTL_FATAL_STRING;
493  default: {
494  std::ostringstream out;
495  out << "(level=" << nLevel << ")";
496  return out.str();
497  }
498  };
499  }
500 
501  // helpers, for dumping the assertion context
502  inline void dump_context_summary( const assert_context & context, std::ostream & out) {
503  out << "\n" << get_typeof_level( context.get_level() )
504  << " in "<<__UTL_BOLD("File")<<": " << context.get_context_file() << ", "<<__UTL_BOLD("Line")<<": " << context.get_context_line() << ", "<<__UTL_BOLD("Function")<<": " << context.get_context_func() << '\n';
505  if ( !context.get_level_msg().empty())
506  // we have a user-friendly message
507  out << context.get_level_msg();
508  else
509  if (context.get_expr()!="\"\"" && context.get_expr()!="")
510  out << __UTL_BOLD("Expression")<<" : '" << __UTL_EXPSTR(context.get_expr()) <<"' " << (context.get_condition()==lvl_condition_assert?"failed":"satisfied");
511  out << std::endl;
512  }
513 
514  inline void dump_context_detail( const assert_context & context, std::ostream & out) {
515  out << "\n" << get_typeof_level( context.get_level() )
516  << " in "<<__UTL_BOLD("File")<<": " << context.get_context_file() << ", "<<__UTL_BOLD("Line")<<": " << context.get_context_line() << ", "<<__UTL_BOLD("Function")<<": " << context.get_context_func() << '\n';
517  if ( !context.get_level_msg().empty())
518  out << __UTL_BOLD("msg")<<": '" << context.get_level_msg() << "'\n";
519  if (context.get_expr()!="\"\"" && context.get_expr()!="")
520  out << __UTL_BOLD("Expression")<<" : '" << __UTL_EXPSTR(context.get_expr()) <<"' " << (context.get_condition()==lvl_condition_assert?"failed":"satisfied") <<"\n";
521 
523  const vals_array & aVals = context.get_vals_array();
524  if ( !aVals.empty() ) {
525  bool bFirstTime = true;
526  vals_array::const_iterator first = aVals.begin(), last = aVals.end();
527  while ( first != last) {
528  if ( bFirstTime) {
529  out << "Values: ";
530  bFirstTime = false;
531  }
532  else {
533  out << " ";
534  }
535  out << first->second << "='" << first->first << "'\n";
536  ++first;
537  }
538  }
539  out << std::endl;
540  }
541 
542  inline void dump_context_log_detail( const assert_context & context, std::ostream & out) {
543  out << "\n" << get_typeof_level( context.get_level() )
544  << " in "<<__UTL_BOLD("File")<<": " << context.get_context_file() << ", "<<__UTL_BOLD("Line")<<": " << context.get_context_line() << ", "<<__UTL_BOLD("Function")<<": " << context.get_context_func() << '\n';
545  if ( !context.get_level_msg().empty())
546  out << __UTL_BOLD("msg")<<": '" << context.get_level_msg() << "'\n";
547  if (context.get_expr()!="\"\"" && context.get_expr()!="")
548  out << __UTL_BOLD("Expression")<<" : '" << __UTL_EXPSTR(context.get_expr()) <<"' " << (context.get_condition()==lvl_condition_assert?"failed":"satisfied") <<"\n";
549 
551  const vals_array & aVals = context.get_vals_array();
552  if ( !aVals.empty() ) {
553  if (aVals.size()==1)
554  out << "(" << aVals[0].second << ") = " << "(" << aVals[0].first << ")";
555  else
556  {
557  out << "(";
558  for ( int i = 0; i < aVals.size()-1; i += 1 )
559  out << aVals[i].second << ", ";
560  out << aVals.back().second << ") = (";
561  for ( int i = 0; i < aVals.size()-1; i += 1 )
562  out << aVals[i].first << ", ";
563  out << aVals.back().first << ")";
564  }
565  out << std::endl;
566  }
567  out << std::endl;
568  }
569 
571  // logger
572 
573  inline void default_logger( const assert_context & context) {
574  if ( default_logger_info.out_ == 0)
575  return;
576  dump_context_log_detail( context, *( default_logger_info.out_) );
577  // if ( default_logger_info.out_ == 0)
578  // dump_context_log_detail( context, std::cout );
579  // else
580  // dump_context_log_detail( context, *( default_logger_info.out_));
581  }
582 
584  // handlers
585 
586  inline void default_log_handler( const assert_context & context)
587  {
588  if ( default_logger_info.out_ == 0)
589  dump_context_log_detail( context, std::cout );
590  else
591  dump_context_log_detail( context, *( default_logger_info.out_));
592  }
593 
594  // warn : just dump summary to console
595  inline void default_warn_handler( const assert_context & context) {
596  dump_context_detail( context, std::cout);
597  }
598 
599 
600  // debug: ask user what to do
601  inline void default_debug_handler( const assert_context & context) {
602  static bool ignore_all = false;
603  if ( ignore_all)
604  // ignore All asserts
605  return;
606  typedef std::pair< std::string, int> file_and_line;
607  static std::set< file_and_line> ignorer;
608  if ( ignorer.find( file_and_line( context.get_context_file(), context.get_context_line())) != ignorer.end() )
609  // this is Ignored Forever
610  return;
611 
612  dump_context_summary( context, std::cerr );
613  std::cerr << "\nPress (I)gnore/ Igore (F)orever/ Ignore (A)ll/ (D)ebug/ A(b)ort: ";
614  std::cerr.flush();
615  char ch = 0;
616 
617  bool bContinue = true;
618  while ( bContinue && std::cin.get( ch)) {
619  bContinue = false;
620  switch ( ch) {
621  case 'i': case 'I':
622  // ignore
623  break;
624 
625  case 'f': case 'F':
626  // ignore forever
627  ignorer.insert( file_and_line( context.get_context_file(), context.get_context_line()));
628  break;
629 
630  case 'a': case 'A':
631  // ignore all
632  ignore_all = true;
633  break;
634 
635  case 'd': case 'D':
636  // break
638  break;
639 
640  case 'b': case 'B':
641  SA_Abort("");
642  break;
643 
644  default:
645  bContinue = true;
646  break;
647  }
648  }
649  }
650 
651 
652  // error : throw a runtime exception
653  inline void default_error_handler( const assert_context & context) {
654  std::ostringstream out;
655  dump_context_detail( context, out);
656  throw std::runtime_error( out.str());
657  }
658 
659 
660  // fatal : dump error and abort
661  inline void default_fatal_handler( const assert_context & context) {
662  dump_context_detail( context, std::cerr);
663  SA_Abort("");
664  }
665 
666 
667 
668 
669 
670  inline void init_assert() {
677  }
678 
679  // sets the default logger to write to this stream
680  inline void set_default_log_stream( std::ostream & out) {
681  default_logger_info.out_ = &out;
682  default_logger_info.owns_ = false;
683  }
684 
685  // sets the default logger to write to this file
686  inline void set_default_log_name( const char * str) {
687  default_logger_info.owns_ = false;
688  default_logger_info.out_ = new std::ofstream( str);
689  default_logger_info.owns_ = true;
690  }
691 
692 } // namespace smart_assert
693 
694 
695 #endif
void set_default_log_stream(std::ostream &out)
const string & get_level_msg() const
const string & get_context_file() const
void default_debug_handler(const assert_context &context)
static void set_handler(int nLevel, assert_func handler)
static assert_func & logger()
void set_expr(const string &str)
Assert & fatal(const char *strMsg=0)
const vals_array & get_vals_array() const
void default_fatal_handler(const assert_context &context)
std::pair< string, string > val_and_str
const string & get_context_func() const
#define __UTL_FATAL_STRING
Definition: utlCoreMacro.h:173
void(* assert_func)(const assert_context &context)
void break_into_debugger()
void default_error_handler(const assert_context &context)
void init_assert()
const string & get_expr() const
void default_logger(const assert_context &context)
Assert & print_context(const char *file, int line)
static handlers_collection & handlers()
smart_assert::assert_func assert_func
Assert(const char *expr)
#define SA_Abort(expout)
static assert_func get_handler(int nLevel)
static void set_log(std::ostream &out)
void dump_context_summary(const assert_context &context, std::ostream &out)
void default_warn_handler(const assert_context &context)
void add_val(const string &val, const string &str)
Assert & level(int nLevel, const char *strMsg=0)
void set_file_line_func_cond(const char *file, int line, const char *func, int cond)
static void set_log(assert_func log)
static void set_log(const char *strFileName)
void set_level_msg(const char *strMsg)
Assert make_assert(const char *expr)
Assert & print_current_val(const type &val, const char *msg)
#define __UTL_LOG_STRING
Definition: utlCoreMacro.h:177
Assert & debug(const char *strMsg=0)
std::string get_typeof_level(int nLevel)
#define __UTL_DEBUG_STRING
Definition: utlCoreMacro.h:176
Assert & error(const char *strMsg=0)
std::vector< val_and_str > vals_array
Assert & log(const char *strMsg=0)
Assert & print_context(const char *file, int line, const char *func, int cond)
#define __UTL_WARNING_STRING
Definition: utlCoreMacro.h:175
void dump_context_detail(const assert_context &context, std::ostream &out)
void set_file_line(const char *file, int line)
void default_log_handler(const assert_context &context)
Assert(const Assert &other)
Assert & warn(const char *strMsg=0)
#define __UTL_ERROR_STRING
Definition: utlCoreMacro.h:174
macros for utlCore
std::map< int, assert_func > handlers_collection
assert_context context_
bool is(const T &) const
Assert & msg(const char *strMsg)
void set_default_log_name(const char *str)
#define __UTL_EXPSTR(str)
Definition: utlCoreMacro.h:179
#define __UTL_BOLD(str)
Definition: utlCoreMacro.h:178
void dump_context_log_detail(const assert_context &context, std::ostream &out)