1 /*
2  * Copyright (c) 2014-2017, Siemens AG. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright notice,
8  * this list of conditions and the following disclaimer.
9  *
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
18  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24  * POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #ifndef EMBB_BASE_EXCEPTIONS_H_
28 #define EMBB_BASE_EXCEPTIONS_H_
29 
30 #ifdef EMBB_PLATFORM_COMPILER_MSVC
31 #pragma warning(push)
32 // Disable warning that exceptions are disabled but try/catch is used.
33 #pragma warning(disable : 4530)
34 #endif // EMBB_PLATFORM_COMPILER_MSVC
35 
36 #include <string>
37 #include <exception>
38 
39 #ifdef EMBB_PLATFORM_COMPILER_MSVC
40 #pragma warning(pop)
41 #endif
42 
43 #include <embb/base/internal/cmake_config.h>
44 #include <embb/base/c/errors.h>
45 
46 /**
47  * \defgroup CPP_BASE_EXCEPTIONS Exception
48  *
49  * Exception types.
50  *
51  * If exceptions are disabled, i.e., if the library was built without support
52  * for exceptions, no exceptions will be thrown. Instead, an error message is
53  * printed to \c stderr and the program exits with the code representing the
54  * exception.
55  *
56  * \ingroup CPP_BASE
57  */
58 
59 /**
60  * Macros to be used within EMBB when throwing and catching exceptions.
61  *
62  * Example:
63  * - Throwing an exception:
64  *   EMBB_THROW(NoMemoryException, "Could not create thread.");
65  *   --> If exceptions are disabled, this will write an error to stderr,
66  *       containing the exception's message, and exit the program with the code
67  *       of the exception.
68  * - Try/catch block:
69  *   EMBB_TRY{ ... things to try ... }
70  *   EMBB_CATCH(ExceptionXYZ& e){ ... things to catch ... }
71  *   --> If exceptions are disabled, this will execute the try block without and
72  *       replace the catch() statement by "if (false)", such that
73  *       the catch block will be compiled but never executed.
74  */
75 #ifdef EMBB_USE_EXCEPTIONS
76 #define EMBB_TRY try
77 #define EMBB_THROW(Type, Message) throw Type(Message);
78 #define EMBB_CATCH(Statement) catch(Statement)
79 #else /* EMBB_USE_EXCEPTIONS */
80 #include <stdio.h>
81 #include <stdlib.h>
82 #include <embb/base/c/internal/unused.h>
83 #define EMBB_TRY
84 /**
85  * Concatenates the inputs.
86  */
87 #define EMBB_CATCH_VAR_CAT2(X, Y) X##Y
88 /**
89  * Is a necessary intermediate macro to create EMBB_CATCH_VAR.
90  */
91 #define EMBB_CATCH_VAR_CAT1(X, Y) EMBB_CATCH_VAR_CAT2(X, Y)
92 /**
93  * Defines a unique variable name for each line of code.
94  *
95  * The line number is concatenated to a base name.
96  */
97 #define EMBB_CATCH_VAR EMBB_CATCH_VAR_CAT1(embb_catch_var_, __LINE__)
98 /**
99  * Replaces catch(xyz) by an if-statement that is always false.
100  *
101  * To avoid a compiler warning that the condition is constant, a variable is
102  * used instead of "false". A unique name for every catch-statement is
103  * necessary, which is achieved by macro EMBB_CATCH_VAR and helper macros. To
104  * avoid the unused variable warning, in addition the EMBB_UNUSED macro is
105  * used.
106  */
107 #define EMBB_CATCH(Statement) \
108         int EMBB_CATCH_VAR = false; \
109         EMBB_UNUSED(EMBB_CATCH_VAR); \
110         if (EMBB_CATCH_VAR)
111 
112 /**
113  * Replaces a throw by an error message and program exit.
114  */
115 #define EMBB_THROW(Type, Message) \
116   { \
117     Type e(Message); \
118     fprintf(stderr, \
119       "Exit program due to (not thrown) " #Type ": %s\n", e.what()); \
120     exit(e.Code()); \
121   }
122 #endif /* else EMBB_USE_EXCEPTIONS */
123 
124 namespace embb {
125 namespace base {
126 
127 /**
128  * Abstract base class for exceptions.
129  *
130  * \ingroup CPP_BASE_EXCEPTIONS
131  */
132 class Exception : public std::exception {
133  public:
134   /**
135    * Constructs an exception with a custom message.
136    */
Exception(const char * message)137   explicit Exception(
138     const char* message
139     /**< [IN] Error message */
140     ) : message_(message) {}
141 
142   /**
143    * Destructs the exception.
144    */
~Exception()145   virtual ~Exception() throw() {}
146 
147   /**
148    * Constructs an exception by copying from an existing one.
149    */
Exception(const Exception & e)150   Exception(
151     const Exception& e
152     /**< [IN] %Exception to be copied */
153     ) : message_(e.message_) {}
154 
155   /**
156    * Assigns an existing exception.
157    *
158    * \return Reference to \c *this
159    */
160   Exception& operator=(
161     const Exception& e
162     /**< [IN] %Exception to assign */
163     ) {
164     message_ = e.message_;
165     return *this;
166   }
167 
168   /**
169    * Returns the error message.
170    *
171    * \return Pointer to error message
172    */
What()173   virtual const char* What() const throw() {
174     return message_;
175   }
176 
177   /**
178    * Returns an integer code representing the exception.
179    *
180    * \return %Exception code
181    */
182   virtual int Code() const = 0;
183 
184  private:
185   /**
186    * Holds error message
187    */
188   const char* message_;
189 };
190 
191 /**
192  * Indicates lack of memory necessary to allocate a resource.
193  *
194  * \ingroup CPP_BASE_EXCEPTIONS
195  */
196 class NoMemoryException : public Exception {
197  public:
198    /**
199     * Constructs an exception with the specified message
200     */
NoMemoryException(const char * message)201   explicit NoMemoryException(
202     const char* message
203     /**< [IN] Error message */
204     ) : Exception(message) {}
Code()205   virtual int Code() const { return EMBB_NOMEM; }
206 };
207 
208 /**
209  * Indicates business (unavailability) of a required resource.
210  *
211  * \ingroup CPP_BASE_EXCEPTIONS
212  */
213 class ResourceBusyException : public Exception {
214  public:
215   /**
216    * Constructs an exception with the specified message
217    */
ResourceBusyException(const char * message)218   explicit ResourceBusyException(
219     const char* message
220     /**< [IN] Error message */
221     ) : Exception(message) {}
Code()222   virtual int Code() const { return EMBB_BUSY; }
223 };
224 
225 /**
226  * Indicates a numeric underflow.
227  *
228  * \ingroup CPP_BASE_EXCEPTIONS
229  */
230 class UnderflowException : public Exception {
231  public:
232   /**
233    * Constructs an exception with the specified message
234    */
UnderflowException(const char * message)235   explicit UnderflowException(
236     const char* message
237     /**< [IN] Error message */
238     ) : Exception(message) {}
Code()239   virtual int Code() const { return EMBB_UNDERFLOW; }
240 };
241 
242 /**
243  * Indicates a numeric overflow.
244  *
245  * \ingroup CPP_BASE_EXCEPTIONS
246  */
247 class OverflowException : public Exception {
248  public:
249   /**
250    * Constructs an exception with the specified message
251    */
OverflowException(const char * message)252   explicit OverflowException(
253     const char* message
254     /**< [IN] Error message */
255     ) : Exception(message) {}
Code()256   virtual int Code() const { return EMBB_OVERFLOW; }
257 };
258 
259 /**
260  * Indicates a general error.
261  *
262  * \ingroup CPP_BASE_EXCEPTIONS
263  */
264 class ErrorException : public Exception {
265  public:
266   /**
267    * Constructs an exception with the specified message
268    */
ErrorException(const char * message)269   explicit ErrorException(
270     const char* message
271     /**< [IN] Error message */
272     ) : Exception(message) {}
Code()273   virtual int Code() const { return EMBB_ERROR; }
274 };
275 
276 } // namespace base
277 } // namespace embb
278 
279 #endif  // EMBB_BASE_EXCEPTIONS_H_
280