1 |
/*******************************************************************\ |
2 |
|
3 |
Copyright (C) 2003 Joseph Coffland |
4 |
|
5 |
This program is free software; you can redistribute it and/or |
6 |
modify it under the terms of the GNU General Public License |
7 |
as published by the Free Software Foundation; either version 2 |
8 |
of the License, or (at your option) any later version. |
9 |
|
10 |
This program is distributed in the hope that it will be useful, |
11 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 |
GNU General Public License for more details. |
14 |
|
15 |
You should have received a copy of the GNU General Public License |
16 |
along with this program; if not, write to the Free Software |
17 |
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA |
18 |
02111-1307, USA. |
19 |
|
20 |
For information regarding this software email |
21 |
jcofflan@users.sourceforge.net |
22 |
|
23 |
\*******************************************************************/ |
24 |
|
25 |
|
26 |
#ifndef UTILS_EXCEPTION_H |
27 |
#define UTILS_EXCEPTION_H |
28 |
|
29 |
#include "config.h" |
30 |
#include "utils/FileLocation.hpp" |
31 |
#include "utils/SmartPointer.hpp" |
32 |
#include "utils/Zap.hpp" |
33 |
|
34 |
#ifdef HAVE_DEBUGGER |
35 |
#include "debug/Debugger.hpp" |
36 |
#endif |
37 |
#ifdef HAVE_BACKTRACE |
38 |
#include "debug/Backtrace.hpp" |
39 |
#endif |
40 |
|
41 |
#include <vector> |
42 |
#include <string> |
43 |
#include <iostream> |
44 |
|
45 |
#ifdef HAVE_NO_SSTREAM |
46 |
#include "utils/sstream_local.hpp" |
47 |
#else |
48 |
#include <sstream> |
49 |
#endif |
50 |
|
51 |
#if defined(HAVE_DEBUGGER) || defined(HAVE_BACKTRACE) |
52 |
#define HAVE_STACK_TRACE |
53 |
#endif |
54 |
|
55 |
|
56 |
namespace OpenMD { |
57 |
// Forward Declarations |
58 |
template <class T, class DEALLOC_T> |
59 |
class SmartPointer; |
60 |
|
61 |
/** |
62 |
* Exception is a general purpose exception class. It is similar to |
63 |
* the java Exception class. A Exception can carry a message, |
64 |
* a FileLocation and/or a pointer to an exception which was the |
65 |
* original cause. |
66 |
* |
67 |
* There are preprocessor macros that can be used to as a convient way |
68 |
* to add the current file, line and column where the exception occured. |
69 |
* These are: |
70 |
* |
71 |
* THROW(const string message) |
72 |
* |
73 |
* and |
74 |
* |
75 |
* ASSERT_OR_THROW(const string message, const bool condition) |
76 |
* |
77 |
* The latter can be used to in place of assert(const bool condition). |
78 |
* Throwing an exception instead of aborting overcomes some of the |
79 |
* limitations of the standard assert. |
80 |
*/ |
81 |
class Exception { |
82 |
#ifdef HAVE_STACK_TRACE |
83 |
public: |
84 |
typedef std::vector<std::string> trace_t; |
85 |
#endif |
86 |
|
87 |
private: |
88 |
std::string message; |
89 |
FileLocation location; |
90 |
SmartPointer<Exception> cause; |
91 |
#ifdef HAVE_STACK_TRACE |
92 |
SmartPointer<trace_t> trace; |
93 |
#endif |
94 |
|
95 |
public: |
96 |
static unsigned int causePrintLevel; |
97 |
#ifdef HAVE_STACK_TRACE |
98 |
static bool enableStackTraces; |
99 |
#endif |
100 |
|
101 |
Exception() {init();} |
102 |
|
103 |
Exception(const std::string message) : message(message) { |
104 |
init(); |
105 |
} |
106 |
|
107 |
Exception(const std::string message, const FileLocation &location) |
108 |
: message(message), location(location) { |
109 |
init(); |
110 |
} |
111 |
|
112 |
Exception(const std::string message, Exception &cause) : |
113 |
message(message) { |
114 |
this->cause = new Exception(cause); |
115 |
init(); |
116 |
} |
117 |
|
118 |
Exception(const std::string message, const FileLocation &location, |
119 |
const Exception &cause) : |
120 |
message(message), location(location) { |
121 |
this->cause = new Exception(cause); |
122 |
init(); |
123 |
} |
124 |
|
125 |
#ifdef HAVE_STACK_TRACE |
126 |
Exception(const Exception &e, const Exception &cause) : |
127 |
message(e.message), location(e.location), cause(new Exception(cause)), |
128 |
trace(e.trace) {} |
129 |
|
130 |
/// Copy constructor |
131 |
Exception(const Exception &e) : |
132 |
message(e.message), location(e.location), cause(e.cause), |
133 |
trace(e.trace) {} |
134 |
#else |
135 |
Exception(const Exception &e, const Exception &cause) : |
136 |
message(e.message), location(e.location), cause(new Exception(cause)) {} |
137 |
|
138 |
/// Copy constructor |
139 |
Exception(const Exception &e) : |
140 |
message(e.message), location(e.location), cause(e.cause) {} |
141 |
#endif |
142 |
|
143 |
virtual ~Exception() {} |
144 |
|
145 |
const std::string &getMessage() const {return message;} |
146 |
const FileLocation &getLocation() const {return location;} |
147 |
|
148 |
/** |
149 |
* @return A SmartPointer to the Exception that caused this |
150 |
* exception or NULL. |
151 |
*/ |
152 |
SmartPointer<Exception> getCause() const {return cause;} |
153 |
|
154 |
#ifdef HAVE_STACK_TRACE |
155 |
SmartPointer<trace_t> getTrace() const {return trace;} |
156 |
#endif |
157 |
|
158 |
/** |
159 |
* Prints the complete exception recuring down to the cause exception if |
160 |
* not null. WARNING: If there are many layers of causes this function |
161 |
* could print a very large amount of data. This can be limited by |
162 |
* setting the causePrintLevel variable. |
163 |
* |
164 |
* @param stream The output stream. |
165 |
* @param printLocations Print file locations. |
166 |
* @param printLevel The current cause print level. |
167 |
* |
168 |
* @return A reference to the passed stream. |
169 |
*/ |
170 |
std::ostream &print(std::ostream &stream, |
171 |
bool printLocations = true, |
172 |
unsigned int printLevel = 0) const { |
173 |
|
174 |
stream << message << std::endl; |
175 |
|
176 |
if (printLocations && !location.isEmpty()) |
177 |
stream << "@ " << location << std::endl; |
178 |
|
179 |
#ifdef HAVE_STACK_TRACE |
180 |
if (enableStackTraces && !trace.isNull()) { |
181 |
trace_t::iterator it; |
182 |
for (it = trace->begin(); it != trace->end(); it++) |
183 |
stream << std::endl << " " << *it; |
184 |
} |
185 |
#endif |
186 |
|
187 |
if (!cause.isNull()) { |
188 |
stream << std::endl << " "; |
189 |
|
190 |
if (printLevel > causePrintLevel) { |
191 |
stream << "Aborting exception dump due to causePrintLevel limit! " |
192 |
<< "Increase Exception::causePrintLevel to see more."; |
193 |
|
194 |
} else { |
195 |
stream << "caused by: "; |
196 |
cause->print(stream, printLocations, printLevel); |
197 |
} |
198 |
} |
199 |
|
200 |
return stream; |
201 |
} |
202 |
|
203 |
protected: |
204 |
void init() { |
205 |
#ifdef HAVE_STACK_TRACE |
206 |
if (enableStackTraces) { |
207 |
trace = new trace_t(); |
208 |
|
209 |
// When Optimization is turned on functions such as this |
210 |
// one are often inlined and not visable to the debugger. |
211 |
// This means stack traces for optimized code will often |
212 |
// be incomplete. |
213 |
#ifdef __OPTIMIZE__ |
214 |
trace->push_back("Warning: Optimization can cause incomplete traces."); |
215 |
#endif |
216 |
|
217 |
#if defined(HAVE_DEBUGGER) && defined(HAVE_BACKTRACE) |
218 |
if (!Debugger::getStackTrace(*trace)) { |
219 |
trace->clear(); |
220 |
Backtrace::getStackTrace(*trace); |
221 |
} |
222 |
|
223 |
#else |
224 |
#if defined(HAVE_DEBUGGER) |
225 |
Debugger::getStackTrace(*trace); |
226 |
#else |
227 |
Backtrace::getStackTrace(*trace); |
228 |
#endif |
229 |
#endif |
230 |
} |
231 |
#endif // HAVE_STACK_TRACE |
232 |
} |
233 |
|
234 |
friend std::ostream &operator<<(std::ostream &, const Exception &); |
235 |
}; |
236 |
|
237 |
/** |
238 |
* An stream output operator for Exception. This allows you to print the |
239 |
* text of an exception to a stream like so: |
240 |
* |
241 |
* . . . |
242 |
* } catch (Exception &e) { |
243 |
* cout << e << endl; |
244 |
* return 0; |
245 |
* } |
246 |
*/ |
247 |
inline std::ostream &operator<<(std::ostream &stream, const Exception &e) { |
248 |
e.print(stream); |
249 |
return stream; |
250 |
} |
251 |
} |
252 |
|
253 |
#ifndef THROW |
254 |
#define THROW(msg) throw OpenMD::Exception((msg), FILE_LOCATION) |
255 |
#define THROWC(msg, cause) \ |
256 |
throw OpenMD::Exception((msg), FILE_LOCATION, (cause)) |
257 |
#define ASSERT_OR_THROW(msg, condition) {if (!(condition)) THROW(msg);} |
258 |
|
259 |
#define THROWS(msgs) { \ |
260 |
std::ostringstream errMsg; \ |
261 |
errMsg << msgs; \ |
262 |
THROW(errMsg.str()); \ |
263 |
} |
264 |
|
265 |
#define THROWSC(msgs, cause) { \ |
266 |
std::ostringstream errMsg; \ |
267 |
errMsg << msgs; \ |
268 |
THROWC(errMsg.str(), cause); \ |
269 |
} |
270 |
#endif // THROW |
271 |
|
272 |
#endif |