1 /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2    Copyright (c) 2012-2021 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     explicit Location(const char*file,unsigned line,const char* pretty=nullptr):
file(file)176       file(file),
177       line(line),
178       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     explicit Assertion(const char*assertion=nullptr):
assertion(assertion)188       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.
Exception(const std::string & msg)197   explicit Exception(const std::string & msg):
198     Exception()
199   {
200     *this << msg;
201   }
202 
203 /// Copy constructor.
204 /// Needed to make sure stream is not copied
Exception(const Exception & e)205   Exception(const Exception & e):
206     msg(e.msg),
207     stackString(e.stackString),
208     note(e.note)
209   {
210   }
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.
what()226   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.
stack()230   virtual const char* stack() const noexcept {return stackString.c_str();}
231 
232 /// Destructor should be defined and should not throw other exceptions
~Exception()233   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   Exception& operator<<(const T & x) {
252     stream<<x;
253     (*this)<<stream.str();
254     stream.str("");
255     return *this;
256   }
257 };
258 
259 /// Class representing a generic error
260 class ExceptionError :
261   public Exception {
262 public:
263   using Exception::Exception;
264   template<typename T>
265   ExceptionError& operator<<(const T & x) {
266     *((Exception*) this) <<x;
267     return *this;
268   }
269 };
270 
271 /// Class representing a debug error (can only be thrown when using debug options)
272 class ExceptionDebug :
273   public Exception {
274 public:
275   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
342