Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2012-2020 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 : #include <sstream>
28 :
29 : namespace PLMD {
30 :
31 : /**
32 : \ingroup TOOLBOX
33 : Class to deal with Plumed runtime errors.
34 :
35 : This class and the related macros can be used to detect programming
36 : errors. Typical cases are internal inconsistencies or errors in the plumed<->MD
37 : interface. Mistakes made by final users (i.e. in the `plumed.dat` file)
38 : should probably be documented in some better way (e.g. printing parts of the manual in the output).
39 : However, also this class allows for significant information to be attached.
40 : Let's try to make error messages as informative as possible!
41 :
42 : \note This class has been rewritten in PLUMED 2.5. It works in a backward compatible manner,
43 : but is much more flexible. The main novelty is that we can use insertion operators to
44 : add arbitrary messages, as in `plumed_error()<<"check this vector "<<v;`
45 : See below for more details.
46 :
47 : To throw an error, just throw a c++ exception
48 : \verbatim
49 : if(something_bad) throw Exception();
50 : \endverbatim
51 : or better add an error message to that
52 : \verbatim
53 : if(something_bad) throw Exception("describe the error here");
54 : \endverbatim
55 :
56 : As of PLUMED 2.5 you can add multiple messages, they will just be concatenated,
57 : but to do se you should use the insertion operator. Notice that anything that
58 : can be formatted with an insertion operator can go to the exception, even a \ref Vector
59 : \verbatim
60 : Vector v;
61 : if(something_bad) throw Exception()<<"problem with this "<<v;
62 : \endverbatim
63 : In principle you can mix the two syntax (add a message as an argument and insert others with `<<`),
64 : however it is not very clear and should be avoided.
65 : We only allow using arguments in parenthesis in order to keep backward compatibility.
66 :
67 : \par Using macros
68 :
69 : In order to provide more context, especially for debugging, it might be useful to know where the exception
70 : originated from. The macros below add information about the exact location of the error in the file (filename, line
71 : and, when available, function name). Macros ending in "error" unconditionally throw
72 : the exception, whereas macros ending in "assert" first perform a conditional check
73 : (similarly to standard assert()).
74 : An extra `m` in the name (e.g. `plumed_merror`) indicates a macro that provides a message as its argument.
75 : However, as of PLUMED 2.5 we should prefer adding messages using insertion operators.
76 : \verbatim
77 : // this is correct but not recommended. add a message please!
78 : plumed_assert(a>0);
79 :
80 : // this is the old syntax (with argument).
81 : // this syntax is basically available for backward compatibility.
82 : plumed_massert(a>0,"a should be larger than zero);
83 :
84 : // this is the recommended syntax, with insertion operators.
85 : // it allows to easily insert multiple objects
86 : plumed_assert(a>0)<<"a should be larger than zero. a="<<a;
87 :
88 : // same as above, but the test is made explicitly:
89 : if(a<=0) plumed_error();
90 : if(a<=0) plumed_error("a should be larger than zero);
91 : if(a<=0) plumed_error()<<"a should be larger than zero. a="<<a;
92 : \endverbatim
93 :
94 : The additional macros
95 : plumed_dbg_assert() and plumed_dbg_massert() are similar
96 : to plumed_assert() and plumed_massert() respectively, but the corresponding
97 : check is only performed when NDEBUG macro is not defined. They should
98 : be used when the check is expensive and should be skipped in production
99 : code. So, for instance, in the following case:
100 : \verbatim
101 : plumed_dbg_assert(expensive_function(i)>0)<<"message";
102 : \endverbatim
103 : `expensive_function()` is not called in the production code.
104 : Notice that the compiler should be able to completely optimize away the
105 : whole statement including functions used to produce the message as in this example:
106 : \verbatim
107 : plumed_dbg_assert(expensive_function(i)>0)<<"I did this check "<<other_expensive_function(i);
108 : \endverbatim
109 :
110 : Finally, notice that there is another macro available, \ref plumed_here.
111 : In can be used in order to create an exception with information about the
112 : line/file coordinates without trowing it. That is, the two following syntaxes
113 : are equivalent
114 : \verbatim
115 : // First way, all at once
116 : plumed_error()<<"some message";
117 : /////////////////////////////////
118 : // Second way, one step at a time
119 : // Create exception
120 : Exception e;
121 : // Append information about line and file
122 : e<<plumed_here;
123 : // Append some other message
124 : e<<"some message";
125 : // Throw the resulting exception
126 : throw e;
127 : \endverbatim
128 :
129 : Exceptions can be caught within plumed or outside of it.
130 : E.g., in an external c++ code using PLUMED as a library, one can type
131 : \verbatim
132 : try{
133 : plumed.cmd("setPrecision",n);
134 : } catch (std::exception & e) {
135 : printf("ee %s",e.what());
136 : exit(1);
137 : }
138 : \endverbatim
139 : This can be useful if an external code wants to exit in a controlled manner
140 : (e.g. flushing files, printing the error message in a specific file, etc.)
141 : but is anyway limited to c++ codes. Moreover,
142 : since these errors are expected to be unrecoverable, the MD code will
143 : usually not be able to do something more clever than exiting.
144 :
145 : \note
146 : We store message and stack trace in growing strings. This is in
147 : principle not recommended, since copying the exception might fail if
148 : copying the string throw another exception. However, this has been like
149 : this in all previous PLUMED versions. In case it is necessary, we can replace
150 : it later with a fixed size array placed on the stack.
151 :
152 : */
153 : class Exception : public std::exception
154 : {
155 : /// Reported message
156 : std::string msg;
157 : /// Stack trace at exception
158 : std::string stackString;
159 : /// Flag to remembed if we have to write the `+++ message follows +++` string.
160 : /// Needed so that the string appears only at the beginning of the message.
161 : bool note;
162 : /// Stream used to insert objects.
163 : /// It is not copied when the Exception is copied.
164 : std::stringstream stream;
165 :
166 : public:
167 :
168 : /// Auxiliary containing the location of the exception in the file.
169 : /// Typically used from the macros below.
170 : class Location {
171 : public:
172 : const char*file;
173 : const unsigned line;
174 : const char* pretty;
175 48 : explicit Location(const char*file,unsigned line,const char* pretty=nullptr):
176 : file(file),
177 : line(line),
178 48 : pretty(pretty)
179 : {}
180 : };
181 :
182 : /// Auxiliary containing the failed assertion.
183 : /// Typically used from the macros below.
184 : class Assertion {
185 : public:
186 : const char*assertion;
187 11 : explicit Assertion(const char*assertion=nullptr):
188 11 : assertion(assertion)
189 : {}
190 : };
191 :
192 : /// Default constructor with no message.
193 : /// Only records the stack trace.
194 : Exception();
195 :
196 : /// Constructor compatible with PLUMED <=2.4.
197 3 : explicit Exception(const std::string & msg):
198 3 : Exception()
199 : {
200 3 : *this << msg;
201 3 : }
202 :
203 : /// Copy constructor.
204 : /// Needed to make sure stream is not copied
205 30 : Exception(const Exception & e):
206 : msg(e.msg),
207 : stackString(e.stackString),
208 120 : note(e.note)
209 : {
210 30 : }
211 :
212 : /// Assignment.
213 : /// Needed to make sure stream is not copied
214 : Exception & operator=(const Exception & e) {
215 : msg=e.msg;
216 : stackString=e.stackString;
217 : note=e.note;
218 : stream.str("");
219 : return *this;
220 : }
221 :
222 : /// Returns the error message.
223 : /// In case the environment variable PLUMED_STACK_TRACE was defined
224 : /// and equal to `yes` when the exception was raised,
225 : /// the error message will contain the stack trace as well.
226 0 : virtual const char* what() const noexcept {return msg.c_str();}
227 :
228 : /// Returns the stack trace.
229 : /// Stack trace stored only if the required functions were found at configure time.
230 0 : virtual const char* stack() const noexcept {return stackString.c_str();}
231 :
232 : /// Destructor should be defined and should not throw other exceptions
233 62 : virtual ~Exception() noexcept {}
234 :
235 : /// Insert location.
236 : /// Format the location properly.
237 : Exception& operator<<(const Location&);
238 :
239 : /// Insert assertion.
240 : /// Format the assertion properly
241 : Exception& operator<<(const Assertion&);
242 :
243 : /// Insert string.
244 : /// Append this string to the message.
245 : Exception& operator<<(const std::string&);
246 :
247 : /// Insert anything else.
248 : /// This allows to dump also other types (e.g. double, or even Vector).
249 : /// Anything that can be written on a stream can go here.
250 : template<typename T>
251 10 : Exception& operator<<(const T & x) {
252 10 : stream<<x;
253 20 : (*this)<<stream.str();
254 20 : stream.str("");
255 10 : return *this;
256 : }
257 : };
258 :
259 : /// Class representing a generic error
260 144 : class ExceptionError :
261 : public Exception {
262 : public:
263 1 : using Exception::Exception;
264 : template<typename T>
265 : ExceptionError& operator<<(const T & x) {
266 96 : *((Exception*) this) <<x;
267 : return *this;
268 : }
269 : };
270 :
271 : /// Class representing a debug error (can only be thrown when using debug options)
272 1 : class ExceptionDebug :
273 : public Exception {
274 : public:
275 1 : using Exception::Exception;
276 : template<typename T>
277 : ExceptionDebug& operator<<(const T & x) {
278 : *((Exception*) this) <<x;
279 : return *this;
280 : }
281 : };
282 :
283 : #ifdef __GNUG__
284 : // With GNU compiler, we can use __PRETTY_FUNCTION__ to get the function name
285 : #define __PLUMED_FUNCNAME __PRETTY_FUNCTION__
286 : #else
287 : // Otherwise, we use the standard C++11 variable
288 : #define __PLUMED_FUNCNAME __func__
289 : #endif
290 :
291 : /// \relates PLMD::Exception
292 : /// Auxiliary macro that generates a PLMD::Exception::Location object.
293 : /// Might be useful if we want to use derived exceptions that could
294 : /// be thrown using `throw DerivedException()<<plumed_here<<" "<<other stuff"`.
295 : /// It is used in the macros below to throw PLMD::Exception.
296 : #define plumed_here PLMD::Exception::Location(__FILE__,__LINE__,__PLUMED_FUNCNAME)
297 :
298 : /// \relates PLMD::Exception
299 : /// Throw an exception with information about the position in the file.
300 : /// Messages can be inserted with `plumed_error()<<"message"`.
301 : #define plumed_error() throw PLMD::ExceptionError() << plumed_here
302 :
303 : /// \relates PLMD::Exception
304 : /// Throw an exception with information about the position in the file
305 : /// and a message. Mostly available for backward compatibility
306 : #define plumed_merror(msg) plumed_error() << msg
307 :
308 : /// \relates PLMD::Exception
309 : /// Launches plumed_merror only if test evaluates to false.
310 : /// The string describing the test is also reported.
311 : /// Further messages can be inserted with `<<`.
312 : #define plumed_assert(test) if(!(test)) plumed_error() << PLMD::Exception::Assertion(#test)
313 :
314 : /// \relates PLMD::Exception
315 : /// Launches plumed_merror only if test evaluates to false.
316 : /// The string describing the test is also reported, in addition to
317 : /// messages reported in the extra argument. Mostly available for backward compatibility.
318 : #define plumed_massert(test,msg) plumed_assert(test) << msg
319 :
320 : #ifdef NDEBUG
321 :
322 : // These are the versions used when compiling with NDEBUG flag.
323 : // The condition is always true, so that the rest of the statement
324 : // should be optimized away.
325 : #define plumed_dbg_assert(test) plumed_assert(true)
326 : #define plumed_dbg_massert(test,msg) plumed_massert(true,msg)
327 :
328 : #else
329 :
330 : /// \relates PLMD::Exception
331 : /// Same as \ref plumed_assert, but only evaluates the condition if NDEBUG is not defined.
332 : #define plumed_dbg_assert(test) if(!(test)) throw PLMD::ExceptionDebug() << plumed_here << PLMD::Exception::Assertion(#test)
333 :
334 : /// \relates PLMD::Exception
335 : /// Same as \ref plumed_massert, but only evaluates the condition if NDEBUG is not defined.
336 : #define plumed_dbg_massert(test,msg) plumed_dbg_assert(test) << msg
337 :
338 : #endif
339 :
340 : }
341 : #endif
|