Refactor for testing interactive selection input
[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,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.
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 and macros 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/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>
59
60 namespace gmx
61 {
62
63 class TextWriter;
64
65 namespace internal
66 {
67 //! Internal container type for storing a list of nested exceptions.
68 typedef std::vector<boost::exception_ptr> NestedExceptionList;
69 }   // namespace internal
70
71 //! \addtogroup module_utility
72 //! \{
73
74 /*! \brief
75  * Provides information for Gromacs exception constructors.
76  *
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.
84  *
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.
94  *
95  * \ingroup module_utility
96  */
97 class ExceptionInitializer
98 {
99     public:
100         /*! \brief
101          * Creates an initialized with the given string as the reason.
102          *
103          * \param[in] reason  Detailed reason for the exception.
104          * \throw     std::bad_alloc if out of memory.
105          *
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.
109          */
110         ExceptionInitializer(const char *reason)
111             : reason_(reason)
112         {
113         }
114         //! \copydoc ExceptionInitializer(const char *)
115         ExceptionInitializer(const std::string &reason)
116             : reason_(reason)
117         {
118         }
119
120         /*! \brief
121          * Returns true if addCurrentExceptionAsNested() has been called.
122          *
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.
126          */
127         bool hasNestedExceptions() const { return !nested_.empty(); }
128         /*! \brief
129          * Adds the currently caught exception as a nested exception.
130          *
131          * May be called multiple times; all provided exceptions will be added
132          * in a list of nested exceptions.
133          *
134          * Must not be called outside a catch block.
135          */
136         void addCurrentExceptionAsNested()
137         {
138             nested_.push_back(boost::current_exception());
139         }
140         /*! \brief
141          * Adds the specified exception as a nested exception.
142          *
143          * May be called multiple times; all provided exceptions will be added
144          * in a list of nested exceptions.
145          *
146          * This is equivalent to throwing \p ex and calling
147          * addCurrentExceptionAsNested() in the catch block, but potentially
148          * more efficient.
149          */
150         template <class Exception>
151         void addNested(const Exception &ex)
152         {
153             nested_.push_back(boost::copy_exception(ex));
154         }
155
156     private:
157         std::string                     reason_;
158         internal::NestedExceptionList   nested_;
159
160         friend class GromacsException;
161 };
162
163 /*! \brief
164  * Base class for all exception objects in Gromacs.
165  *
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.
175  *
176  * \inpublicapi
177  */
178 class GromacsException : public std::exception, public boost::exception
179 {
180     public:
181         /*! \brief
182          * Returns the reason string for the exception.
183          *
184          * The return value is the string that was passed to the constructor.
185          */
186         virtual const char *what() const throw();
187         /*! \brief
188          * Returns the error code corresponding to the exception type.
189          */
190         virtual int errorCode() const = 0;
191
192         /*! \brief
193          * Adds context information to this exception.
194          *
195          * \param[in] context  Context string to add.
196          * \throws    std::bad_alloc if out of memory.
197          *
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.
201          *
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.
208          */
209         void prependContext(const std::string &context);
210
211     protected:
212         /*! \brief
213          * Creates an exception object with the provided initializer/reason.
214          *
215          * \param[in] details  Initializer for the exception.
216          * \throws    std::bad_alloc if out of memory.
217          */
218         explicit GromacsException(const ExceptionInitializer &details);
219 };
220
221 /*! \brief
222  * Exception class for file I/O errors.
223  *
224  * \inpublicapi
225  */
226 class FileIOError : public GromacsException
227 {
228     public:
229         /*! \brief
230          * Creates an exception object with the provided initializer/reason.
231          *
232          * \param[in] details  Initializer for the exception.
233          * \throws    std::bad_alloc if out of memory.
234          *
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.
238          */
239         explicit FileIOError(const ExceptionInitializer &details)
240             : GromacsException(details) {}
241
242         virtual int errorCode() const;
243 };
244
245 /*! \brief
246  * Exception class for user input errors.
247  *
248  * Derived classes should be used to indicate the nature of the error instead
249  * of throwing this class directly.
250  *
251  * \inpublicapi
252  */
253 class UserInputError : public GromacsException
254 {
255     protected:
256         //! \copydoc FileIOError::FileIOError()
257         explicit UserInputError(const ExceptionInitializer &details)
258             : GromacsException(details) {}
259 };
260
261 /*! \brief
262  * Exception class for situations where user input cannot be parsed/understood.
263  *
264  * \inpublicapi
265  */
266 class InvalidInputError : public UserInputError
267 {
268     public:
269         //! \copydoc FileIOError::FileIOError()
270         explicit InvalidInputError(const ExceptionInitializer &details)
271             : UserInputError(details) {}
272
273         virtual int errorCode() const;
274 };
275
276 /*! \brief
277  * Exception class for situations where user input is inconsistent.
278  *
279  * \inpublicapi
280  */
281 class InconsistentInputError : public UserInputError
282 {
283     public:
284         //! \copydoc FileIOError::FileIOError()
285         explicit InconsistentInputError(const ExceptionInitializer &details)
286             : UserInputError(details) {}
287
288         virtual int errorCode() const;
289 };
290
291 /*! \brief
292  * Exception class for simulation instabilities.
293  *
294  * \inpublicapi
295  */
296 class SimulationInstabilityError : public GromacsException
297 {
298     public:
299         //! \copydoc FileIOError::FileIOError()
300         explicit SimulationInstabilityError(const ExceptionInitializer &details)
301             : GromacsException(details) {}
302
303         virtual int errorCode() const;
304 };
305
306 /*! \brief
307  * Exception class for internal errors.
308  *
309  * \inpublicapi
310  */
311 class InternalError : public GromacsException
312 {
313     public:
314         //! \copydoc FileIOError::FileIOError()
315         explicit InternalError(const ExceptionInitializer &details)
316             : GromacsException(details) {}
317
318         virtual int errorCode() const;
319 };
320
321 /*! \brief
322  * Exception class for incorrect use of an API.
323  *
324  * \inpublicapi
325  */
326 class APIError : public GromacsException
327 {
328     public:
329         //! \copydoc FileIOError::FileIOError()
330         explicit APIError(const ExceptionInitializer &details)
331             : GromacsException(details) {}
332
333         virtual int errorCode() const;
334 };
335
336 /*! \brief
337  * Exception class for use of an unimplemented feature.
338  *
339  * \inpublicapi
340  */
341 class NotImplementedError : public APIError
342 {
343     public:
344         //! \copydoc FileIOError::FileIOError()
345         explicit NotImplementedError(const ExceptionInitializer &details)
346             : APIError(details) {}
347
348         virtual int errorCode() const;
349 };
350
351
352 /*! \brief
353  * Macro for throwing an exception.
354  *
355  * \param[in] e    Exception object to throw.
356  *
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.
361  *
362  * Basic usage:
363  * \code
364    if (value < 0)
365    {
366        GMX_THROW(InconsistentUserInput("Negative values not allowed for value"));
367    }
368    \endcode
369  */
370 #define GMX_THROW(e) \
371     BOOST_THROW_EXCEPTION((e))
372
373 /*! \brief
374  * Macro for throwing an exception based on errno.
375  *
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.
379  *
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.
387  *
388  * Typical usage (note that gmx::File wraps this particular case):
389  * \code
390    FILE *fp = fopen("filename.txt", "r");
391    if (fp == NULL)
392    {
393        GMX_THROW(FileIOError("Could not open file"), "fopen", errno);
394    }
395    \endcode
396  */
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
404
405 /*! \brief
406  * Formats a standard fatal error message for reporting an exception.
407  *
408  * \param[in] fp  %File to format the message to.
409  * \param[in] ex  Exception to format.
410  *
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.
413  *
414  * Normal usage in Gromacs command-line programs is like this:
415  * \code
416    int main(int argc, char *argv[])
417    {
418        gmx::init(&argc, &argv);
419        try
420        {
421            // The actual code for the program
422            return 0;
423        }
424        catch (const std::exception &ex)
425        {
426            gmx::printFatalErrorMessage(stderr, ex);
427            return gmx::processExceptionAtExit(ex);
428        }
429    }
430    \endcode
431  */
432 void printFatalErrorMessage(FILE *fp, const std::exception &ex);
433 /*! \brief
434  * Formats an error message for reporting an exception.
435  *
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.
439  */
440 std::string formatExceptionMessageToString(const std::exception &ex);
441 /*! \brief
442  * Formats an error message for reporting an exception.
443  *
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.
447  */
448 void formatExceptionMessageToFile(FILE *fp, const std::exception &ex);
449 /*! \brief
450  * Formats an error message for reporting an exception.
451  *
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.
455  */
456 void formatExceptionMessageToWriter(TextWriter           *writer,
457                                     const std::exception &ex);
458 /*! \brief
459  * Handles an exception that is causing the program to terminate.
460  *
461  * \param[in] ex  Exception that is the cause for terminating the program.
462  * \returns   Return code to return from main().
463  *
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()).
468  *
469  * See printFatalErrorMessage() for example usage.
470  *
471  * Does not throw.
472  */
473 int processExceptionAtExit(const std::exception &ex);
474
475 /*! \brief
476  * Converts an exception into a return code.
477  */
478 int translateException(const std::exception &ex);
479
480 /*! \brief
481  * Macro for catching exceptions at C++ -> C boundary.
482  *
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.
488  *
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.
492  *
493  * Usage:
494    \code
495    try
496    {
497        // C++ code
498    }
499    GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
500    \endcode
501  */
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)); \
506     }
507
508 //! \}
509
510 } // namespace gmx
511
512 #endif