ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/branches/development/src/utils/Exception.hpp
Revision: 1492
Committed: Mon Aug 16 18:07:50 2010 UTC (14 years, 8 months ago) by chuckv
File size: 7822 byte(s)
Log Message:
Adding exception and reporting mechanism from ProtoMol to OpenMD.

File Contents

# Content
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