Merge release-4-6 into master
[alexxy/gromacs.git] / src / gromacs / utility / exceptions.h
1 /*
2  *
3  *                This source code is part of
4  *
5  *                 G   R   O   M   A   C   S
6  *
7  *          GROningen MAchine for Chemical Simulations
8  *
9  * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
10  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
11  * Copyright (c) 2001-2009, The GROMACS development team,
12  * check out http://www.gromacs.org for more information.
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * If you want to redistribute modifications, please consider that
20  * scientific software is very special. Version control is crucial -
21  * bugs must be traceable. We will be happy to consider code for
22  * inclusion in the official distribution, but derived work must not
23  * be called official GROMACS. Details are found in the README & COPYING
24  * files - if they are missing, get the official version at www.gromacs.org.
25  *
26  * To help us fund GROMACS development, we humbly ask that you cite
27  * the papers on the package - you can find them in the top README file.
28  *
29  * For more info, check our website at http://www.gromacs.org
30  */
31 /*! \file
32  * \brief
33  * Declares common exception classes for fatal error handling.
34  *
35  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
36  * \inpublicapi
37  * \ingroup module_utility
38  */
39 #ifndef GMX_UTILITY_EXCEPTIONS_H
40 #define GMX_UTILITY_EXCEPTIONS_H
41
42 #include <cstdio>
43 #include <cstdlib>
44
45 #include <exception>
46 #include <string>
47 #include <vector>
48
49 #include <boost/exception_ptr.hpp>
50 #include <boost/exception/errinfo_api_function.hpp>
51 #include <boost/exception/errinfo_errno.hpp>
52 #include <boost/exception/exception.hpp>
53 #include <boost/exception/info.hpp>
54 #include <boost/throw_exception.hpp>
55
56 namespace gmx
57 {
58
59 namespace internal
60 {
61 //! Internal container type for storing a list of nested exceptions.
62 typedef std::vector<boost::exception_ptr> NestedExceptionList;
63 } // namespace internal
64
65 /*! \addtopublicapi
66  * \{
67  */
68
69 /*! \brief
70  * Provides information for Gromacs exception constructors.
71  *
72  * This class exists to implement common functionality for initializing all
73  * Gromacs exceptions without having extra code in each exception class.
74  * In simple cases, it can be implicitly constructed by passing a simple string
75  * to an exception constructor.
76  * If more complex initialization is necessary, it is possible to explicitly
77  * construct an object of this type and then call other methods to add
78  * information before actually creating the exception object.
79  *
80  * \todo
81  * With the exception of the reason string, information added with this class
82  * is not currently accessible through any public API, except for calling
83  * printFatalErrorMessage().  This is not implemented as there is no current
84  * need for it, and it is not clear what would be the best alternative for the
85  * access.  It should be possible to refactor the internal implementation to
86  * suit the needs of such external access without requiring changes in code
87  * that throws these exceptions.
88  *
89  * \ingroup module_utility
90  */
91 class ExceptionInitializer
92 {
93     public:
94         /*! \brief
95          * Creates an initialized with the given string as the reason.
96          *
97          * \param[in] reason  Detailed reason for the exception.
98          * \throw     std::bad_alloc if out of memory.
99          *
100          * This constructor is not explicit to allow constructing exceptions
101          * with a plain string argument given to the constructor without adding
102          * extra code to each exception class.
103          */
104         ExceptionInitializer(const char *reason)
105             : reason_(reason)
106         {
107         }
108         //! \copydoc ExceptionInitializer(const char *)
109         ExceptionInitializer(const std::string &reason)
110             : reason_(reason)
111         {
112         }
113
114         /*! \brief
115          * Returns true if addCurrentExceptionAsNested() has been called.
116          *
117          * Provided for convenience for cases where exceptions will be added
118          * conditionally, and the caller wants to check whether any excetions
119          * were actually added.
120          */
121         bool hasNestedExceptions() const { return !nested_.empty(); }
122         /*! \brief
123          * Adds the currently caught exception as a nested exception.
124          *
125          * May be called multiple times; all provided exceptions will be added
126          * in a list of nested exceptions.
127          *
128          * Must not be called outside a catch block.
129          */
130         void addCurrentExceptionAsNested()
131         {
132             nested_.push_back(boost::current_exception());
133         }
134
135     private:
136         std::string                     reason_;
137         internal::NestedExceptionList   nested_;
138
139         friend class GromacsException;
140 };
141
142 /*! \brief
143  * Base class for all exception objects in Gromacs.
144  *
145  * Although boost recommends using virtual inheritance in exception hiearchies,
146  * it is not used here for two reasons:
147  * -# It is only useful when there is diamond inheritance, and that should
148  *    never occur in this exception hierarchy because this class is the only
149  *    instance of multiple inheritance (Gromacs programming guidelines prohibit
150  *    multiple inheritance from concrete classes, but it is unavoidable here
151  *    because of the design of boost::exception).
152  * -# Because the constructor takes an argument, virtual inheritance would
153  *    complicate any classes that inherit indirectly from this class.
154  *
155  * \ingroup module_utility
156  */
157 class GromacsException : public std::exception, public boost::exception
158 {
159     public:
160         /*! \brief
161          * Returns the reason string for the exception.
162          *
163          * The return value is the string that was passed to the constructor.
164          */
165         virtual const char *what() const throw();
166         /*! \brief
167          * Returns the error code corresponding to the exception type.
168          */
169         virtual int errorCode() const = 0;
170
171         /*! \brief
172          * Adds context information to this exception.
173          *
174          * \param[in] context  Context string to add.
175          * \throws    std::bad_alloc if out of memory.
176          *
177          * Typical use is to add additional information higher up in the call
178          * stack using this function in a catch block and the rethrow the
179          * exception.
180          *
181          * \todo
182          * The added information is currently not accessible through what(),
183          * nor through any other means except for calling
184          * printFatalErrorMessage(). See ExceptionInitializer for more
185          * discussion.
186          */
187         void prependContext(const std::string &context);
188
189     protected:
190         /*! \brief
191          * Creates an exception object with the provided initializer/reason.
192          *
193          * \param[in] details  Initializer for the exception.
194          * \throws    std::bad_alloc if out of memory.
195          */
196         explicit GromacsException(const ExceptionInitializer &details);
197 };
198
199 /*! \brief
200  * Exception class for file I/O errors.
201  *
202  * \ingroup module_utility
203  */
204 class FileIOError : public GromacsException
205 {
206     public:
207         /*! \brief
208          * Creates an exception object with the provided initializer/reason.
209          *
210          * \param[in] details  Initializer for the exception.
211          * \throws    std::bad_alloc if out of memory.
212          *
213          * It is possible to call this constructor either with an explicit
214          * ExceptionInitializer object (useful for more complex cases), or
215          * a simple string if only a reason string needs to be provided.
216          */
217         explicit FileIOError(const ExceptionInitializer &details)
218             : GromacsException(details) {}
219
220         virtual int errorCode() const;
221 };
222
223 /*! \brief
224  * Exception class for user input errors.
225  *
226  * Derived classes should be used to indicate the nature of the error instead
227  * of throwing this class directly.
228  *
229  * \ingroup module_utility
230  */
231 class UserInputError : public GromacsException
232 {
233     protected:
234         //! \copydoc FileIOError::FileIOError()
235         explicit UserInputError(const ExceptionInitializer &details)
236             : GromacsException(details) {}
237 };
238
239 /*! \brief
240  * Exception class for situations where user input cannot be parsed/understood.
241  *
242  * \ingroup module_utility
243  */
244 class InvalidInputError : public UserInputError
245 {
246     public:
247         //! \copydoc FileIOError::FileIOError()
248         explicit InvalidInputError(const ExceptionInitializer &details)
249             : UserInputError(details) {}
250
251         virtual int errorCode() const;
252 };
253
254 /*! \brief
255  * Exception class for situations where user input is inconsistent.
256  *
257  * \ingroup module_utility
258  */
259 class InconsistentInputError : public UserInputError
260 {
261     public:
262         //! \copydoc FileIOError::FileIOError()
263         explicit InconsistentInputError(const ExceptionInitializer &details)
264             : UserInputError(details) {}
265
266         virtual int errorCode() const;
267 };
268
269 /*! \brief
270  * Exception class for simulation instabilities.
271  *
272  * \ingroup module_utility
273  */
274 class SimulationInstabilityError : public GromacsException
275 {
276     public:
277         //! \copydoc FileIOError::FileIOError()
278         explicit SimulationInstabilityError(const ExceptionInitializer &details)
279             : GromacsException(details) {}
280
281         virtual int errorCode() const;
282 };
283
284 /*! \brief
285  * Exception class for internal errors.
286  *
287  * \ingroup module_utility
288  */
289 class InternalError : public GromacsException
290 {
291     public:
292         //! \copydoc FileIOError::FileIOError()
293         explicit InternalError(const ExceptionInitializer &details)
294             : GromacsException(details) {}
295
296         virtual int errorCode() const;
297 };
298
299 /*! \brief
300  * Exception class for incorrect use of an API.
301  *
302  * \ingroup module_utility
303  */
304 class APIError : public GromacsException
305 {
306     public:
307         //! \copydoc FileIOError::FileIOError()
308         explicit APIError(const ExceptionInitializer &details)
309             : GromacsException(details) {}
310
311         virtual int errorCode() const;
312 };
313
314 /*! \brief
315  * Exception class for use of an unimplemented feature.
316  *
317  * \ingroup module_utility
318  */
319 class NotImplementedError : public APIError
320 {
321     public:
322         //! \copydoc FileIOError::FileIOError()
323         explicit NotImplementedError(const ExceptionInitializer &details)
324             : APIError(details) {}
325
326         virtual int errorCode() const;
327 };
328
329
330 /*! \brief
331  * Macro for throwing an exception.
332  *
333  * \param[in] e    Exception object to throw.
334  *
335  * Using this macro instead of \c throw directly makes it possible to uniformly
336  * attach information into the exception objects.
337  * \p e should evaluate to an instance of an object derived from
338  * GromacsException.
339  *
340  * Basic usage:
341  * \code
342 if (value < 0)
343 {
344     GMX_THROW(InconsistentUserInput("Negative values not allowed for value"));
345 }
346  * \endcode
347  */
348 #define GMX_THROW(e) \
349     BOOST_THROW_EXCEPTION((e))
350
351 /*! \brief
352  * Macro for throwing an exception based on errno.
353  *
354  * \param[in] e       Exception object to throw.
355  * \param[in] syscall Name of the syscall that returned the error.
356  * \param[in] err     errno value returned by the syscall.
357  *
358  * This macro provides a convenience interface for throwing an exception to
359  * report an error based on a errno value.  In addition to adding the necessary
360  * information to the exception object, the macro also ensures that \p errno is
361  * evaluated before, e.g., the constructor of \p e may call other functions
362  * that could overwrite the errno value.
363  * \p e should evaluate to an instance of an object derived from
364  * GromacsException.
365  *
366  * Typical usage (note that gmx::File wraps this particular case):
367  * \code
368 FILE *fp = fopen("filename.txt", "r");
369 if (fp == NULL)
370 {
371     GMX_THROW(FileIOError("Could not open file"), "fopen", errno);
372 }
373  * \endcode
374  */
375 #define GMX_THROW_WITH_ERRNO(e, syscall, err) \
376     do { \
377         int stored_errno_ = (err); \
378         GMX_THROW((e) << boost::errinfo_errno(stored_errno_) \
379                       << boost::errinfo_api_function(syscall)); \
380     } while(0)
381
382 /*! \brief
383  * Formats a standard fatal error message for reporting an exception.
384  *
385  * Does not throw.  If memory allocation fails or some other error occurs
386  * while formatting the error, tries to print a reasonable alternative message.
387  *
388  * Normal usage in Gromacs command-line programs is like this:
389  * \code
390 int main(int argc, char *argv[])
391 {
392     gmx::ProgramInfo::init(argc, argv);
393     try
394     {
395         // The actual code for the program
396         return 0;
397     }
398     catch (const std::exception &ex)
399     {
400         gmx::printFatalErrorMessage(stderr, ex);
401         return 1;
402     }
403 }
404  * \endcode
405  */
406 void printFatalErrorMessage(FILE *fp, const std::exception &ex);
407
408 /*! \brief
409  * Converts an exception into a return code.
410  */
411 int translateException(const std::exception &ex);
412
413 /*!\}*/
414
415 /*! \cond libapi */
416 /*! \libinternal \brief
417  * Macro for catching exceptions at C++ -> C boundary.
418  *
419  * This macro is intended for uniform handling of exceptions when C++ code is
420  * called from C code within Gromacs.  Since most existing code is written
421  * using the assumption that fatal errors terminate the program, this macro
422  * implements this behavior for exceptions.  It should only be used in cases
423  * where the error cannot be propagated upwards using return values or such.
424  *
425  * Having this as a macro instead of having the same code in each place makes
426  * it easy to 1) find all such locations in the code, and 2) change the exact
427  * behavior if needed.
428  *
429  * Usage:
430  * \code
431 try
432 {
433     // C++ code
434 }
435 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
436  * \endcode
437  *
438  * \inlibraryapi
439  */
440 #define GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR \
441     catch (const std::exception &ex) { \
442         ::gmx::printFatalErrorMessage(stderr, ex); \
443         std::exit(1); \
444     }
445 //! \endcond
446
447 } // namespace gmx
448
449 #endif