LifeV
LifeAssertSmart.hpp
Go to the documentation of this file.
1 //@HEADER
2 /*
3 *******************************************************************************
4 
5 Copyright (C) 2004, 2005, 2007 EPFL, Politecnico di Milano, INRIA
6 Copyright (C) 2010 EPFL, Politecnico di Milano, Emory University
7 
8 This file is part of LifeV.
9 
10 LifeV is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
14 
15 LifeV is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
19 
20 You should have received a copy of the GNU Lesser General Public License
21 along with LifeV. If not, see <http://www.gnu.org/licenses/>.
22 
23 *******************************************************************************
24 */
25 //@HEADER
26 /*!
27  @file
28  @brief Complex assertion mechanism
29 
30  @date 16-01-2005
31  @author Christophe Prud'homme <christophe.prudhomme@epfl.ch>
32 
33  @maintainer Radu Popescu <radu.popescu@epfl.ch>
34 */
35 
36 #ifndef SMART_ASSERT_H
37 #define SMART_ASSERT_H
38 
39 #include <sstream>
40 #include <utility>
41 #include <vector>
42 #include <map>
43 #include <iostream>
44 #include <set>
45 
46 namespace LifeV
47 {
48 enum
49 {
50  // default behavior - just loggs this assert
51  // (a message is shown to the user to the console)
52  lvl_warn = 100,
53 
54  // default behavior - asks the user what to do:
55  // Ignore/ Retry/ etc.
56  lvl_debug = 200,
57 
58  // default behavior - throws a SmartAssert_error
59  lvl_error = 300,
60 
61  // default behavior - dumps all assert context to console,
62  // and aborts
63  lvl_fatal = 1000
64 };
65 
66 /**
67  \class AssertContext
68  \brief contains details about a failed assertion
69 */
71 {
72 public:
73  //! @name Public typedefs
74  //@{
75  typedef std::pair< std::string, std::string> valueAndString_Type;
77  //@}
78 
79  //! @name Constructor
80  //@{
82  virtual ~AssertContext() {}
83  //@}
84 
85  //! @name Public methods
86  //@{
87  // adds one value and its corresponding string
88  void addValue ( const std::string& val, const std::string& str)
89  {
90  M_values.push_back ( valueAndString_Type ( val, str) );
91  }
92  //@}
93 
94  //! @name Set methods
95  //@{
96  void setFileLine ( const char* file, int line)
97  {
98  M_file = file;
99  M_contextLine = line;
100  }
101 
102  void setExpression ( const std::string& str)
103  {
104  M_expression = str;
105  }
106 
107  void setLevel ( int nLevel)
108  {
109  M_level = nLevel;
110  }
111 
112  void setLevelMsg ( const char* strMsg)
113  {
114  if ( strMsg)
115  {
116  M_message = strMsg;
117  }
118  else
119  {
120  M_message.erase();
121  }
122  }
123  //@}
124 
125  //! @name Get methods
126  //@{
127  const std::string& file() const
128  {
129  return M_file;
130  }
131 
132  int contextLine() const
133  {
134  return M_contextLine;
135  }
136 
137  const std::string& expression() const
138  {
139  return M_expression;
140  }
141 
142  const valueArray_Type& values() const
143  {
144  return M_values;
145  }
146 
147  const int& level() const
148  {
149  return M_level;
150  }
151 
152  const std::string& message() const
153  {
154  return M_message;
155  }
156  //@}
157 
158 private:
159  // where the assertion occured
160  std::string M_file;
162 
163  // expression and values
164  std::string M_expression;
166 
167  // level and message
168  int M_level;
169  std::string M_message;
170 };
171 
172 
173 namespace SmartAssert
174 {
175 
176 typedef void (*assertFunction_Type) ( const AssertContext& context);
177 
178 // helpers
179 std::string getTypeofLevel ( int nLevel);
180 void dumpContextSummary ( const AssertContext& context, std::ostream& out);
181 void dumpContextDetail ( const AssertContext& context, std::ostream& out);
182 
183 // defaults
184 void defaultWarnHandler ( const AssertContext& context);
185 void defaultDebugHandler ( const AssertContext& context);
186 void defaultErrorHandler ( const AssertContext& context);
187 void defaultFatalHandler ( const AssertContext& context);
188 void defaultLogger ( const AssertContext& context);
189 
190 } // namespace SmartAssert
191 
192 namespace Private
193 {
194 void initAssert();
195 void setDefaultLogStream ( std::ostream& out);
196 void setDefaultLogName ( const char* str);
197 
198 // allows finding if a value is of type 'const char *'
199 // and is null; if so, we cannot print it to an ostream
200 // directly!!!
201 template< class T>
203 {
204  bool is ( const T&) const
205  {
206  return false;
207  }
208 };
209 
210 template<>
211 struct isNullFinder< char*>
212 {
213  bool is ( char* const& val)
214  {
215  return val == 0;
216  }
217 };
218 
219 template<>
220 struct isNullFinder< const char*>
221 {
222  bool is ( const char* const& val)
223  {
224  return val == 0;
225  }
226 };
227 
228 } // namespace Private
229 
230 struct Assert
231 {
232  //! @name Helpers and Typedefs
233  //@{
234  typedef SmartAssert::assertFunction_Type assertFunction_Type;
235 
236  // helpers, in order to be able to compile the code
239  //@}
240 
241  //! @name Constructors and destructor
242  //@{
243  Assert ( const char* expr) :
244  SMART_ASSERT_A ( *this),
245  SMART_ASSERT_B ( *this),
246  M_needsHandling ( true)
247  {
248  M_context.setExpression ( expr);
249 
250  if ( ( logger() == 0) || handlers().size() < 4)
251  {
252  // used before main!
254  }
255  }
256 
257  Assert ( const Assert& other) :
258  SMART_ASSERT_A ( *this),
259  SMART_ASSERT_B ( *this),
260  M_context ( other.M_context),
261  M_needsHandling ( true)
262  {
263  other.M_needsHandling = false;
264  }
265 
266  virtual ~Assert()
267  {
268  if ( M_needsHandling)
269  {
271  }
272  }
273  //@}
274 
275  //! @name Public methods
276  //@{
277  template< class type>
278  Assert& printCurrentValue ( const type& val, const char* msg)
279  {
280  std::ostringstream out;
281 
282  Private::isNullFinder< type> f;
283  bool bIsNull = f.is ( val);
284  if ( !bIsNull)
285  {
286  out << val;
287  }
288  else
289  // null string
290  {
291  out << "null";
292  }
293  M_context.addValue ( out.str(), msg);
294  return *this;
295  }
296 
297  Assert& printContext ( const char* file, int line)
298  {
299  M_context.setFileLine ( file, line);
300  return *this;
301  }
302 
303  Assert& msg ( const char* strMsg)
304  {
305  M_context.setLevelMsg ( strMsg);
306  return *this;
307  }
308 
309  Assert& level ( int nLevel, const char* strMsg = 0)
310  {
311  M_context.setLevel ( nLevel);
312  M_context.setLevelMsg ( strMsg);
313  return *this;
314  }
315 
316  Assert& warn ( const char* strMsg = 0)
317  {
318  return level ( lvl_warn, strMsg);
319  }
320 
321  Assert& debug ( const char* strMsg = 0)
322  {
323  return level ( lvl_debug, strMsg);
324  }
325 
326  Assert& error ( const char* strMsg = 0)
327  {
328  return level ( lvl_error, strMsg);
329  }
330 
331  Assert& error ( const std::string strMsg )
332  {
333  return level ( lvl_error, strMsg.c_str() );
334  }
335 
336  Assert& fatal ( const char* strMsg = 0)
337  {
338  return level ( lvl_fatal, strMsg);
339  }
340  //@}
341 
342  //! @name Static methods
343  //@{
344  // in this case, we set the default logger, and make it
345  // write everything to this file
346  static void setLog ( const char* strFileName)
347  {
348  Private::setDefaultLogName ( strFileName);
350  }
351 
352  // in this case, we set the default logger, and make it
353  // write everything to this log
354  static void setLog ( std::ostream& out)
355  {
358  }
359 
360  static void setLog ( assertFunction_Type log)
361  {
362  logger() = log;
363  }
364 
365  static void setHandler ( int nLevel, assertFunction_Type handler)
366  {
367  handlers() [ nLevel] = handler;
368  }
369  //@}
370 
371 private:
372  //! @name Private methods
373  //@{
374  // handles the current assertion.
376  {
379  }
380 
381  /*
382  IMPORTANT NOTE:
383  The only reason logger & handlers are functions, are
384  because you might use SMART_ASSERT before main().
385 
386  In this case, since they're statics, they might not
387  be initialized. However, making them functions
388  will make it work.
389  */
390  //@}
391 
392  //! @name Private static methods
393  //@{
394  // the log
395  static assertFunction_Type& logger()
396  {
397  static assertFunction_Type inst;
398  return inst;
399  }
400 
401  // the handler
404  {
405  static handlerCollection_Type inst;
406  return inst;
407  }
408 
409  static assertFunction_Type handler ( int nLevel)
410  {
411  handlerCollection_Type::const_iterator found = handlers().find ( nLevel);
412  if ( found != handlers().end() )
413  {
414  return found->second;
415  }
416  else
417  // we always assume the debug handler has been set
418  {
419  return handlers().find ( lvl_debug)->second;
420  }
421  }
422  //@}
423 
424 private:
426  mutable bool M_needsHandling;
427 };
428 
429 namespace SmartAssert
430 {
431 inline ::LifeV::Assert makeAssert ( const char* expr)
432 {
433  return ::LifeV::Assert ( expr);
434 }
435 } // namespace SmartAssert
436 
437 } // LifeV Namespace
438 
439 #ifdef LIFEV_SMART_ASSERT_DEBUG_MODE
440 
441 #if LIFEV_SMART_ASSERT_DEBUG_MODE == 1
442 #define LIFEV_SMART_ASSERT_DEBUG
443 #else
444 #undef LIFEV_SMART_ASSERT_DEBUG
445 #endif
446 
447 #else
448 
449 // defaults
450 #ifdef HAVE_LIFEV_DEBUG
451 #define LIFEV_SMART_ASSERT_DEBUG
452 #else
453 #undef LIFEV_SMART_ASSERT_DEBUG
454 #endif
455 
456 #endif
457 
458 
459 #ifdef LIFEV_SMART_ASSERT_DEBUG
460 // "debug" mode
461 #define LIFEV_SMART_ASSERT( expr)
462  if ( (expr) ) ;
463  else ::LifeV::SmartAssert::makeAssert( #expr).printContext( __FILE__, __LINE__).SMART_ASSERT_A
464  /**/
465 
466 #else
467 // "release" mode
468 #define LIFEV_SMART_ASSERT( expr)
469  if ( true ) ;
470  else ::LifeV::SmartAssert::makeAssert( "").SMART_ASSERT_A
471  /**/
472 
473 #endif // ifdef LIFEV_SMART_ASSERT_DEBUG
474 
475 // LIFEV_ASSERT is a equivalent to LIFEV_SMART_ASSERT
476 #define LIFEV_ASSERT( expr) LIFEV_SMART_ASSERT(expr)
477 
478 
479 #define LIFEV_SMART_VERIFY( expr)
480  if ( (expr) ) ;
481  else ::LifeV::SmartAssert::makeAssert( #expr).error().printContext( __FILE__, __LINE__).SMART_ASSERT_A
482  /**/
483 #define LIFEV_VERIFY( expr) LIFEV_SMART_VERIFY(expr)
484 
485 
486 #define SMART_ASSERT_A(x) LIFEV_SMART_ASSERT_OP(x, B)
487 #define SMART_ASSERT_B(x) LIFEV_SMART_ASSERT_OP(x, A)
488 
489 #define LIFEV_SMART_ASSERT_OP(x, next)
490  SMART_ASSERT_A.printCurrentValue((x), #x).SMART_ASSERT_ ## next
491  /**/
492 
493 #endif // SMART_ASSERT_H
const int & level() const
void setFileLine(const char *file, int line)
static void setLog(assertFunction_Type log)
void setDefaultLogName(const char *str)
static handlerCollection_Type & handlers()
void defaultFatalHandler(const AssertContext &context)
void defaultLogger(const AssertContext &context)
Assert & fatal(const char *strMsg=0)
Assert & warn(const char *strMsg=0)
Assert & printContext(const char *file, int line)
static assertFunction_Type handler(int nLevel)
Assert & debug(const char *strMsg=0)
#define LIFEV_SMART_ASSERT_OP(x, next)
valueArray_Type M_values
static void setLog(std::ostream &out)
inline ::LifeV::Assert makeAssert(const char *expr)
Assert & level(int nLevel, const char *strMsg=0)
std::pair< std::string, std::string > valueAndString_Type
#define LIFEV_SMART_VERIFY(expr)
static assertFunction_Type & logger()
void setLevel(int nLevel)
void dumpContextSummary(const AssertContext &context, std::ostream &out)
void updateInverseJacobian(const UInt &iQuadPt)
void setLevelMsg(const char *strMsg)
void defaultWarnHandler(const AssertContext &context)
void defaultDebugHandler(const AssertContext &context)
const std::string & file() const
const valueArray_Type & values() const
Assert & SMART_ASSERT_B
Assert & error(const std::string strMsg)
static void setHandler(int nLevel, assertFunction_Type handler)
Assert & msg(const char *strMsg)
const std::string & expression() const
contains details about a failed assertion
void setExpression(const std::string &str)
void setDefaultLogStream(std::ostream &out)
void(* assertFunction_Type)(const AssertContext &context)
std::vector< valueAndString_Type > valueArray_Type
void defaultErrorHandler(const AssertContext &context)
static void setLog(const char *strFileName)
Assert & printCurrentValue(const type &val, const char *msg)
void dumpContextDetail(const AssertContext &context, std::ostream &out)
const std::string & message() const
Assert & error(const char *strMsg=0)
void addValue(const std::string &val, const std::string &str)
Assert(const char *expr)
Assert(const Assert &other)
Assert & SMART_ASSERT_A
#define SMART_ASSERT_A(x)
std::map< int, assertFunction_Type > handlerCollection_Type
std::string getTypeofLevel(int nLevel)
#define LIFEV_SMART_ASSERT(expr)
AssertContext M_context