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