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