Modernize syntax of enable_if and traits to use _t helpers
[gromacs.git] / src / gromacs / utility / exceptions.h
blob053ba3b573595a92c2fb99db570cf1cdfc7f609e
1 /*
2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2011,2012,2013,2014,2015,2016,2018,2019, 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 ~GromacsException() noexcept override {}
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 const char *what() const noexcept override;
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))`.
373 * - Return a copy of the same class it takes in. The compiler needs
374 * this information to throw the correct type of exception. This
375 * would be tedious to achieve with a member function (without a
376 * lot of code duplication). Generally, \c ex will be a temporary,
377 * copied twice and returned by value, which the compiler will
378 * typically elide away (and anyway performance is not important
379 * when throwing). We are not using the typical
380 * return-by-const-reference idiom for this operator so that
381 * tooling can reliably see that we are throwing by value.
382 * - Provide convenient syntax for adding multiple items. A non-member
383 * function that would require nested calls would look ugly for such cases.
385 * The reason for the enable_if is that this way, it does not conflict with
386 * other overloads of `operator<<` for ExceptionInfo objects, in case someone
387 * would like to declare those. But currently we do not have such overloads, so
388 * if the enable_if causes problems with some compilers, it can be removed.
390 template <class Exception, class Tag, class T>
391 inline
392 std::enable_if_t<std::is_base_of<GromacsException, Exception>::value, Exception>
393 operator<<(Exception ex, const ExceptionInfo<Tag, T> &item)
395 ex.setInfo(item);
396 return ex;
399 /*! \brief
400 * Exception class for file I/O errors.
402 * \inpublicapi
404 class FileIOError : public GromacsException
406 public:
407 /*! \brief
408 * Creates an exception object with the provided initializer/reason.
410 * \param[in] details Initializer for the exception.
411 * \throws std::bad_alloc if out of memory.
413 * It is possible to call this constructor either with an explicit
414 * ExceptionInitializer object (useful for more complex cases), or
415 * a simple string if only a reason string needs to be provided.
417 explicit FileIOError(const ExceptionInitializer &details)
418 : GromacsException(details) {}
420 int errorCode() const override;
423 /*! \brief
424 * Exception class for user input errors.
426 * Derived classes should be used to indicate the nature of the error instead
427 * of throwing this class directly.
429 * \inpublicapi
431 class UserInputError : public GromacsException
433 protected:
434 //! \copydoc FileIOError::FileIOError()
435 explicit UserInputError(const ExceptionInitializer &details)
436 : GromacsException(details) {}
439 /*! \brief
440 * Exception class for situations where user input cannot be parsed/understood.
442 * \inpublicapi
444 class InvalidInputError : public UserInputError
446 public:
447 //! \copydoc FileIOError::FileIOError()
448 explicit InvalidInputError(const ExceptionInitializer &details)
449 : UserInputError(details) {}
451 int errorCode() const override;
454 /*! \brief
455 * Exception class for situations where user input is inconsistent.
457 * \inpublicapi
459 class InconsistentInputError : public UserInputError
461 public:
462 //! \copydoc FileIOError::FileIOError()
463 explicit InconsistentInputError(const ExceptionInitializer &details)
464 : UserInputError(details) {}
466 int errorCode() const override;
469 /*! \brief
470 * Exception class when a specified tolerance cannot be achieved.
472 * \inpublicapi
474 class ToleranceError : public GromacsException
476 public:
477 /*! \brief
478 * Creates an exception object with the provided initializer/reason.
480 * \param[in] details Initializer for the exception.
481 * \throws std::bad_alloc if out of memory.
483 * It is possible to call this constructor either with an explicit
484 * ExceptionInitializer object (useful for more complex cases), or
485 * a simple string if only a reason string needs to be provided.
487 explicit ToleranceError(const ExceptionInitializer &details)
488 : GromacsException(details) {}
490 int errorCode() const override;
493 /*! \brief
494 * Exception class for simulation instabilities.
496 * \inpublicapi
498 class SimulationInstabilityError : public GromacsException
500 public:
501 //! \copydoc FileIOError::FileIOError()
502 explicit SimulationInstabilityError(const ExceptionInitializer &details)
503 : GromacsException(details) {}
505 int errorCode() const override;
508 /*! \brief
509 * Exception class for internal errors.
511 * \inpublicapi
513 class InternalError : public GromacsException
515 public:
516 //! \copydoc FileIOError::FileIOError()
517 explicit InternalError(const ExceptionInitializer &details)
518 : GromacsException(details) {}
520 int errorCode() const override;
523 /*! \brief
524 * Exception class for incorrect use of an API.
526 * \inpublicapi
528 class APIError : public GromacsException
530 public:
531 //! \copydoc FileIOError::FileIOError()
532 explicit APIError(const ExceptionInitializer &details)
533 : GromacsException(details) {}
535 int errorCode() const override;
538 /*! \brief
539 * Exception class for out-of-range values or indices
541 * \inpublicapi
543 class RangeError : public GromacsException
545 public:
546 //! \copydoc FileIOError::FileIOError()
547 explicit RangeError(const ExceptionInitializer &details)
548 : GromacsException(details) {}
550 int errorCode() const override;
553 /*! \brief
554 * Exception class for use of an unimplemented feature.
556 * \inpublicapi
558 class NotImplementedError : public APIError
560 public:
561 //! \copydoc FileIOError::FileIOError()
562 explicit NotImplementedError(const ExceptionInitializer &details)
563 : APIError(details) {}
565 int errorCode() const override;
568 /*! \brief Exception class for use when ensuring that MPI ranks to throw
569 * in a coordinated fashion.
571 * Generally all ranks that can throw would need to check for whether
572 * an exception has been caught, communicate whether any rank caught,
573 * then all throw one of these, with either a string that describes
574 * any exception caught on that rank, or a generic string.
576 * \inpublicapi
578 class ParallelConsistencyError : public APIError
580 public:
581 //! \copydoc FileIOError::FileIOError()
582 explicit ParallelConsistencyError(const ExceptionInitializer &details)
583 : APIError(details) {}
585 int errorCode() const override;
588 /*! \brief
589 * Macro for throwing an exception.
591 * \param[in] e Exception object to throw.
593 * Using this macro instead of \c throw directly makes it possible to uniformly
594 * attach information into the exception objects.
595 * \p e should evaluate to an instance of an object derived from
596 * GromacsException.
598 * Basic usage:
599 * \code
600 if (value < 0)
602 GMX_THROW(InconsistentUserInput("Negative values not allowed for value"));
604 \endcode
606 #define GMX_THROW(e) \
607 throw (e) << gmx::ExceptionInfoLocation(gmx::ThrowLocation(GMX_CURRENT_FUNCTION, __FILE__, __LINE__))
609 /*! \brief
610 * Macro for throwing an exception based on errno.
612 * \param[in] e Exception object to throw.
613 * \param[in] syscall Name of the syscall that returned the error.
614 * \param[in] err errno value returned by the syscall.
616 * This macro provides a convenience interface for throwing an exception to
617 * report an error based on a errno value. In addition to adding the necessary
618 * information to the exception object, the macro also ensures that \p errno is
619 * evaluated before, e.g., the constructor of \p e may call other functions
620 * that could overwrite the errno value.
621 * \p e should evaluate to an instance of an object derived from
622 * GromacsException.
624 * Typical usage (note that gmx::File wraps this particular case):
625 * \code
626 FILE *fp = fopen("filename.txt", "r");
627 if (fp == NULL)
629 GMX_THROW(FileIOError("Could not open file"), "fopen", errno);
631 \endcode
633 #define GMX_THROW_WITH_ERRNO(e, syscall, err) \
634 do { \
635 int stored_errno_ = (err); \
636 GMX_THROW((e) << gmx::ExceptionInfoErrno(stored_errno_) \
637 << gmx::ExceptionInfoApiFunction(syscall)); \
638 } while (0)
639 //TODO: Add an equivalent macro for Windows GetLastError
641 /*! \brief
642 * Formats a standard fatal error message for reporting an exception.
644 * \param[in] fp %File to format the message to.
645 * \param[in] ex Exception to format.
647 * Does not throw. If memory allocation fails or some other error occurs
648 * while formatting the error, tries to print a reasonable alternative message.
650 * Normal usage in Gromacs command-line programs is like this:
651 * \code
652 int main(int argc, char *argv[])
654 gmx::init(&argc, &argv);
657 // The actual code for the program
658 return 0;
660 catch (const std::exception &ex)
662 gmx::printFatalErrorMessage(stderr, ex);
663 return gmx::processExceptionAtExit(ex);
666 \endcode
668 void printFatalErrorMessage(FILE *fp, const std::exception &ex);
669 /*! \brief
670 * Formats an error message for reporting an exception.
672 * \param[in] ex Exception to format.
673 * \returns Formatted string containing details of \p ex.
674 * \throws std::bad_alloc if out of memory.
676 std::string formatExceptionMessageToString(const std::exception &ex);
677 /*! \brief
678 * Formats an error message for reporting an exception.
680 * \param fp %File to write the message to.
681 * \param[in] ex Exception to format.
682 * \throws std::bad_alloc if out of memory.
684 void formatExceptionMessageToFile(FILE *fp, const std::exception &ex);
685 /*! \brief
686 * Formats an error message for reporting an exception.
688 * \param writer Writer to use for writing the message.
689 * \param[in] ex Exception to format.
690 * \throws std::bad_alloc if out of memory.
692 void formatExceptionMessageToWriter(TextWriter *writer,
693 const std::exception &ex);
694 /*! \brief
695 * Handles an exception that is causing the program to terminate.
697 * \param[in] ex Exception that is the cause for terminating the program.
698 * \returns Return code to return from main().
700 * This method should be called as the last thing before terminating the
701 * program because of an exception. It exists to terminate the program as
702 * gracefully as possible in the case of MPI processing (but the current
703 * implementation always calls MPI_Abort()).
705 * See printFatalErrorMessage() for example usage.
707 * Does not throw.
709 int processExceptionAtExit(const std::exception &ex);
711 /*! \brief
712 * Helper function for terminating the program on an exception.
714 * \param[in] ex Exception that is the cause for terminating the program.
716 * Does not throw, and does not return.
718 [[noreturn]] void processExceptionAsFatalError(const std::exception &ex);
720 /*! \brief
721 * Macro for catching exceptions at C++ -> C boundary.
723 * This macro is intended for uniform handling of exceptions when C++ code is
724 * called from C code within Gromacs. Since most existing code is written
725 * using the assumption that fatal errors terminate the program, this macro
726 * implements this behavior for exceptions. It should only be used in cases
727 * where the error cannot be propagated upwards using return values or such.
729 * Having this as a macro instead of having the same code in each place makes
730 * it easy to 1) find all such locations in the code, and 2) change the exact
731 * behavior if needed.
733 * Usage:
734 \code
737 // C++ code
739 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
740 \endcode
742 #define GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR \
743 catch (const std::exception &ex) { \
744 ::gmx::processExceptionAsFatalError(ex); \
747 //! \}
749 } // namespace gmx
751 #endif