1 /** 2 * @file ctexceptions.h 3 * Definitions for the classes that are 4 * thrown when %Cantera experiences an error condition 5 * (also contains errorhandling module text - see \ref errorhandling). 6 */ 7 8 // This file is part of Cantera. See License.txt in the top-level directory or 9 // at https://cantera.org/license.txt for license and copyright information. 10 11 #ifndef CT_CTEXCEPTIONS_H 12 #define CT_CTEXCEPTIONS_H 13 14 #include "cantera/base/fmt.h" 15 #include <exception> 16 17 namespace Cantera 18 { 19 20 /*! 21 * @defgroup errorhandling Error Handling 22 * 23 * \brief These classes and related functions are used to handle errors and 24 * unknown events within Cantera. 25 * 26 * The general idea is that exceptions are thrown using the common base class 27 * called CanteraError. Derived types of CanteraError characterize what type of 28 * error is thrown. A list of all of the thrown errors is kept in the 29 * Application class. 30 * 31 * Any exceptions which are not caught cause a fatal error exit from the 32 * program. 33 * 34 * A group of defines may be used during debugging to assert conditions which 35 * should be true. These are named AssertTrace(), AssertThrow(), and 36 * AssertThrowMsg(). Examples of their usage is given below. 37 * 38 * @code 39 * AssertTrace(p == OneAtm); 40 * AssertThrow(p == OneAtm, "Kinetics::update"); 41 * AssertThrowMsg(p == OneAtm, "Kinetics::update", 42 * "Algorithm limited to atmospheric pressure"); 43 * @endcode 44 * 45 * Their first argument is a boolean. If the boolean is not true, a CanteraError 46 * is thrown, with descriptive information indicating where the error occurred. 47 * The Assert* checks are skipped if the NDEBUG preprocessor symbol is defined, 48 * e.g. with the compiler option -DNDEBUG. 49 */ 50 51 52 //! Base class for exceptions thrown by Cantera classes. 53 /*! 54 * This class is the base class for exceptions thrown by Cantera. It inherits 55 * from std::exception so that normal error handling operations from 56 * applications may automatically handle the errors in their own way. 57 * 58 * @ingroup errorhandling 59 */ 60 class CanteraError : public std::exception 61 { 62 public: 63 //! Normal Constructor for the CanteraError base class 64 /*! 65 * @param procedure Name of the function within which the error was 66 * generated. For member functions, this should be written as 67 * `ClassName::functionName`. For constructors, this should be 68 * `ClassName::ClassName`. Arguments can be specified to 69 * disambiguate overloaded functions, e.g. 70 * `ClassName::functionName(int, int)`. 71 * @param msg Descriptive string describing the type of error message. This 72 * can be a fmt-style format string (i.e. using curly braces to indicate 73 * fields), which will be used with additional arguments to generate a 74 * formatted error message 75 * @param args Arguments which will be used to interpolate the format string 76 */ 77 template <typename... Args> CanteraError(const std::string & procedure,const std::string & msg,const Args &...args)78 CanteraError(const std::string& procedure, const std::string& msg, 79 const Args&... args) 80 : procedure_(procedure) 81 { 82 if (sizeof...(args) == 0) { 83 msg_ = msg; 84 } else { 85 msg_ = fmt::format(msg, args...); 86 } 87 } 88 89 //! Destructor for base class does nothing ~CanteraError()90 virtual ~CanteraError() throw() {}; 91 92 //! Get a description of the error 93 const char* what() const throw(); 94 95 //! Method overridden by derived classes to format the error message 96 virtual std::string getMessage() const; 97 98 //! Method overridden by derived classes to indicate their type getClass()99 virtual std::string getClass() const { 100 return "CanteraError"; 101 } 102 103 protected: 104 //! Protected default constructor discourages throwing errors containing no 105 //! information. CanteraError()106 CanteraError() {}; 107 108 //! Constructor used by derived classes that override getMessage() 109 explicit CanteraError(const std::string& procedure); 110 111 //! The name of the procedure where the exception occurred 112 std::string procedure_; 113 mutable std::string formattedMessage_; //!< Formatted message returned by what() 114 115 private: 116 std::string msg_; //!< Message associated with the exception 117 }; 118 119 120 //! Array size error. 121 /*! 122 * This error is thrown if a supplied length to a vector supplied to Cantera is 123 * too small. 124 * 125 * @ingroup errorhandling 126 */ 127 class ArraySizeError : public CanteraError 128 { 129 public: 130 //! Constructor 131 /*! 132 * The length needed is supplied by the argument, reqd, and the 133 * length supplied is given by the argument sz. 134 * 135 * @param procedure String name for the function within which the error was 136 * generated. 137 * @param sz This is the length supplied to Cantera. 138 * @param reqd This is the required length needed by Cantera 139 */ ArraySizeError(const std::string & procedure,size_t sz,size_t reqd)140 ArraySizeError(const std::string& procedure, size_t sz, size_t reqd) : 141 CanteraError(procedure), sz_(sz), reqd_(reqd) {} 142 143 virtual std::string getMessage() const; getClass()144 virtual std::string getClass() const { 145 return "ArraySizeError"; 146 } 147 148 private: 149 size_t sz_, reqd_; 150 }; 151 152 153 //! An array index is out of range. 154 /*! 155 * @ingroup errorhandling 156 */ 157 class IndexError : public CanteraError 158 { 159 public: 160 //! Constructor 161 /*! 162 * This class indicates an out-of-bounds array index. 163 * 164 * @param func String name for the function within which the error was 165 * generated. 166 * @param arrayName name of the corresponding array 167 * @param m This is the value of the out-of-bounds index. 168 * @param mmax This is the maximum allowed value of the index. The 169 * minimum allowed value is assumed to be 0. 170 */ IndexError(const std::string & func,const std::string & arrayName,size_t m,size_t mmax)171 IndexError(const std::string& func, const std::string& arrayName, size_t m, size_t mmax) : 172 CanteraError(func), arrayName_(arrayName), m_(m), mmax_(mmax) {} 173 ~IndexError()174 virtual ~IndexError() throw() {}; 175 virtual std::string getMessage() const; getClass()176 virtual std::string getClass() const { 177 return "IndexError"; 178 } 179 180 private: 181 std::string arrayName_; 182 size_t m_, mmax_; 183 }; 184 185 //! An error indicating that an unimplemented function has been called 186 class NotImplementedError : public CanteraError 187 { 188 public: 189 //! @param func Name of the unimplemented function, e.g. 190 //! `ClassName::functionName` NotImplementedError(const std::string & func)191 NotImplementedError(const std::string& func) : 192 CanteraError(func, "Not implemented.") {} 193 194 //! Alternative constructor taking same arguments as @see CanteraError 195 template <typename... Args> NotImplementedError(const std::string & func,const std::string & msg,const Args &...args)196 NotImplementedError(const std::string& func, const std::string& msg, 197 const Args&... args) : 198 CanteraError(func, msg, args...) {} 199 getClass()200 virtual std::string getClass() const { 201 return "NotImplementedError"; 202 } 203 }; 204 205 //! Provides a line number 206 #define XSTR_TRACE_LINE(s) STR_TRACE_LINE(s) 207 208 //! Provides a line number 209 #define STR_TRACE_LINE(s) #s 210 211 //! Provides a std::string variable containing the file and line number 212 /*! 213 * This is a std:string containing the file name and the line number 214 */ 215 #define STR_TRACE (std::string(__FILE__) + ":" + XSTR_TRACE_LINE(__LINE__)) 216 217 #ifdef NDEBUG 218 #ifndef AssertTrace 219 # define AssertTrace(expr) ((void) (0)) 220 #endif 221 #ifndef AssertThrow 222 # define AssertThrow(expr, procedure) ((void) (0)) 223 #endif 224 #ifndef AssertThrowMsg 225 # define AssertThrowMsg(expr,procedure, ...) ((void) (0)) 226 #endif 227 #else 228 229 //! Assertion must be true or an error is thrown 230 /*! 231 * Assertion must be true or else a CanteraError is thrown. A diagnostic string 232 * containing the file and line number, indicating where the error occurred is 233 * added to the thrown object. 234 * 235 * @param expr Boolean expression that must be true 236 * 237 * @ingroup errorhandling 238 */ 239 #ifndef AssertTrace 240 # define AssertTrace(expr) ((expr) ? (void) 0 : throw CanteraError(STR_TRACE, std::string("failed assert: ") + #expr)) 241 #endif 242 243 //! Assertion must be true or an error is thrown 244 /*! 245 * Assertion must be true or else a CanteraError is thrown. A diagnostic string 246 * indicating where the error occurred is added to the thrown object. 247 * 248 * @param expr Boolean expression that must be true 249 * @param procedure Character string or std:string expression indicating the 250 * procedure where the assertion failed 251 * @ingroup errorhandling 252 */ 253 #ifndef AssertThrow 254 # define AssertThrow(expr, procedure) ((expr) ? (void) 0 : throw CanteraError(procedure, std::string("failed assert: ") + #expr)) 255 #endif 256 257 //! Assertion must be true or an error is thrown 258 /*! 259 * Assertion must be true or else a CanteraError is thrown. A diagnostic string 260 * indicating where the error occurred is added to the thrown object. 261 * 262 * @param expr Boolean expression that must be true 263 * @param procedure Character string or std:string expression indicating 264 * the procedure where the assertion failed 265 * Additional arguments are passed on to the constructor for CanteraError to 266 * generate a formatted error message. 267 * 268 * @ingroup errorhandling 269 */ 270 #ifndef AssertThrowMsg 271 # define AssertThrowMsg(expr, procedure, ...) ((expr) ? (void) 0 : throw CanteraError(procedure + std::string(":\nfailed assert: \"") + std::string(#expr) + std::string("\""), __VA_ARGS__)) 272 #endif 273 274 #endif 275 276 //! Throw an exception if the specified exception is not a finite number. 277 #ifndef AssertFinite 278 # define AssertFinite(expr, procedure, ...) AssertThrowMsg(expr < BigNumber && expr > -BigNumber, procedure, __VA_ARGS__) 279 #endif 280 281 } 282 283 #endif 284