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

# User Rev Content
1 chuckv 1492 /*******************************************************************\
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