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