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