From 76eff849e0f81be41c0f6e2b41630c317739ec24 Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Mon, 9 Mar 1998 16:37:25 +0000 Subject: [PATCH] Exception-handling scheme git-svn-id: https://svn.dealii.org/trunk@46 0785d39b-7218-0410-832d-ea1e28bc413d --- deal.II/base/include/base/exceptions.h | 405 +++++++++++++++++++++++++ 1 file changed, 405 insertions(+) create mode 100644 deal.II/base/include/base/exceptions.h diff --git a/deal.II/base/include/base/exceptions.h b/deal.II/base/include/base/exceptions.h new file mode 100644 index 0000000000..d59a48796e --- /dev/null +++ b/deal.II/base/include/base/exceptions.h @@ -0,0 +1,405 @@ +/*---------------------------- exceptions.h ---------------------------*/ +/* $Id$ */ +#ifndef __exceptions_H +#define __exceptions_H +/*---------------------------- exceptions.h ---------------------------*/ + + +#include + + + +#ifndef __GNUC__ +# define __PRETTY_FUNCTION__ "(unknown)" +#endif + + /** + * This class should be used as a base class for + * all exception classes. Do not use its methods + * and variables directly since the interface + * and mechanism may be subject to change. Rather + * create new exception classes using the + * #DeclException# macro family. + * + * @see Assert + * @see DeclException0 + * @author Wolfgang Bangerth, November 1997 + */ +class ExceptionBase { + public: + ExceptionBase () {}; + /** + * The constructor takes the file in which the + * error happened, the line and the violated + * condition as well as the name of the + * exception class as a #char*# as arguments. + */ + ExceptionBase (const char* f, const int l, const char *func, + const char* c, const char *e) : + file(f), line(l), function(func), cond(c), exc(e) {}; + + /** + * Set the file name and line of where the + * exception appeared as well as the violated + * condition and the name of the exception as + * a char pointer. + */ + void SetFields (const char* f, + const int l, + const char *func, + const char *c, + const char *e) { + file = f; + line = l; + function = func; + cond = c; + exc = e; + }; + /** + * Print out the general part of the error + * information. + */ + void PrintExcData (ostream &out) const { + out << "An error occurred in line <" << line + << "> of file <" << file + << "> in function" << endl + << " " << function << endl + << "The violated condition was: "<< endl + << " " << cond << endl + << "The name and call sequence of the exception was:" << endl + << " " << exc << endl + << "Additional Information: " << endl; + }; + + /** + * Print more specific information about the + * exception which occured. Overload this + * function in your own exception classes. + * Since we use templates rather than derivation + * information, we need not declare this + * function as #virtual# and thus avoid problems + * with virtual functions in classes in which + * all functions are declared inline. + */ + void PrintInfo (ostream &out) const { + out << "(none)" << endl; + }; + + + const char *file; + int line; + const char *function; + const char *cond; + const char *exc; +}; + + + /** + * This routine does the main work for the + * exception generation mechanism. + * + * @see Assert + */ +template +void __IssueError (const char *file, + int line, + const char *function, + const char *cond, + const char *exc, + exc e) { + // Fill the fields of the exception object + e.SetFields (file, line, function, cond, exc); + cerr << "--------------------------------------------------------" + << endl; + // print out general data + e.PrintExcData (cerr); + // print out exception specific data + e.PrintInfo (cerr); + cerr << "--------------------------------------------------------" + << endl; + + abort (); + }; + + + +#ifdef DEBUG //////////////////////////////////////// + +/** + This is the main routine in the exception mechanism. + Use it in the following way: declare an exception + class using the #DeclException# macros (see there), + for example + \begin{verbatim} + DeclException2 (ExcDomain, int, int, + << "Index= " << arg1 << "Upper Bound= " << arg2); + \end{verbatim} + to declare an exception class named #ExcDomain#, which + has two variables as additional information (named + #arg1# and #arg2# by default) and which outputs the + given sequence (which is appended to an #ostream# + variable's name, thus the weird syntax). There are + other #DeclExceptionN# macros for exception classes + with more or no parameters. It is proposed to let start + the name of all exceptions by #Exc...#. + + In your source code write lines like + \begin{verbatim} + Assert (nm, ExcSomewhat());# + + {\bf How it works internally:} + The call #Assert (cond, exc);# + is converted by the preprocessor into the sequence + \begin{verbatim} + if (!(cond)) + __IssueError (__FILE__, + __LINE__, + __PRETTY_FUNCTION__, + #cond, + #exc, + &exc); + \end{verbatim} + i.e. if the given condition is violated, then the file and + line in which the exception occured as well as + the condition itself and the call sequence of the + exception object is transferred. Additionally an object + of the form given by #exc# is created (this is normally an + unnamed object like in #ExcDomain (n, dim)# of class + #ExcDomain#) and transferred to the #__IssueError# + function. + + #__PRETTY__FUNCTION__# is a macro defined only by the GNU CC + compiler and gives the name of the function. If another compiler + is used, we set #__PRETTY_FUNCTION__ = "(unknown)"#. + + In #__IssueError# the given data + is transferred into the #exc# object by calling the + #SetFields# function; after that, the general error info + is printed onto #cerr# using the #PrintError# function of + #exc# and finally the exception specific data is printed + using the user defined function #PrintError# (which is + normally created using the #DeclException (...)# macro + family. + + After printing all this information, #abort()# is called. + This may in future versions be replaced by calling + #throw exc;#. + + If the preprocessor variable #DEBUG# is not set, then nothing + happens, i.e. the macro is expanded to #(void) 0;#. + + @memo Assert that a certain condition is fulfilled, otherwise + issue an error and abort the program. + + @see DeclException0 + @author Wolfgang Bangerth, November 1997 + */ +#define Assert(cond, exc) \ + if (!(cond)) \ + __IssueError (__FILE__, \ + __LINE__, \ + __PRETTY_FUNCTION__, #cond, #exc, exc) + + +#else //////////////////////////////////////// + +#define Assert(cond, exc) \ + (void) 0 +#endif //////////////////////////////////////// + + + +/** + Declare an exception class without any additional parameters. + There is a whole family of #DeclException?# macros + where #?# is to be replaced by the number of additional + parameters (0 to 5 presently). + + The syntax is as follows: + \begin{verbatim} + DeclException2 (ExcDomain, + int, + int, + << " i=" << arg1 << ", m=" << arg2); + \end{verbatim} + The first is the name of the exception class to be created. + The next arguments are the types of the parameters (in this + case there are two type names needed) and finally the output + sequence with which you can print additional information. + + The syntax of the output sequence is a bit weird but gets + clear once you see how this macro is defined: + \begin{verbatim} + class name : public ExceptionBase { + public: + name (const type1 a1, const type2 a2) : + arg1 (a1), arg2(a2) {}; + void PrintInfo (ostream &out) const { + out outsequence << endl; + }; + private: + type1 arg1; + type2 arg2; + }; + \end{verbatim} + The #PrintInfo# function is not declared #virtual# since we would + then create a class with virtual functions and only inlined code. + For this kind of class at least GNU C++ does not know where to put + the virtual method table and the program will not be compiled. + + If declared as specified, you can later use this exception class + in the following manner: + \begin{verbatim} + int i=5; + int m=3; + Assert (i of file . + The violated condition was: + i