Flow123d
exceptions.hh
Go to the documentation of this file.
1 /*
2  * exceptions.hh
3  *
4  * Created on: Apr 10, 2012
5  * Author: jb
6  */
7 
8 
9 #ifndef EXCEPTIONS_HH_
10 #define EXCEPTIONS_HH_
11 
12 
13 #include <boost/exception/all.hpp>
14 #include <iostream>
15 #include <string>
16 
17 
18 
19 /**
20  * @brief Wrapper for throw. Saves the throwing point.
21  *
22  * Macro for throwing with saving place of the throw. Just shortcut for BOOST_THROW_EXCEPTION. Creates boost kind of exception, that may
23  * accept further information through redirection.
24  *
25  * Usage:
26  * @code
27  * THROW( ExcError() << EI_SomeValue(42) );
28  * @endcode
29  *
30  * EI_SomeValue is an @p error_info object for transfer of values form throw point to catch point. See @p EI<Tag,Type> class template.
31  *
32  * @ingroup exceptions
33  */
34 #define THROW(whole_exception_expr) BOOST_THROW_EXCEPTION( whole_exception_expr)
35 
36 
37 namespace internal {
38  class ExcStream;
39 }
40 
41 /**
42  * @brief Base of exceptions used in Flow123d.
43  *
44  * We use boost::exception as parent in order to allow passing
45  * some data through the exception object from the throw point to the catch point.
46  * See DECLARE_EXCEPTION macro for usage.
47  *
48  * When deriving particular exceptions always use virtual inheritance:
49  * @code
50  * struct my_exception : virtual ExceptionBase {};
51  * @endcode
52  *
53  * @ingroup exceptions
54  */
55 class ExceptionBase : public virtual std::exception, public virtual boost::exception
56 {
57 public:
58  /// Default constructor, just calls @p fill_stacktrace().
59  ExceptionBase();
60  /// Copy constructor, performs deep copy of stacktrace.
61  ExceptionBase(const ExceptionBase &other);
62  /// Call GNU backtrace if available, save call stack information into @p stacktrace member.
63  void fill_stacktrace();
64  /// Prints formated stacktrace into given stream @p out.
65  void print_stacktrace(std::ostream &out) const;
66  /**
67  * Purely virtual method, that should be implemented by descendants. Prints specific error message into
68  * stream @p out. In particular you can use macros DECLARE_EXCEPTION or DECLARE_INPUT_EXCEPTION for easy declarations.
69  */
70  virtual void print_info(std::ostringstream &out) const=0;
71  /**
72  * Overloaded method for output the exception message if it is not catched.
73  * Implements composition of complex message including diagnostic informations and stack trace.
74  * Should not be overloded in descendant classes. Use @p print_info instead.
75  */
76  virtual const char * what () const throw ();
77  /// Destructor, possibly free stacktrace.
78  virtual ~ExceptionBase() throw ();
79 
80 private:
81 
82  /// Array of backtrace frames returned by glibc backtrace_symbols.
83  char ** stacktrace;
84 
85  /// Size of stacktrace table - number of frames.
87 };
88 
89 
90 
91 
92 
93 /**
94  * @brief Macro for simple definition of exceptions.
95  *
96  * First parameter, @p ExcName, is name of the exception class to define. Macro expands to
97  * the class derived from @p ExceptionBase and implements virtual method @p print_info
98  * with output given by @p Format, the second parameter of the macro. This method is used
99  * by what() method to produce specific part of the error message.
100  *
101  * You can use error info classes (see @p TYPEDEFERR_INFO) and stream modifiers
102  * @p val, @p qval to output relevant data. Modifier @p val outputs plain value,
103  * modifier @p qval outputs value in quotas.
104  *
105  * Example:
106  * @code
107  * TYPEDEF_ERR_INFO( EI_Dim1Mismatch, int);
108  * TYPEDEF_ERR_INFO( EI_Dim2Mismatch, int);
109  * DECLARE_EXCEPTION( ExcDimensionMismatch,
110  * << "Dimensions dim1=" << EI_Dim1Missmatch::val
111  * << " and dim2=" << EI_Dim2Mismatch::val << " should be same.");
112  * @endcode
113  *
114  * One can also pass whole classes through the exception as long as they are default constructable and copy constructable.
115  *
116  * Example:
117  * @code
118  * class Matrix;
119  * TYPEDEF_ERR_INFO( EI_Matrix, Matrix);
120  * DECLARE_EXCEPTION( ExcWrongMatrixState,
121  * << "Matrix state: " << EI_Matrix::ptr(*this)->state() << "\n"
122  * << "Matrix info: " << EI_Matrix::ref(*this).info() );
123  * @endcode
124  *
125  * The example shows two ways how to call methods of the object of class Matrix passed through the exception. One can either get pointer to the object or
126  * reference. The @p ref method checks that the pointer to the object is not NULL (so that the object was actually passed).
127  * The @p ptr method do not perform the check. However, when using one of these methods you have to guarantee that the @p error_info object
128  * is passed to the exception at every throw point that use that exception. Otherwise you get an error,
129  * meaningful in case of the @p ref method, seg. fault for the @p ptr method.
130  *
131  * Currently implemented mechanism do no support standard stream modifiers, namely "endl". Please, use "\n" instead.
132  *
133  * @ingroup exceptions
134  */
135 #define DECLARE_EXCEPTION( ExcName, Format) \
136 struct ExcName : public virtual ::ExceptionBase { \
137  virtual void print_info(std::ostringstream &out) const { \
138  using namespace internal; \
139  ::internal::ExcStream estream(out, *this); \
140  estream Format ; \
141  out << std::endl; \
142  } \
143  virtual ~ExcName() throw () {} \
144 }
145 
146 /* ExcName const &_exc=*this; */
147 
148 
149 
150 /**
151  * @brief Macro to simplify declaration of error_info types.
152  *
153  * Is used to declare types of data that can be passed through exceptions from the throw point to the catch point, or possibly collect
154  * various data along stack rewinding when an exception is thrown.
155  *
156  * Typical usage:
157  * @code
158  * // declares type EI_ParticularNumber
159  * TYPEDEF_ERR_INFO( EI_ParticularNumber, int);
160  * // declares exception that use it
161  * DECLARE_EXCEPTION(SomeException, << " Particular number: " << EI_ParticularNumber::val );
162  * // ... some code ...
163  *
164  * // here you pass particular number important for
165  * // determination of cause of the exception
166  * THROW( SomeException() << EI_ParticularNumber(10) );
167  *
168  * @endcode
169  *
170  * @ingroup exceptions
171  *
172  */
173 #define TYPEDEF_ERR_INFO(EI_Type, Type) typedef EI< struct EI_Type##_TAG, Type > EI_Type
174 
175 /**
176  * This class should not be used directly but through macro TYPEDEF_ERR_INFO.
177  * It is derived from boost::error_info<tag, type> and similarly as its parent it
178  * is tailored for passing a value of type @p Type from the throw point to
179  * the catch point. Compared to boost::error_info it provides manipulators @p val and @p qval
180  * which can by used in formating exception message to the ExcStream. The first manipulator evaluates
181  * directly to the output of the stored value, while @p qval puts the output into single quotas.
182  *
183  * The static function @p ref can be used when you want to extract and output some particular information
184  * from the passed value. However, if no value is given at throw point this function simply aborts. There is
185  * probably no way how to make the check and still keep flexibility in manipulation with the result of @p ref
186  * function.
187  *
188  * For usage see documentation of @p TYPEDEF_ERR_INFO mecro.
189  */
190 template<class Tag, class Type>
191 class EI : public boost::error_info< Tag, Type > {
192 public:
193  typedef typename boost::error_info< Tag, Type> ErrorInfo;
194 
195  /// Construction from given value, that has to bee passed to the catch point.
196  EI(Type const & value) : ErrorInfo(value) {}
197  /**
198  * Stream manipulator used to output the stored value. We have to use special stream ExcStream, that
199  * has overloaded << operator in order to support manipulators 'val' and 'qval'.
200  */
202  /**
203  * Stream manipulator for output of quoted value.
204  */
206 
207  /**
208  * Returns reference to stored value in given exception object @p e.
209  * Check validity of the value.
210  */
211  static Type const & ref( ExceptionBase const &e);
212 
213  /**
214  * Similar to the previous but returns pointer to the stored value and check nothing.
215  */
216  static Type const * ptr( ExceptionBase const &e);
217 
218 };
219 
220 
221 
222 
223 
224 
225 
226 
227 namespace internal {
228 
229 /*
230  * Helper class template. Together with its redirection operator it either outputs value pointed by pointer given to the constructor or
231  * , if the pointer is null, outputs string 'NO_VALUE'. If the optional parameter quoted is true, the value is printed in single quotation marks.
232  */
233 template <class Type>
235 public:
236  NullOutputEnvelope( const Type * x, bool quoted =false)
237  : x_(x), quoted_(quoted) {}
238  inline bool is_null() const {return x_ == NULL;}
239  inline bool is_quoted() const { return quoted_; }
240  inline const Type & value() const {return (*x_);}
241 private:
242  const Type * x_;
243  bool quoted_;
244 };
245 
246 template<class Type>
247 std::ostream& operator<<
248  (std::ostream& stream, const NullOutputEnvelope<Type> & value)
249 {
250  if (value.is_null()) return (stream << "NO_VALUE");
251  else if (value.is_quoted()) return (stream << "'" << value.value() << "'");
252  else return (stream << value.value() );
253 }
254 
255 
256 /**
257  * Helper stream that knows stream and exception for which we format the message.
258  *
259  * TODO: Make std manipulators work!
260  */
261 
262 class ExcStream : public std::ostream {
263 public:
264  ExcStream(std::ostream & stream,const ExceptionBase &exc) : stream_(stream), exc_(exc) {}
265  std::ostream & stream_;
267 
268  // treat exception manipulators
270  {
271  return pf(*this);
272  }
273 /*
274  // treat other manipulators ( This doesn't work. Why?? )
275  template <class T>
276  ExcStream & operator<<(T & (*pf) (T &) )
277  {
278  pf(stream_);
279  return (*this);
280  }*/
281 };
282 
283 
284 template < class T>
285 ExcStream & operator<<(ExcStream & estream, const T & x)
286 {
287  estream.stream_ << x;
288  return estream;
289 }
290 
291 template < class Tag, class Type, class Func>
292 internal::ExcStream & operator<<(internal::ExcStream & estream, typename EI<Tag, Type>::template lambda<Func> const & lambda_func)
293 {
294  if (EI<Tag,Type>::get_value_ptr()) estream.stream_ << "NO_VALUE";
295  else estream.stream_ << lambda_func.func_(* EI<Tag,Type>::get_value_ptr());
296  return estream;
297 }
298 
299 
300 } // namespace internal
301 
302 
303 
304 /**
305  * Exception thrown in xprintf function.
306  */
307 TYPEDEF_ERR_INFO( EI_XprintfHeader, std::string);
308 TYPEDEF_ERR_INFO( EI_XprintfMessage, std::string);
309 DECLARE_EXCEPTION( ExcXprintfMsg, << EI_XprintfHeader::val << EI_XprintfMessage::val);
310 
311 
312 
313 
314 /***********************************************************************
315  * Implementation of templated method
316  */
317 
318 template <class Tag, class Type>
321  ( ptr(es.exc_), false );
322  return es;
323 }
324 
325 
326 
327 template <class Tag, class Type>
330  ( ptr(es.exc_), true );
331  return es;
332 }
333 
334 
335 template <class Tag, class Type>
336 Type const & EI<Tag, Type>::ref( ExceptionBase const &e)
337  {
338  Type const * val_ptr = boost::get_error_info< ErrorInfo > (e);
339  if (! val_ptr) {
340  // try to printout unfinished ErrStream
341  std::cerr << "------------------------------------------------------------------------------\n";
342  std::cerr << " Fatal Error - dereferencing null pointer when formating an exception message.\n";
343  std::cerr << "------------------------------------------------------------------------------\n";
344  std::cerr << "** Diagnosting Informations **\n";
345  std::cerr << boost::diagnostic_information_what( e );
346  abort();
347  }
348  return *val_ptr;
349  }
350 
351 
352 template <class Tag, class Type>
353 Type const * EI<Tag, Type>::ptr( ExceptionBase const &e)
354  { return boost::get_error_info< ErrorInfo > (e); }
355 
356 
357 /**
358  * Assertion that results in an exception.
359  */
360 /*
361 #ifdef DEBUG_ASSERTS
362 
363 #define ASSERT_THROW( condition, exception ) \
364  (condition) ? : throw
365 
366 #else
367 
368 #define ASSERT_THROW( condition, exception )
369 #endif
370 */
371 
372 
373 
374 
375 /*******************************************************************
376 
377 Myslenky ohledne exceptions, chybovych hlasek a logovani (co dnes zajistuje xprintf
378 
379 1) Nutno oddelit nechybove logovani (vcetne warningu) a chybove zpravy (ty pokud je nekdo neodchyti tak vedou na terminate() )
380 
381 2) Logovani ted neresim.
382 
383 3) Jakakoliv chyba by mela radeji vyvolavat vyjimku (lze odchytit, lze pridavat inforamace behem stack unfolding. )
384  A to vcetne ASSERT.
385 
386 4) Neprijemne je, ze exception musim definovat jako zvlastni tridy, zejmena pokud chci mit nejake specialni formaty chybovych hlasek.
387  ale navrhl jsem makro a navazujici implementacni sablony, ktere by to mely zjednodusit. (inspirovano deal.ii)
388 
389 5) bylo by dobre mit par preddefinovanych vyjimek a preddefinovanych assertions.
390 
391 
392 
393 
394 */
395 
396 #endif /* EXCEPTIONS_HH_ */