23 |
23 |
24 #include <exception> |
24 #include <exception> |
25 #include <string> |
25 #include <string> |
26 #include <sstream> |
26 #include <sstream> |
27 |
27 |
|
28 #include <boost/shared_ptr.hpp> |
28 |
29 |
29 namespace lemon { |
30 namespace lemon { |
|
31 |
|
32 /// Exception-safe convenient "error message" class. |
|
33 class ErrorMessage { |
|
34 protected: |
|
35 boost::shared_ptr<std::ostringstream> buf; |
|
36 |
|
37 bool init() throw() { |
|
38 try { |
|
39 buf.reset(new std::ostringstream); |
|
40 } |
|
41 catch(...) { |
|
42 buf.reset(); |
|
43 } |
|
44 return buf; |
|
45 } |
|
46 |
|
47 public: |
|
48 |
|
49 ErrorMessage() throw() { init(); } |
|
50 |
|
51 ErrorMessage(const char *message) throw() { |
|
52 init(); |
|
53 *this << message; |
|
54 } |
|
55 |
|
56 ErrorMessage(const std::string &message) throw() { |
|
57 init(); |
|
58 *this << message; |
|
59 } |
|
60 |
|
61 template <typename T> |
|
62 ErrorMessage& operator<<(const T &t) throw() { |
|
63 if( !buf ) return *this; |
|
64 |
|
65 try { |
|
66 *buf << t; |
|
67 } |
|
68 catch(...) { |
|
69 buf.reset(); |
|
70 } |
|
71 } |
|
72 |
|
73 const char* message() throw() { |
|
74 if( !buf ) return 0; |
|
75 |
|
76 const char* mes = 0; |
|
77 try { |
|
78 mes = buf->str().c_str(); |
|
79 } |
|
80 catch(...) {} |
|
81 return mes; |
|
82 } |
|
83 |
|
84 }; |
30 |
85 |
31 /** |
86 /** |
32 * \brief Generic exception class. |
87 * \brief Generic exception class. |
33 * |
88 * |
34 * \todo Do we need this? |
89 * Base class for exceptions used in LEMON. |
35 * |
|
36 * \todo Don't we need different kind of exceptions for different kind |
|
37 * of errors? |
|
38 * Shouldn't we use \<stdexcept\> instead? |
|
39 */ |
90 */ |
40 class Exception : public std::exception { |
91 class Exception : public std::exception, public ErrorMessage { |
41 protected: |
|
42 std::ostringstream buf; |
|
43 public: |
92 public: |
44 Exception() {} |
93 Exception() throw() {} |
45 explicit Exception(const std::string &s) { buf << s; } |
94 explicit Exception(const std::string &s) throw() |
46 Exception(const Exception &e) : std::exception() { |
95 : ErrorMessage(s) {} |
47 buf << e.buf.str(); |
|
48 } |
|
49 virtual ~Exception() throw() {} |
96 virtual ~Exception() throw() {} |
50 |
97 |
51 virtual const char* what() const throw() { |
98 virtual const char* what() const throw() { |
52 return buf.str().c_str(); |
99 const char *mes = message(); |
|
100 if( mes ) return mes; |
|
101 return "lemon::Exception"; |
|
102 } |
|
103 }; |
|
104 |
|
105 |
|
106 class LogicError : public Exception { |
|
107 explicit LogicError(const std::string &s) |
|
108 : Exception(s) {} |
|
109 }; |
|
110 |
|
111 class RuntimeError : public Exception { |
|
112 explicit RuntimeError(const std::string &s) |
|
113 : Exception(s) {} |
|
114 }; |
|
115 |
|
116 class RangeError : public RuntimeError { |
|
117 explicit RangeError(const std::string &s) |
|
118 : RuntimeError(s) {} |
|
119 }; |
|
120 |
|
121 class IOError : public RuntimeError { |
|
122 explicit IOError(const std::string &s) |
|
123 : RuntimeError(s) {} |
|
124 }; |
|
125 |
|
126 class DataFormatError : public IOError { |
|
127 explicit DataFormatError(const std::string &message) |
|
128 : IOError(message) : line(0) {} |
|
129 DataFormatError(const std::string &file_name, int line_num, |
|
130 sconst std::string &message) |
|
131 : IOError(message), line(line_num) { set_file(file_name); } |
|
132 |
|
133 void set_line(int line_num) { line=line_num; } |
|
134 void set_file(const std::string &file_name) { |
|
135 try { |
|
136 file.reset(new std::string); |
|
137 *file = file_name; |
|
138 } |
|
139 catch(...) { |
|
140 file.reset(); |
|
141 } |
53 } |
142 } |
54 |
143 |
55 template <typename T> |
144 virtual const char* what() const { |
56 Exception& operator<<(T const& t) { buf << t; return *this; } |
145 const char *mes = 0; |
|
146 try { |
|
147 std::ostringstream ostr; |
|
148 ostr << IOError::what(); |
|
149 if( file || line ) { |
|
150 ostr << " ("; |
|
151 if( file ) ostr << "in file" << *file; |
|
152 if( line ) ostr << " at line" << line; |
|
153 } |
|
154 mes = ostr.str().c_str(); |
|
155 } |
|
156 catch(...) {} |
|
157 if( mes ) return mes; |
|
158 return "lemon::DataFormatError"; |
|
159 } |
57 }; |
160 }; |
58 |
161 |
|
162 |
|
163 |
|
164 /**************** Macros ****************/ |
|
165 |
|
166 |
59 /** |
167 /** |
60 * \brief Generic error signaling function. |
168 * \brief Macro for assertions with customizable message |
61 * |
|
62 * \todo Do we really need this? Is it helpful? |
|
63 */ |
169 */ |
64 inline void fault(const std::string &msg) { |
170 |
65 throw Exception(msg); |
171 # define lemon_assert(exp, msg) \ |
66 } |
172 if(!(exp)) { \ |
|
173 std::cerr << __FILE__ ":" << __LINE__ << ": " << (msg) << std::endl; \ |
|
174 abort; \ |
|
175 } |
|
176 |
67 |
177 |
68 /** |
178 /** |
69 * \brief Macro for mark not yet implemented features. |
179 * \brief Macro for mark not yet implemented features. |
70 * |
180 * |
71 * \todo Is this the right place for this? It should be used only in |
181 * \todo Is this the right place for this? It should be used only in |
72 * modules under development. |
182 * modules under development. |
73 */ |
183 */ |
74 |
184 |
75 # define FIXME(msg) \ |
185 # define FIXME(msg) lemon_assert(0, "FIXME: " msg) |
76 do { throw ::lemon::Exception() << "FIXME: " msg " (in: " \ |
|
77 __FILE__ ", " << __LINE__ << ")"; \ |
|
78 } while(false) |
|
79 |
186 |
80 } |
187 } |
81 #endif // LEMON_ERROR_H |
188 #endif // LEMON_ERROR_H |