1 /**
2  *  \file RMF/exceptions.h
3  *  \brief Declarations of the various exception types.
4  *
5  *  Copyright 2007-2021 IMP Inventors. All rights reserved.
6  *
7  */
8 
9 #ifndef RMF_EXCEPTIONS_H
10 #define RMF_EXCEPTIONS_H
11 
12 #include <boost/exception/exception.hpp>  // IWYU pragma: export
13 #include <exception>
14 #include <string>
15 
16 #include "RMF/config.h"
17 #include "compiler_macros.h"
18 
19 RMF_ENABLE_WARNINGS
20 namespace RMF {
21 /** The base class for RMF exceptions. Use the what() method
22     to get back a string describing the exception.
23 
24     Use get_message() to get a nice message describing the
25     exception.
26  */
27 class RMFEXPORT Exception : public virtual std::exception,
28                             public virtual boost::exception {
29   mutable std::string message_;
30 
31  public:
32   RMF_CXX11_DEFAULT_COPY_CONSTRUCTOR(Exception);
33   Exception();
34   const char* what() const RMF_NOEXCEPT RMF_OVERRIDE;
35   virtual ~Exception() RMF_NOEXCEPT;
36 };
37 
38 /** Use this instead of the more standard what() to get the
39     message as what() presents issues for memory management
40     with dynamically generated messages like. */
41 RMFEXPORT std::string get_message(const Exception& e);
42 
43 /** Usage exceptions are thrown when the library is misused in some way,
44     e.g., an out of bounds element is requested from a collection. In general
45     when these are throw, the failed operation should have been cleanly
46     aborted without changing the file.
47  */
48 class RMFEXPORT UsageException : public Exception {
49  public:
50   RMF_CXX11_DEFAULT_COPY_CONSTRUCTOR(UsageException);
51   UsageException();
52   ~UsageException() RMF_NOEXCEPT;
53 };
54 
55 /** IOExceptions are thrown when some operation on a disk file fails.
56  */
57 class RMFEXPORT IOException : public Exception {
58  public:
59   RMF_CXX11_DEFAULT_COPY_CONSTRUCTOR(IOException);
60   IOException();
61   ~IOException() RMF_NOEXCEPT;
62 };
63 
64 /** Internal exceptions are thrown when the library discovers that some
65     internal invariant no longer holds. Since they represent bugs in the
66     library, one can not necessarily recover when they occur..
67  */
68 class RMFEXPORT InternalException : public Exception {
69  public:
70   RMF_CXX11_DEFAULT_COPY_CONSTRUCTOR(InternalException);
71   InternalException();
72   ~InternalException() RMF_NOEXCEPT;
73 };
74 
75 /** IndexExceptions are thrown when you walk off the end of something.
76  */
77 class RMFEXPORT IndexException : public Exception {
78  public:
79   RMF_CXX11_DEFAULT_COPY_CONSTRUCTOR(IndexException);
80   IndexException();
81   ~IndexException() RMF_NOEXCEPT;
82 };
83 }
84 
85 #define RMF_THROW(m, e)                          \
86   {                                              \
87     using namespace ::RMF::internal::ErrorInfo;  \
88     using ::RMF::internal::ErrorInfo::Type;      \
89     using ::RMF::internal::ErrorInfo::Category;  \
90     using ::RMF::internal::ErrorInfo::Key;       \
91     using ::RMF::internal::ErrorInfo::Decorator; \
92     using boost::operator<<;                     \
93     throw e() << m;                              \
94   }
95 
96 #define RMF_RETHROW(m, e)                        \
97   {                                              \
98     using namespace ::RMF::internal::ErrorInfo;  \
99     using ::RMF::internal::ErrorInfo::Type;      \
100     using ::RMF::internal::ErrorInfo::Category;  \
101     using ::RMF::internal::ErrorInfo::Key;       \
102     using ::RMF::internal::ErrorInfo::Decorator; \
103     using boost::operator<<;                     \
104     e << m;                                      \
105     throw;                                       \
106   }
107 
108 #define RMF_USAGE_CHECK(check, message)                                    \
109   do {                                                                     \
110     if (!(check)) {                                                        \
111       RMF_THROW(Message(message) << Type("Usage"), ::RMF::UsageException); \
112     }                                                                      \
113   } while (false)
114 
115 #define RMF_INDEX_CHECK(value, end)                                      \
116   RMF_USAGE_CHECK(                                                       \
117       static_cast<unsigned int>(value) < static_cast<unsigned int>(end), \
118       "Out of range index");
119 
120 #define RMF_PATH_CHECK(path)                                                 \
121   if (!boost::filesystem::exists(path)) {                                    \
122     RMF_THROW(Message("File does not exist") << File(path) << Type("Usage"), \
123               IOException);                                                  \
124   }
125 
126 #ifndef RMF_NDEBUG
127 #define RMF_INTERNAL_CHECK(check, message)                                   \
128   do {                                                                       \
129     if (!(check)) {                                                          \
130       RMF_THROW(Message(message) << Type("Internal") << SourceFile(__FILE__) \
131                                  << SourceLine(__LINE__)                     \
132                                  << Function(BOOST_CURRENT_FUNCTION),        \
133                 ::RMF::InternalException);                                   \
134     }                                                                        \
135   } while (false)
136 
137 #define RMF_IF_CHECK if (true)
138 
139 #else  // NDEBUG
140 #define RMF_INTERNAL_CHECK(check, message)
141 #define RMF_IF_CHECK
142 
143 #endif
144 
145 #define RMF_NOT_IMPLEMENTED                                                \
146   RMF_THROW(Message("Not implemented") << Function(BOOST_CURRENT_FUNCTION) \
147                                        << SourceFile(__FILE__)             \
148                                        << SourceLine(__LINE__)             \
149                                        << Type("NotImplemented"),          \
150             ::RMF::InternalException)
151 
152 RMF_DISABLE_WARNINGS
153 
154 #include "RMF/internal/errors.h"  // IWYU pragma: export
155 
156 #endif /* RMF_EXCEPTIONS_H */
157