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