Merge branch release-2016 into release-2018
[gromacs.git] / src / gromacs / utility / exceptions.h
blobfd66bdb98870ca2fafa92a5fcd9ab49257cd6726
1 /*
2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2011,2012,2013,2014,2015,2016, 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 * The basic approach is the same as in boost::exception for storing additional
40 * context information to exceptions, but since that functionality is a very
41 * small and simple part of boost::exception, the code is duplicated here.
43 * \author Teemu Murtola <teemu.murtola@gmail.com>
44 * \inpublicapi
45 * \ingroup module_utility
47 #ifndef GMX_UTILITY_EXCEPTIONS_H
48 #define GMX_UTILITY_EXCEPTIONS_H
50 #include <cstdio>
51 #include <cstdlib>
53 #include <exception>
54 #include <memory>
55 #include <string>
56 #include <type_traits>
57 #include <typeindex>
58 #include <vector>
60 #include "gromacs/utility/basedefinitions.h"
61 #include "gromacs/utility/classhelpers.h"
62 #include "gromacs/utility/current_function.h"
63 #include "gromacs/utility/gmxassert.h"
65 namespace gmx
68 class TextWriter;
70 namespace internal
72 //! Internal container type for storing a list of nested exceptions.
73 typedef std::vector<std::exception_ptr> NestedExceptionList;
75 /*! \internal
76 * \brief
77 * Base class for ExceptionInfo.
79 * This class only provides a way to store different ExceptionInfo objects in
80 * the same container. Actual access to the ExceptionInfo items is handled by
81 * downcasting, after looking up the correct item based on its type.
83 * \ingroup module_utility
85 class IExceptionInfo
87 public:
88 virtual ~IExceptionInfo();
89 GMX_DEFAULT_CONSTRUCTORS(IExceptionInfo);
92 //! Smart pointer to manage IExceptionInfo ownership.
93 typedef std::unique_ptr<IExceptionInfo> ExceptionInfoPointer;
95 class ExceptionData;
97 } // namespace internal
99 //! \addtogroup module_utility
100 //! \{
102 /*! \brief
103 * Stores additional context information for exceptions.
105 * \tparam Tag Tag type (typically, a forward-declared struct that is not
106 * defined anywhere) that makes all ExceptionInfo types unique, even if
107 * they have the same value type.
108 * \tparam T Type of value this object stores.
109 * Needs to be copy-constructible.
111 * Example of declaring a new info type that stores an integer:
112 * \code
113 typedef ExceptionInfo<struct ExceptionInfoMyInfo_, int> ExceptionInfoMyInfo;
114 \endcode
116 * \inpublicapi
118 template <class Tag, typename T>
119 class ExceptionInfo : public internal::IExceptionInfo
121 public:
122 //! The type of value stored in this object.
123 typedef T value_type;
125 //! Creates an info object from given value.
126 explicit ExceptionInfo(const T &value)
127 : value_(value)
131 //! Returns the stored value.
132 const T &value() const { return value_; }
134 private:
135 T value_;
138 /*! \internal
139 * \brief
140 * Stores the location from which an exception was thrown.
142 struct ThrowLocation
144 //! Creates an object for storing the throw location.
145 ThrowLocation(const char *func, const char *file, int line)
146 : func(func), file(file), line(line)
150 //! Function where the throw occurred.
151 const char *func;
152 //! File where the throw occurred.
153 const char *file;
154 //! Line number where the throw occurred.
155 int line;
158 //! Stores `errno` value that triggered the exception.
159 typedef ExceptionInfo<struct ExceptionInfoErrno_, int>
160 ExceptionInfoErrno;
161 //! Stores the function name that returned the `errno` in ExceptionInfoErrno.
162 typedef ExceptionInfo<struct ExceptionInfoApiFunc_, const char *>
163 ExceptionInfoApiFunction;
164 //! Stores the location where the exception was thrown.
165 typedef ExceptionInfo<struct ExceptionInfoLocation_, ThrowLocation>
166 ExceptionInfoLocation;
168 /*! \brief
169 * Provides information for Gromacs exception constructors.
171 * This class exists to implement common functionality for initializing all
172 * Gromacs exceptions without having extra code in each exception class.
173 * In simple cases, it can be implicitly constructed by passing a simple string
174 * to an exception constructor.
175 * If more complex initialization is necessary, it is possible to explicitly
176 * construct an object of this type and then call other methods to add
177 * information before actually creating the exception object.
179 * \todo
180 * With the exception of the reason string, information added with this class
181 * is not currently accessible through any public API, except for calling
182 * printFatalErrorMessage(), formatExceptionMessageToString() or
183 * formatExceptionMessageToFile(). This is not implemented as there is not yet
184 * need for it, and it is not clear what would be the best alternative for the
185 * access. It should be possible to refactor the internal implementation to
186 * suit the needs of such external access without requiring changes in code
187 * that throws these exceptions.
189 * \ingroup module_utility
191 class ExceptionInitializer
193 public:
194 /*! \brief
195 * Creates an initialized with the given string as the reason.
197 * \param[in] reason Detailed reason for the exception.
198 * \throw std::bad_alloc if out of memory.
200 * This constructor is not explicit to allow constructing exceptions
201 * with a plain string argument given to the constructor without adding
202 * extra code to each exception class.
204 ExceptionInitializer(const char *reason)
205 : reason_(reason)
208 //! \copydoc ExceptionInitializer(const char *)
209 ExceptionInitializer(const std::string &reason)
210 : reason_(reason)
214 /*! \brief
215 * Returns true if addCurrentExceptionAsNested() has been called.
217 * Provided for convenience for cases where exceptions will be added
218 * conditionally, and the caller wants to check whether any excetions
219 * were actually added.
221 bool hasNestedExceptions() const { return !nested_.empty(); }
222 /*! \brief
223 * Adds the currently caught exception as a nested exception.
225 * May be called multiple times; all provided exceptions will be added
226 * in a list of nested exceptions.
228 * Must not be called outside a catch block.
230 void addCurrentExceptionAsNested()
232 nested_.push_back(std::current_exception());
234 /*! \brief
235 * Adds the specified exception as a nested exception.
237 * May be called multiple times; all provided exceptions will be added
238 * in a list of nested exceptions.
240 * This is equivalent to throwing \p ex and calling
241 * addCurrentExceptionAsNested() in the catch block, but potentially
242 * more efficient.
244 template <class Exception>
245 void addNested(const Exception &ex)
247 nested_.push_back(std::make_exception_ptr(ex));
250 private:
251 std::string reason_;
252 internal::NestedExceptionList nested_;
254 friend class GromacsException;
257 /*! \brief
258 * Base class for all exception objects in Gromacs.
260 * \inpublicapi
262 class GromacsException : public std::exception
264 public:
265 // Explicitly declared because some compiler/library combinations warn
266 // about missing noexcept otherwise.
267 virtual ~GromacsException() noexcept {}
269 GMX_DEFAULT_CONSTRUCTORS(GromacsException);
271 /*! \brief
272 * Returns the reason string for the exception.
274 * The return value is the string that was passed to the constructor.
276 virtual const char *what() const noexcept;
277 /*! \brief
278 * Returns the error code corresponding to the exception type.
280 virtual int errorCode() const = 0;
282 /*! \brief
283 * Returns the value associated with given ExceptionInfo.
285 * \tparam InfoType ExceptionInfo type to get the value for.
286 * \returns Value set for `InfoType`, or `nullptr` if such info has not
287 * been set.
289 * Does not throw.
291 template <class InfoType>
292 const typename InfoType::value_type *getInfo() const
294 const internal::IExceptionInfo *item = getInfo(typeid(InfoType));
295 if (item != nullptr)
297 GMX_ASSERT(dynamic_cast<const InfoType *>(item) != nullptr,
298 "Invalid exception info item found");
299 return &static_cast<const InfoType *>(item)->value();
301 return nullptr;
304 /*! \brief
305 * Associates extra information with the exception.
307 * \tparam Tag ExceptionInfo tag type.
308 * \tparam T ExceptionInfo value type.
309 * \param[in] item ExceptionInfo to associate.
310 * \throws std::bad_alloc if out of memory.
311 * \throws unspecified any exception thrown by `T` copy construction.
313 * If an item of this type is already associated, it is overwritten.
315 template <class Tag, typename T>
316 void setInfo(const ExceptionInfo<Tag, T> &item)
318 typedef ExceptionInfo<Tag, T> ItemType;
319 internal::ExceptionInfoPointer itemPtr(new ItemType(item));
320 setInfo(typeid(ItemType), std::move(itemPtr));
323 /*! \brief
324 * Adds context information to this exception.
326 * \param[in] context Context string to add.
327 * \throws std::bad_alloc if out of memory.
329 * Typical use is to add additional information higher up in the call
330 * stack using this function in a catch block and the rethrow the
331 * exception.
333 * \todo
334 * The added information is currently not accessible through what(),
335 * nor through any other means except for calling
336 * printFatalErrorMessage(), formatExceptionMessageToString() or
337 * formatExceptionMessageToFile(). See ExceptionInitializer for more
338 * discussion.
340 void prependContext(const std::string &context);
342 protected:
343 /*! \brief
344 * Creates an exception object with the provided initializer/reason.
346 * \param[in] details Initializer for the exception.
347 * \throws std::bad_alloc if out of memory.
349 explicit GromacsException(const ExceptionInitializer &details);
351 private:
352 const internal::IExceptionInfo *getInfo(const std::type_index &index) const;
353 void setInfo(const std::type_index &index, internal::ExceptionInfoPointer &&item);
355 std::shared_ptr<internal::ExceptionData> data_;
358 /*! \brief
359 * Associates extra information with an exception.
361 * \tparam Exception Exception type (must be derived from GromacsException).
362 * \tparam Tag ExceptionInfo tag.
363 * \tparam T ExceptionInfo value type.
364 * \param[in,out] ex Exception to associate the information to.
365 * \param[in] item Information to associate.
367 * \internal
368 * The association is done with a templated non-member operator of exactly this
369 * form to make the simple syntax of GMX_THROW() possible. To support this,
370 * this operation needs to:
371 * - Allow setting information in a temporary to support
372 * `GMX_THROW(InvalidInputError(ex))`. This is the reason for taking a
373 * const reference and the `const_cast`.
374 * - Return the same reference it takes in, instead of a base class.
375 * The compiler needs this information to throw the correct type of
376 * exception. This would be tedious to achieve with a member function
377 * (without a lot of code duplication).
378 * - Provide convenient syntax for adding multiple items. A non-member
379 * function that would require nested calls would look ugly for such cases.
381 * The reason for the enable_if is that this way, it does not conflict with
382 * other overloads of `operator<<` for ExceptionInfo objects, in case someone
383 * would like to declare those. But currently we do not have such overloads, so
384 * if the enable_if causes problems with some compilers, it can be removed.
386 template <class Exception, class Tag, class T>
387 inline
388 typename std::enable_if<std::is_base_of<GromacsException, Exception>::value, const Exception &>::type
389 operator<<(const Exception &ex, const ExceptionInfo<Tag, T> &item)
391 const_cast<Exception &>(ex).setInfo(item);
392 return ex;
395 /*! \brief
396 * Exception class for file I/O errors.
398 * \inpublicapi
400 class FileIOError : public GromacsException
402 public:
403 /*! \brief
404 * Creates an exception object with the provided initializer/reason.
406 * \param[in] details Initializer for the exception.
407 * \throws std::bad_alloc if out of memory.
409 * It is possible to call this constructor either with an explicit
410 * ExceptionInitializer object (useful for more complex cases), or
411 * a simple string if only a reason string needs to be provided.
413 explicit FileIOError(const ExceptionInitializer &details)
414 : GromacsException(details) {}
416 virtual int errorCode() const;
419 /*! \brief
420 * Exception class for user input errors.
422 * Derived classes should be used to indicate the nature of the error instead
423 * of throwing this class directly.
425 * \inpublicapi
427 class UserInputError : public GromacsException
429 protected:
430 //! \copydoc FileIOError::FileIOError()
431 explicit UserInputError(const ExceptionInitializer &details)
432 : GromacsException(details) {}
435 /*! \brief
436 * Exception class for situations where user input cannot be parsed/understood.
438 * \inpublicapi
440 class InvalidInputError : public UserInputError
442 public:
443 //! \copydoc FileIOError::FileIOError()
444 explicit InvalidInputError(const ExceptionInitializer &details)
445 : UserInputError(details) {}
447 virtual int errorCode() const;
450 /*! \brief
451 * Exception class for situations where user input is inconsistent.
453 * \inpublicapi
455 class InconsistentInputError : public UserInputError
457 public:
458 //! \copydoc FileIOError::FileIOError()
459 explicit InconsistentInputError(const ExceptionInitializer &details)
460 : UserInputError(details) {}
462 virtual int errorCode() const;
465 /*! \brief
466 * Exception class when a specified tolerance cannot be achieved.
468 * \inpublicapi
470 class ToleranceError : public GromacsException
472 public:
473 /*! \brief
474 * Creates an exception object with the provided initializer/reason.
476 * \param[in] details Initializer for the exception.
477 * \throws std::bad_alloc if out of memory.
479 * It is possible to call this constructor either with an explicit
480 * ExceptionInitializer object (useful for more complex cases), or
481 * a simple string if only a reason string needs to be provided.
483 explicit ToleranceError(const ExceptionInitializer &details)
484 : GromacsException(details) {}
486 virtual int errorCode() const;
489 /*! \brief
490 * Exception class for simulation instabilities.
492 * \inpublicapi
494 class SimulationInstabilityError : public GromacsException
496 public:
497 //! \copydoc FileIOError::FileIOError()
498 explicit SimulationInstabilityError(const ExceptionInitializer &details)
499 : GromacsException(details) {}
501 virtual int errorCode() const;
504 /*! \brief
505 * Exception class for internal errors.
507 * \inpublicapi
509 class InternalError : public GromacsException
511 public:
512 //! \copydoc FileIOError::FileIOError()
513 explicit InternalError(const ExceptionInitializer &details)
514 : GromacsException(details) {}
516 virtual int errorCode() const;
519 /*! \brief
520 * Exception class for incorrect use of an API.
522 * \inpublicapi
524 class APIError : public GromacsException
526 public:
527 //! \copydoc FileIOError::FileIOError()
528 explicit APIError(const ExceptionInitializer &details)
529 : GromacsException(details) {}
531 virtual int errorCode() const;
534 /*! \brief
535 * Exception class for out-of-range values or indices
537 * \inpublicapi
539 class RangeError : public GromacsException
541 public:
542 //! \copydoc FileIOError::FileIOError()
543 explicit RangeError(const ExceptionInitializer &details)
544 : GromacsException(details) {}
546 virtual int errorCode() const;
549 /*! \brief
550 * Exception class for use of an unimplemented feature.
552 * \inpublicapi
554 class NotImplementedError : public APIError
556 public:
557 //! \copydoc FileIOError::FileIOError()
558 explicit NotImplementedError(const ExceptionInitializer &details)
559 : APIError(details) {}
561 virtual int errorCode() const;
564 /*! \brief
565 * Macro for throwing an exception.
567 * \param[in] e Exception object to throw.
569 * Using this macro instead of \c throw directly makes it possible to uniformly
570 * attach information into the exception objects.
571 * \p e should evaluate to an instance of an object derived from
572 * GromacsException.
574 * Basic usage:
575 * \code
576 if (value < 0)
578 GMX_THROW(InconsistentUserInput("Negative values not allowed for value"));
580 \endcode
582 #define GMX_THROW(e) \
583 throw (e) << gmx::ExceptionInfoLocation(gmx::ThrowLocation(GMX_CURRENT_FUNCTION, __FILE__, __LINE__))
585 /*! \brief
586 * Macro for throwing an exception based on errno.
588 * \param[in] e Exception object to throw.
589 * \param[in] syscall Name of the syscall that returned the error.
590 * \param[in] err errno value returned by the syscall.
592 * This macro provides a convenience interface for throwing an exception to
593 * report an error based on a errno value. In addition to adding the necessary
594 * information to the exception object, the macro also ensures that \p errno is
595 * evaluated before, e.g., the constructor of \p e may call other functions
596 * that could overwrite the errno value.
597 * \p e should evaluate to an instance of an object derived from
598 * GromacsException.
600 * Typical usage (note that gmx::File wraps this particular case):
601 * \code
602 FILE *fp = fopen("filename.txt", "r");
603 if (fp == NULL)
605 GMX_THROW(FileIOError("Could not open file"), "fopen", errno);
607 \endcode
609 #define GMX_THROW_WITH_ERRNO(e, syscall, err) \
610 do { \
611 int stored_errno_ = (err); \
612 GMX_THROW((e) << gmx::ExceptionInfoErrno(stored_errno_) \
613 << gmx::ExceptionInfoApiFunction(syscall)); \
614 } while (0)
615 //TODO: Add an equivalent macro for Windows GetLastError
617 /*! \brief
618 * Formats a standard fatal error message for reporting an exception.
620 * \param[in] fp %File to format the message to.
621 * \param[in] ex Exception to format.
623 * Does not throw. If memory allocation fails or some other error occurs
624 * while formatting the error, tries to print a reasonable alternative message.
626 * Normal usage in Gromacs command-line programs is like this:
627 * \code
628 int main(int argc, char *argv[])
630 gmx::init(&argc, &argv);
633 // The actual code for the program
634 return 0;
636 catch (const std::exception &ex)
638 gmx::printFatalErrorMessage(stderr, ex);
639 return gmx::processExceptionAtExit(ex);
642 \endcode
644 void printFatalErrorMessage(FILE *fp, const std::exception &ex);
645 /*! \brief
646 * Formats an error message for reporting an exception.
648 * \param[in] ex Exception to format.
649 * \returns Formatted string containing details of \p ex.
650 * \throws std::bad_alloc if out of memory.
652 std::string formatExceptionMessageToString(const std::exception &ex);
653 /*! \brief
654 * Formats an error message for reporting an exception.
656 * \param fp %File to write the message to.
657 * \param[in] ex Exception to format.
658 * \throws std::bad_alloc if out of memory.
660 void formatExceptionMessageToFile(FILE *fp, const std::exception &ex);
661 /*! \brief
662 * Formats an error message for reporting an exception.
664 * \param writer Writer to use for writing the message.
665 * \param[in] ex Exception to format.
666 * \throws std::bad_alloc if out of memory.
668 void formatExceptionMessageToWriter(TextWriter *writer,
669 const std::exception &ex);
670 /*! \brief
671 * Handles an exception that is causing the program to terminate.
673 * \param[in] ex Exception that is the cause for terminating the program.
674 * \returns Return code to return from main().
676 * This method should be called as the last thing before terminating the
677 * program because of an exception. It exists to terminate the program as
678 * gracefully as possible in the case of MPI processing (but the current
679 * implementation always calls MPI_Abort()).
681 * See printFatalErrorMessage() for example usage.
683 * Does not throw.
685 int processExceptionAtExit(const std::exception &ex);
687 /*! \brief
688 * Helper function for terminating the program on an exception.
690 * \param[in] ex Exception that is the cause for terminating the program.
692 * Does not throw, and does not return.
694 gmx_noreturn void processExceptionAsFatalError(const std::exception &ex);
696 /*! \brief
697 * Macro for catching exceptions at C++ -> C boundary.
699 * This macro is intended for uniform handling of exceptions when C++ code is
700 * called from C code within Gromacs. Since most existing code is written
701 * using the assumption that fatal errors terminate the program, this macro
702 * implements this behavior for exceptions. It should only be used in cases
703 * where the error cannot be propagated upwards using return values or such.
705 * Having this as a macro instead of having the same code in each place makes
706 * it easy to 1) find all such locations in the code, and 2) change the exact
707 * behavior if needed.
709 * Usage:
710 \code
713 // C++ code
715 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
716 \endcode
718 #define GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR \
719 catch (const std::exception &ex) { \
720 ::gmx::processExceptionAsFatalError(ex); \
723 //! \}
725 } // namespace gmx
727 #endif