Refactor for testing interactive selection input
[gromacs.git] / src / gromacs / utility / exceptions.h
blob493ee6bb6052a5b8d13e3de8d4318a24e57193c1
1 /*
2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2011,2012,2013,2014,2015, by the GROMACS development team, led by
5 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6 * and including many others, as listed in the AUTHORS file in the
7 * top-level source directory and at http://www.gromacs.org.
9 * GROMACS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1
12 * of the License, or (at your option) any later version.
14 * GROMACS 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 GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with GROMACS; if not, see
21 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * If you want to redistribute modifications to GROMACS, please
25 * consider that scientific software is very special. Version
26 * control is crucial - bugs must be traceable. We will be happy to
27 * consider code for inclusion in the official distribution, but
28 * derived work must not be called official GROMACS. Details are found
29 * in the README & COPYING files - if they are missing, get the
30 * official version at http://www.gromacs.org.
32 * To help us fund GROMACS development, we humbly ask that you cite
33 * the research papers on the package. Check out http://www.gromacs.org.
35 /*! \file
36 * \brief
37 * Declares common exception classes and macros for fatal error handling.
39 * \author Teemu Murtola <teemu.murtola@gmail.com>
40 * \inpublicapi
41 * \ingroup module_utility
43 #ifndef GMX_UTILITY_EXCEPTIONS_H
44 #define GMX_UTILITY_EXCEPTIONS_H
46 #include <cstdio>
47 #include <cstdlib>
49 #include <exception>
50 #include <string>
51 #include <vector>
53 #include <boost/exception_ptr.hpp>
54 #include <boost/throw_exception.hpp>
55 #include <boost/exception/errinfo_api_function.hpp>
56 #include <boost/exception/errinfo_errno.hpp>
57 #include <boost/exception/exception.hpp>
58 #include <boost/exception/info.hpp>
60 namespace gmx
63 class TextWriter;
65 namespace internal
67 //! Internal container type for storing a list of nested exceptions.
68 typedef std::vector<boost::exception_ptr> NestedExceptionList;
69 } // namespace internal
71 //! \addtogroup module_utility
72 //! \{
74 /*! \brief
75 * Provides information for Gromacs exception constructors.
77 * This class exists to implement common functionality for initializing all
78 * Gromacs exceptions without having extra code in each exception class.
79 * In simple cases, it can be implicitly constructed by passing a simple string
80 * to an exception constructor.
81 * If more complex initialization is necessary, it is possible to explicitly
82 * construct an object of this type and then call other methods to add
83 * information before actually creating the exception object.
85 * \todo
86 * With the exception of the reason string, information added with this class
87 * is not currently accessible through any public API, except for calling
88 * printFatalErrorMessage(), formatExceptionMessageToString() or
89 * formatExceptionMessageToFile(). This is not implemented as there is not yet
90 * need for it, and it is not clear what would be the best alternative for the
91 * access. It should be possible to refactor the internal implementation to
92 * suit the needs of such external access without requiring changes in code
93 * that throws these exceptions.
95 * \ingroup module_utility
97 class ExceptionInitializer
99 public:
100 /*! \brief
101 * Creates an initialized with the given string as the reason.
103 * \param[in] reason Detailed reason for the exception.
104 * \throw std::bad_alloc if out of memory.
106 * This constructor is not explicit to allow constructing exceptions
107 * with a plain string argument given to the constructor without adding
108 * extra code to each exception class.
110 ExceptionInitializer(const char *reason)
111 : reason_(reason)
114 //! \copydoc ExceptionInitializer(const char *)
115 ExceptionInitializer(const std::string &reason)
116 : reason_(reason)
120 /*! \brief
121 * Returns true if addCurrentExceptionAsNested() has been called.
123 * Provided for convenience for cases where exceptions will be added
124 * conditionally, and the caller wants to check whether any excetions
125 * were actually added.
127 bool hasNestedExceptions() const { return !nested_.empty(); }
128 /*! \brief
129 * Adds the currently caught exception as a nested exception.
131 * May be called multiple times; all provided exceptions will be added
132 * in a list of nested exceptions.
134 * Must not be called outside a catch block.
136 void addCurrentExceptionAsNested()
138 nested_.push_back(boost::current_exception());
140 /*! \brief
141 * Adds the specified exception as a nested exception.
143 * May be called multiple times; all provided exceptions will be added
144 * in a list of nested exceptions.
146 * This is equivalent to throwing \p ex and calling
147 * addCurrentExceptionAsNested() in the catch block, but potentially
148 * more efficient.
150 template <class Exception>
151 void addNested(const Exception &ex)
153 nested_.push_back(boost::copy_exception(ex));
156 private:
157 std::string reason_;
158 internal::NestedExceptionList nested_;
160 friend class GromacsException;
163 /*! \brief
164 * Base class for all exception objects in Gromacs.
166 * Although boost recommends using virtual inheritance in exception hiearchies,
167 * it is not used here for two reasons:
168 * -# It is only useful when there is diamond inheritance, and that should
169 * never occur in this exception hierarchy because this class is the only
170 * instance of multiple inheritance (Gromacs programming guidelines prohibit
171 * multiple inheritance from concrete classes, but it is unavoidable here
172 * because of the design of boost::exception).
173 * -# Because the constructor takes an argument, virtual inheritance would
174 * complicate any classes that inherit indirectly from this class.
176 * \inpublicapi
178 class GromacsException : public std::exception, public boost::exception
180 public:
181 /*! \brief
182 * Returns the reason string for the exception.
184 * The return value is the string that was passed to the constructor.
186 virtual const char *what() const throw();
187 /*! \brief
188 * Returns the error code corresponding to the exception type.
190 virtual int errorCode() const = 0;
192 /*! \brief
193 * Adds context information to this exception.
195 * \param[in] context Context string to add.
196 * \throws std::bad_alloc if out of memory.
198 * Typical use is to add additional information higher up in the call
199 * stack using this function in a catch block and the rethrow the
200 * exception.
202 * \todo
203 * The added information is currently not accessible through what(),
204 * nor through any other means except for calling
205 * printFatalErrorMessage(), formatExceptionMessageToString() or
206 * formatExceptionMessageToFile(). See ExceptionInitializer for more
207 * discussion.
209 void prependContext(const std::string &context);
211 protected:
212 /*! \brief
213 * Creates an exception object with the provided initializer/reason.
215 * \param[in] details Initializer for the exception.
216 * \throws std::bad_alloc if out of memory.
218 explicit GromacsException(const ExceptionInitializer &details);
221 /*! \brief
222 * Exception class for file I/O errors.
224 * \inpublicapi
226 class FileIOError : public GromacsException
228 public:
229 /*! \brief
230 * Creates an exception object with the provided initializer/reason.
232 * \param[in] details Initializer for the exception.
233 * \throws std::bad_alloc if out of memory.
235 * It is possible to call this constructor either with an explicit
236 * ExceptionInitializer object (useful for more complex cases), or
237 * a simple string if only a reason string needs to be provided.
239 explicit FileIOError(const ExceptionInitializer &details)
240 : GromacsException(details) {}
242 virtual int errorCode() const;
245 /*! \brief
246 * Exception class for user input errors.
248 * Derived classes should be used to indicate the nature of the error instead
249 * of throwing this class directly.
251 * \inpublicapi
253 class UserInputError : public GromacsException
255 protected:
256 //! \copydoc FileIOError::FileIOError()
257 explicit UserInputError(const ExceptionInitializer &details)
258 : GromacsException(details) {}
261 /*! \brief
262 * Exception class for situations where user input cannot be parsed/understood.
264 * \inpublicapi
266 class InvalidInputError : public UserInputError
268 public:
269 //! \copydoc FileIOError::FileIOError()
270 explicit InvalidInputError(const ExceptionInitializer &details)
271 : UserInputError(details) {}
273 virtual int errorCode() const;
276 /*! \brief
277 * Exception class for situations where user input is inconsistent.
279 * \inpublicapi
281 class InconsistentInputError : public UserInputError
283 public:
284 //! \copydoc FileIOError::FileIOError()
285 explicit InconsistentInputError(const ExceptionInitializer &details)
286 : UserInputError(details) {}
288 virtual int errorCode() const;
291 /*! \brief
292 * Exception class for simulation instabilities.
294 * \inpublicapi
296 class SimulationInstabilityError : public GromacsException
298 public:
299 //! \copydoc FileIOError::FileIOError()
300 explicit SimulationInstabilityError(const ExceptionInitializer &details)
301 : GromacsException(details) {}
303 virtual int errorCode() const;
306 /*! \brief
307 * Exception class for internal errors.
309 * \inpublicapi
311 class InternalError : public GromacsException
313 public:
314 //! \copydoc FileIOError::FileIOError()
315 explicit InternalError(const ExceptionInitializer &details)
316 : GromacsException(details) {}
318 virtual int errorCode() const;
321 /*! \brief
322 * Exception class for incorrect use of an API.
324 * \inpublicapi
326 class APIError : public GromacsException
328 public:
329 //! \copydoc FileIOError::FileIOError()
330 explicit APIError(const ExceptionInitializer &details)
331 : GromacsException(details) {}
333 virtual int errorCode() const;
336 /*! \brief
337 * Exception class for use of an unimplemented feature.
339 * \inpublicapi
341 class NotImplementedError : public APIError
343 public:
344 //! \copydoc FileIOError::FileIOError()
345 explicit NotImplementedError(const ExceptionInitializer &details)
346 : APIError(details) {}
348 virtual int errorCode() const;
352 /*! \brief
353 * Macro for throwing an exception.
355 * \param[in] e Exception object to throw.
357 * Using this macro instead of \c throw directly makes it possible to uniformly
358 * attach information into the exception objects.
359 * \p e should evaluate to an instance of an object derived from
360 * GromacsException.
362 * Basic usage:
363 * \code
364 if (value < 0)
366 GMX_THROW(InconsistentUserInput("Negative values not allowed for value"));
368 \endcode
370 #define GMX_THROW(e) \
371 BOOST_THROW_EXCEPTION((e))
373 /*! \brief
374 * Macro for throwing an exception based on errno.
376 * \param[in] e Exception object to throw.
377 * \param[in] syscall Name of the syscall that returned the error.
378 * \param[in] err errno value returned by the syscall.
380 * This macro provides a convenience interface for throwing an exception to
381 * report an error based on a errno value. In addition to adding the necessary
382 * information to the exception object, the macro also ensures that \p errno is
383 * evaluated before, e.g., the constructor of \p e may call other functions
384 * that could overwrite the errno value.
385 * \p e should evaluate to an instance of an object derived from
386 * GromacsException.
388 * Typical usage (note that gmx::File wraps this particular case):
389 * \code
390 FILE *fp = fopen("filename.txt", "r");
391 if (fp == NULL)
393 GMX_THROW(FileIOError("Could not open file"), "fopen", errno);
395 \endcode
397 #define GMX_THROW_WITH_ERRNO(e, syscall, err) \
398 do { \
399 int stored_errno_ = (err); \
400 GMX_THROW((e) << boost::errinfo_errno(stored_errno_) \
401 << boost::errinfo_api_function(syscall)); \
402 } while (0)
403 //TODO: Add an equivalent macro for Windows GetLastError
405 /*! \brief
406 * Formats a standard fatal error message for reporting an exception.
408 * \param[in] fp %File to format the message to.
409 * \param[in] ex Exception to format.
411 * Does not throw. If memory allocation fails or some other error occurs
412 * while formatting the error, tries to print a reasonable alternative message.
414 * Normal usage in Gromacs command-line programs is like this:
415 * \code
416 int main(int argc, char *argv[])
418 gmx::init(&argc, &argv);
421 // The actual code for the program
422 return 0;
424 catch (const std::exception &ex)
426 gmx::printFatalErrorMessage(stderr, ex);
427 return gmx::processExceptionAtExit(ex);
430 \endcode
432 void printFatalErrorMessage(FILE *fp, const std::exception &ex);
433 /*! \brief
434 * Formats an error message for reporting an exception.
436 * \param[in] ex Exception to format.
437 * \returns Formatted string containing details of \p ex.
438 * \throws std::bad_alloc if out of memory.
440 std::string formatExceptionMessageToString(const std::exception &ex);
441 /*! \brief
442 * Formats an error message for reporting an exception.
444 * \param fp %File to write the message to.
445 * \param[in] ex Exception to format.
446 * \throws std::bad_alloc if out of memory.
448 void formatExceptionMessageToFile(FILE *fp, const std::exception &ex);
449 /*! \brief
450 * Formats an error message for reporting an exception.
452 * \param writer Writer to use for writing the message.
453 * \param[in] ex Exception to format.
454 * \throws std::bad_alloc if out of memory.
456 void formatExceptionMessageToWriter(TextWriter *writer,
457 const std::exception &ex);
458 /*! \brief
459 * Handles an exception that is causing the program to terminate.
461 * \param[in] ex Exception that is the cause for terminating the program.
462 * \returns Return code to return from main().
464 * This method should be called as the last thing before terminating the
465 * program because of an exception. It exists to terminate the program as
466 * gracefully as possible in the case of MPI processing (but the current
467 * implementation always calls MPI_Abort()).
469 * See printFatalErrorMessage() for example usage.
471 * Does not throw.
473 int processExceptionAtExit(const std::exception &ex);
475 /*! \brief
476 * Converts an exception into a return code.
478 int translateException(const std::exception &ex);
480 /*! \brief
481 * Macro for catching exceptions at C++ -> C boundary.
483 * This macro is intended for uniform handling of exceptions when C++ code is
484 * called from C code within Gromacs. Since most existing code is written
485 * using the assumption that fatal errors terminate the program, this macro
486 * implements this behavior for exceptions. It should only be used in cases
487 * where the error cannot be propagated upwards using return values or such.
489 * Having this as a macro instead of having the same code in each place makes
490 * it easy to 1) find all such locations in the code, and 2) change the exact
491 * behavior if needed.
493 * Usage:
494 \code
497 // C++ code
499 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
500 \endcode
502 #define GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR \
503 catch (const std::exception &ex) { \
504 ::gmx::printFatalErrorMessage(stderr, ex); \
505 ::std::exit(::gmx::processExceptionAtExit(ex)); \
508 //! \}
510 } // namespace gmx
512 #endif