Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2012-2019 The plumed team
3 : (see the PEOPLE file at the root of the distribution for a list of names)
4 :
5 : See http://www.plumed.org for more information.
6 :
7 : This file is part of plumed, version 2.
8 :
9 : plumed is free software: you can redistribute it and/or modify
10 : it under the terms of the GNU Lesser General Public License as published by
11 : the Free Software Foundation, either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : plumed is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU Lesser General Public License for more details.
18 :
19 : You should have received a copy of the GNU Lesser General Public License
20 : along with plumed. If not, see <http://www.gnu.org/licenses/>.
21 : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
22 : #ifndef __PLUMED_tools_Exception_h
23 : #define __PLUMED_tools_Exception_h
24 :
25 : #include <string>
26 : #include <stdexcept>
27 :
28 : namespace PLMD {
29 :
30 : /**
31 : \ingroup TOOLBOX
32 : Class to deal with Plumed runtime errors.
33 :
34 : This class, or better the related macros, can be used to detect programming
35 : errors. Typical cases are internal inconsistencies or errors in the plumed<->MD
36 : interface. Mistakes made by final users (i.e. in the plumed.dat file)
37 : should be documented in some better way (e.g. printing parts of the manual in the output).
38 :
39 : To throw an error, just throw a c++ exception
40 : \verbatim
41 : if(something_bad) throw Exception();
42 : \endverbatim
43 : or better add an error message to that
44 : \verbatim
45 : if(something_bad) throw Exception("describe the error here);
46 : \endverbatim
47 :
48 : Even better, you can use the predefined macros
49 : plumed_error(), plumed_assert(), plumed_merror() and plumed_massert(),
50 : which add information about the exact location of the error in the file (filename, line
51 : and, for g++, function name). Macros ending in "error" unconditionally throw
52 : the exception, whereas macros ending in "assert" first perform a conditional check
53 : (similarly to standard assert()). The extra "m" in the name means that an
54 : extensive error message can be added.
55 : \verbatim
56 : // examples:
57 : plumed_assert(a>0);
58 : plumed_massert(a>0,"a should be larger than zero");
59 : if(a<=0) plumed_error();
60 : if(a<=0) plumed_merror("a should be larger than zero");
61 : \endverbatim
62 : The additional macros
63 : plumed_dbg_assert() and plumed_dbg_massert() are similar
64 : to plumed_assert() and plumed_massert() respectively, but the corresponding
65 : check is only performed when NDEBUG macro is not defined. They should
66 : be used when the check is expensive and should be skipped in production
67 : code.
68 :
69 : By default, execution is terminated imediately and a message is printed on stderr.
70 :
71 : If PLUMED is compiled with -D__PLUMED_EXCEPTIONS execution will continue
72 : and the exception will be passed to c++, so that it will be possible
73 : to intercepted it at a higher level, even outside plumed.
74 : E.g., in an external c++ code using PLUMED as a library, one can type
75 : \verbatim
76 : try{
77 : plumed.cmd("setPrecision",n);
78 : } catch (std::exception & e) {
79 : printf("ee %s",e.what());
80 : exit(1);
81 : }
82 : \endverbatim
83 : This can be useful if an external code wants to exit in a controlled manner
84 : (e.g. flushing files, printing the error message in a specific file, etc.)
85 : but is anyway limited to c++ codes. Moreover,
86 : since these errors are expected to be unrecoverable, the MD code will
87 : usually not be able to do something more clever than exiting.
88 :
89 : \note
90 : In the future we might decide to extend the usage of exceptions to
91 : detect recoverable errors (e.g. optional arguments not found, etc),
92 : even if I am not fully convinced that this is a good idea.
93 : Notice that sometime people claim that code compiled with exception enabled
94 : is slower (GB)
95 : */
96 : class Exception : public std::exception
97 : {
98 : /// Stack trace at exception
99 : std::string stackString;
100 : /// Reported message
101 : std::string msg;
102 : /// Create stack trace
103 : static std::string trace();
104 : /// Common tool, invoked by all the constructor to build the message string
105 : static std::string format(const std::string&,const std::string&,unsigned,const std::string&);
106 : /// Method which aborts in case exceptions are disabled
107 : void abortIfExceptionsAreDisabled();
108 : public:
109 : /// Without message
110 : Exception();
111 : /// With message
112 : explicit Exception(const std::string&);
113 : /// With message plus file, line and function (meant to be used through a preprocessor macro)
114 : Exception(const std::string&,const std::string&,unsigned,const std::string&);
115 : /// Returns the error message.
116 : /// In case the environment variable PLUMED_STACK_TRACE is defined, the error
117 : /// message will contain the stack trace as well.
118 0 : virtual const char* what() const throw() {return msg.c_str();}
119 : /// Returns the stack trace
120 0 : virtual const char* stack() const throw() {return stackString.c_str();}
121 : /// Destructor should be defined and should not throw other exceptions
122 96 : virtual ~Exception() throw() {}
123 : };
124 :
125 : // With GNU compiler, we can use __PRETTY_FUNCTION__ to get the function name
126 : #if !defined(__PRETTY_FUNCTION__)
127 : #define __PRETTY_FUNCTION__ ""
128 : #endif
129 :
130 : /// \relates PLMD::Exception
131 : /// Just print file/line/function information and exit
132 : #define plumed_error() throw PLMD::Exception("",__FILE__,__LINE__,__PRETTY_FUNCTION__)
133 : /// \relates PLMD::Exception
134 : /// Print file/line/function information plus msg and exit
135 : #define plumed_merror(msg) throw PLMD::Exception(msg,__FILE__,__LINE__,__PRETTY_FUNCTION__)
136 : /// \relates PLMD::Exception
137 : /// Conditionally print file/line/function information and exit
138 : #define plumed_assert(test) if(!(test)) throw PLMD::Exception("assertion failed " #test,__FILE__,__LINE__,__PRETTY_FUNCTION__)
139 : /// \relates PLMD::Exception
140 : /// Conditionally print file/line/function information plus msg and exit
141 : #define plumed_massert(test,msg) if(!(test)) throw PLMD::Exception("assertion failed " #test ", " msg,__FILE__,__LINE__,__PRETTY_FUNCTION__)
142 :
143 : #ifdef NDEBUG
144 : #define plumed_dbg_assert(test)
145 : #define plumed_dbg_massert(test,msg)
146 : #else
147 : /// \relates PLMD::Exception
148 : /// Conditionally print file/line/function information and exit when NDEBUG flag is not present
149 : #define plumed_dbg_assert(test) if(!(test)) throw PLMD::Exception("assertion failed " #test,__FILE__,__LINE__,__PRETTY_FUNCTION__)
150 : /// \relates PLMD::Exception
151 : /// Conditionally print file/line/function information plus msg and exit when NDEBUG flag is not present
152 : #define plumed_dbg_massert(test,msg) if(!(test)) throw PLMD::Exception("assertion failed " #test ", " msg,__FILE__,__LINE__,__PRETTY_FUNCTION__)
153 : #endif
154 :
155 : }
156 : #endif
|